add-ipnumber-validatation #77

Merged
hsh-michaelhoennig merged 4 commits from add-ipnumber-validatation into master 2024-07-16 10:32:41 +02:00
14 changed files with 356 additions and 133 deletions
Showing only changes of commit e5db6ebe56 - Show all commits

View File

@ -1,6 +1,49 @@
## HostingAsset Type Structure ## HostingAsset Type Structure
### Webspace+Server
```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
}
package Hosting #feb28c{
package Server #99bcdb {
entity HA_CLOUD_SERVER
entity HA_MANAGED_SERVER
entity HA_IPV4_NUMBER
entity HA_IPV6_NUMBER
}
}
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_IPV4_NUMBER o..> HA_CLOUD_SERVER
HA_IPV4_NUMBER o..> HA_MANAGED_SERVER
HA_IPV6_NUMBER o..> HA_CLOUD_SERVER
HA_IPV6_NUMBER o..> HA_MANAGED_SERVER
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
```
### Domain ### Domain
```plantuml ```plantuml
@ -24,12 +67,6 @@ package Hosting #feb28c{
entity HA_EMAIL_ADDRESS entity HA_EMAIL_ADDRESS
} }
package Server #99bcdb {
entity HA_CLOUD_SERVER
entity HA_MANAGED_SERVER
entity HA_IP_NUMBER
}
package Webspace #99bcdb { package Webspace #99bcdb {
entity HA_MANAGED_WEBSPACE entity HA_MANAGED_WEBSPACE
entity HA_UNIX_USER entity HA_UNIX_USER
@ -42,25 +79,19 @@ BI_CLOUD_SERVER *--> BI_PRIVATE_CLOUD
BI_MANAGED_SERVER *--> BI_PRIVATE_CLOUD BI_MANAGED_SERVER *--> BI_PRIVATE_CLOUD
BI_MANAGED_WEBSPACE *--> BI_MANAGED_SERVER 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 *==> BI_MANAGED_WEBSPACE
HA_MANAGED_WEBSPACE o..> HA_MANAGED_SERVER
HA_UNIX_USER *==> HA_MANAGED_WEBSPACE HA_UNIX_USER *==> HA_MANAGED_WEBSPACE
HA_EMAIL_ALIAS *==> HA_MANAGED_WEBSPACE HA_EMAIL_ALIAS *==> HA_MANAGED_WEBSPACE
HA_DOMAIN_SETUP o..> HA_DOMAIN_SETUP HA_DOMAIN_SETUP o..> HA_DOMAIN_SETUP
HA_DOMAIN_DNS_SETUP *==> HA_DOMAIN_SETUP HA_DOMAIN_DNS_SETUP *==> HA_DOMAIN_SETUP
HA_DOMAIN_DNS_SETUP o..> HA_MANAGED_WEBSPACE HA_DOMAIN_DNS_SETUP o--> HA_MANAGED_WEBSPACE
HA_DOMAIN_HTTP_SETUP *==> HA_DOMAIN_SETUP HA_DOMAIN_HTTP_SETUP *==> HA_DOMAIN_SETUP
HA_DOMAIN_HTTP_SETUP o..> HA_UNIX_USER HA_DOMAIN_HTTP_SETUP o--> HA_UNIX_USER
HA_DOMAIN_SMTP_SETUP *==> HA_DOMAIN_SETUP HA_DOMAIN_SMTP_SETUP *==> HA_DOMAIN_SETUP
HA_DOMAIN_SMTP_SETUP o..> HA_MANAGED_WEBSPACE HA_DOMAIN_SMTP_SETUP o--> HA_MANAGED_WEBSPACE
HA_DOMAIN_MBOX_SETUP *==> HA_DOMAIN_SETUP HA_DOMAIN_MBOX_SETUP *==> HA_DOMAIN_SETUP
HA_DOMAIN_MBOX_SETUP o..> HA_MANAGED_WEBSPACE HA_DOMAIN_MBOX_SETUP o--> HA_MANAGED_WEBSPACE
HA_EMAIL_ADDRESS *==> HA_DOMAIN_MBOX_SETUP HA_EMAIL_ADDRESS *==> HA_DOMAIN_MBOX_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 { package Legend #white {
SUB_ENTITY1 *--> REQUIRED_PARENT_ENTITY SUB_ENTITY1 *--> REQUIRED_PARENT_ENTITY
@ -91,12 +122,6 @@ package Hosting #feb28c{
entity HA_MARIADB_DATABASE entity HA_MARIADB_DATABASE
} }
package Server #99bcdb {
entity HA_CLOUD_SERVER
entity HA_MANAGED_SERVER
entity HA_IP_NUMBER
}
package Webspace #99bcdb { package Webspace #99bcdb {
entity HA_MANAGED_WEBSPACE entity HA_MANAGED_WEBSPACE
entity HA_UNIX_USER entity HA_UNIX_USER
@ -109,20 +134,12 @@ BI_CLOUD_SERVER *--> BI_PRIVATE_CLOUD
BI_MANAGED_SERVER *--> BI_PRIVATE_CLOUD BI_MANAGED_SERVER *--> BI_PRIVATE_CLOUD
BI_MANAGED_WEBSPACE *--> BI_MANAGED_SERVER 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 *==> BI_MANAGED_WEBSPACE
HA_MANAGED_WEBSPACE o..> HA_MANAGED_SERVER
HA_UNIX_USER *==> HA_MANAGED_WEBSPACE HA_UNIX_USER *==> HA_MANAGED_WEBSPACE
HA_EMAIL_ALIAS *==> HA_MANAGED_WEBSPACE HA_EMAIL_ALIAS *==> HA_MANAGED_WEBSPACE
HA_MARIADB_INSTANCE *==> HA_MANAGED_SERVER
HA_MARIADB_USER *==> HA_MANAGED_WEBSPACE HA_MARIADB_USER *==> HA_MANAGED_WEBSPACE
HA_MARIADB_USER o..> HA_MARIADB_INSTANCE HA_MARIADB_USER o--> HA_MARIADB_INSTANCE
HA_MARIADB_DATABASE *==> HA_MARIADB_USER HA_MARIADB_DATABASE *==> HA_MARIADB_USER
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 { package Legend #white {
SUB_ENTITY1 *--> REQUIRED_PARENT_ENTITY SUB_ENTITY1 *--> REQUIRED_PARENT_ENTITY
@ -153,12 +170,6 @@ package Hosting #feb28c{
entity HA_PGSQL_DATABASE entity HA_PGSQL_DATABASE
} }
package Server #99bcdb {
entity HA_CLOUD_SERVER
entity HA_MANAGED_SERVER
entity HA_IP_NUMBER
}
package Webspace #99bcdb { package Webspace #99bcdb {
entity HA_MANAGED_WEBSPACE entity HA_MANAGED_WEBSPACE
entity HA_UNIX_USER entity HA_UNIX_USER
@ -171,20 +182,12 @@ BI_CLOUD_SERVER *--> BI_PRIVATE_CLOUD
BI_MANAGED_SERVER *--> BI_PRIVATE_CLOUD BI_MANAGED_SERVER *--> BI_PRIVATE_CLOUD
BI_MANAGED_WEBSPACE *--> BI_MANAGED_SERVER 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 *==> BI_MANAGED_WEBSPACE
HA_MANAGED_WEBSPACE o..> HA_MANAGED_SERVER
HA_UNIX_USER *==> HA_MANAGED_WEBSPACE HA_UNIX_USER *==> HA_MANAGED_WEBSPACE
HA_EMAIL_ALIAS *==> HA_MANAGED_WEBSPACE HA_EMAIL_ALIAS *==> HA_MANAGED_WEBSPACE
HA_PGSQL_INSTANCE *==> HA_MANAGED_SERVER HA_PGSQL_USER *==> HA_MANAGED_WEBSPACE
HA_PGSQL_USER *==> HA_PGSQL_INSTANCE HA_PGSQL_USER o--> HA_PGSQL_INSTANCE
HA_PGSQL_USER o..> HA_MANAGED_WEBSPACE HA_PGSQL_DATABASE *==> HA_PGSQL_USER
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 { package Legend #white {
SUB_ENTITY1 *--> REQUIRED_PARENT_ENTITY SUB_ENTITY1 *--> REQUIRED_PARENT_ENTITY

View File

@ -1,6 +1,7 @@
package net.hostsharing.hsadminng.hs.booking.item; package net.hostsharing.hsadminng.hs.booking.item;
import java.util.List; import java.util.List;
import java.util.Set;
import static java.util.Optional.ofNullable; import static java.util.Optional.ofNullable;
@ -21,12 +22,17 @@ public enum HsBookingItemType implements Node {
} }
@Override @Override
public List<String> edges() { public List<String> edges(final Set<String> inGroups) {
return ofNullable(parentItemType) return ofNullable(parentItemType)
.map(p -> (nodeName() + " *--> " + p.nodeName())) .map(p -> (nodeName() + " *--> " + p.nodeName()))
.stream().toList(); .stream().toList();
} }
@Override
public boolean belongsToAny(final Set<String> groups) {
return true;
}
@Override @Override
public String nodeName() { public String nodeName() {
return "BI_" + name(); return "BI_" + name();

View File

@ -1,9 +1,11 @@
package net.hostsharing.hsadminng.hs.booking.item; package net.hostsharing.hsadminng.hs.booking.item;
import java.util.List; import java.util.List;
import java.util.Set;
public interface Node { public interface Node {
String nodeName(); String nodeName();
List<String> edges(); boolean belongsToAny(Set<String> groups);
List<String> edges(final Set<String> inGroup);
} }

View File

@ -5,7 +5,6 @@ import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemEntity;
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType; import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType;
import net.hostsharing.hsadminng.hs.booking.item.Node; import net.hostsharing.hsadminng.hs.booking.item.Node;
import jakarta.validation.constraints.NotNull;
import javax.naming.NamingException; import javax.naming.NamingException;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
@ -30,7 +29,6 @@ import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.Rela
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.RelationType.ASSIGNED_TO_ASSET; 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.BOOKING_ITEM;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.RelationType.PARENT_ASSET; import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.RelationType.PARENT_ASSET;
import static net.hostsharing.hsadminng.mapper.Array.emptyArray;
public enum HsHostingAssetType implements Node { public enum HsHostingAssetType implements Node {
SAME_TYPE, // pseudo-type for recursive references SAME_TYPE, // pseudo-type for recursive references
@ -116,22 +114,27 @@ public enum HsHostingAssetType implements Node {
IPV4_NUMBER( IPV4_NUMBER(
inGroup("Server"), inGroup("Server"),
optionallyAssignedTo(CLOUD_SERVER).or(MANAGED_SERVER).or(MANAGED_WEBSPACE) optionallyAssignedTo(CLOUD_SERVER).or(MANAGED_SERVER).or(MANAGED_WEBSPACE)
),
IPV6_NUMBER(
inGroup("Server"),
optionallyAssignedTo(CLOUD_SERVER).or(MANAGED_SERVER).or(MANAGED_WEBSPACE)
); );
private final String groupName; private final String groupName;
private final EntityTypeRelation<?, ?>[] relations; private final EntityTypeRelation<?, ?>[] relations;
HsHostingAssetType( HsHostingAssetType(
String groupName, final String groupName,
@NotNull final EntityTypeRelation<?, ?>... relations final EntityTypeRelation<?, ?>... relations
) { ) {
this.groupName = groupName; this.groupName = groupName;
this.relations = relations; this.relations = relations;
} }
HsHostingAssetType() { HsHostingAssetType() {
this.groupName = null; this.groupName = null;
this.relations = emptyArray(EntityTypeRelation.class); this.relations = null;
} }
/// just syntactic sugar /// just syntactic sugar
@ -200,14 +203,22 @@ public enum HsHostingAssetType implements Node {
} }
@Override @Override
public List<String> edges() { public List<String> edges(final Set<String> inGroups) {
return stream(relations) return stream(relations)
.map(r -> r.relatedTypes(this).stream().map(x -> nodeName() + r.edge + x.nodeName()).toList()) .map(r -> r.relatedTypes(this).stream()
.filter(x -> x.belongsToAny(inGroups))
.map(x -> nodeName() + r.edge + x.nodeName())
.toList())
.flatMap(List::stream) .flatMap(List::stream)
.sorted() .sorted()
.toList(); .toList();
} }
@Override
public boolean belongsToAny(final Set<String> groups) {
return groups.contains(this.groupName);
}
@Override @Override
public String nodeName() { public String nodeName() {
return "HA_" + name(); return "HA_" + name();
@ -233,12 +244,12 @@ public enum HsHostingAssetType implements Node {
.map(t -> "entity " + t.nodeName()) .map(t -> "entity " + t.nodeName())
.collect(joining("\n")); .collect(joining("\n"));
final String bookingItemEdges = stream(HsBookingItemType.values()) final String bookingItemEdges = stream(HsBookingItemType.values())
.map(HsBookingItemType::edges) .map(t -> t.edges(includedHostingGroups))
.flatMap(Collection::stream) .flatMap(Collection::stream)
.collect(joining("\n")); .collect(joining("\n"));
final String hostingAssetEdges = stream(HsHostingAssetType.values()) final String hostingAssetEdges = stream(HsHostingAssetType.values())
.filter(t -> t.isInGroups(includedHostingGroups)) .filter(t -> t.isInGroups(includedHostingGroups))
.map(HsHostingAssetType::edges) .map(t -> t.edges(includedHostingGroups))
.flatMap(Collection::stream) .flatMap(Collection::stream)
.collect(joining("\n")); .collect(joining("\n"));
return """ return """
@ -304,9 +315,11 @@ public enum HsHostingAssetType implements Node {
.map(t -> t.groupName) .map(t -> t.groupName)
.collect(toSet())); .collect(toSet()));
markdown.append(renderAsPlantUML("Domain", Set.of("Domain", "Webspace", "Server"))) markdown
.append(renderAsPlantUML("MariaDB", Set.of("MariaDB", "Webspace", "Server"))) .append(renderAsPlantUML("Webspace+Server", Set.of("Server")))
.append(renderAsPlantUML("PostgreSQL", Set.of("PostgreSQL", "Webspace", "Server"))); .append(renderAsPlantUML("Domain", Set.of("Domain", "Webspace")))
.append(renderAsPlantUML("MariaDB", Set.of("MariaDB", "Webspace")))
.append(renderAsPlantUML("PostgreSQL", Set.of("PostgreSQL", "Webspace")));
markdown.append(""" markdown.append("""

View File

@ -33,6 +33,7 @@ public class HostingAssetEntityValidatorRegistry {
register(PGSQL_USER, new HsPostgreSqlUserHostingAssetValidator()); register(PGSQL_USER, new HsPostgreSqlUserHostingAssetValidator());
register(PGSQL_DATABASE, new HsPostgreSqlDatabaseHostingAssetValidator()); register(PGSQL_DATABASE, new HsPostgreSqlDatabaseHostingAssetValidator());
register(IPV4_NUMBER, new HsIPv4NumberHostingAssetValidator()); register(IPV4_NUMBER, new HsIPv4NumberHostingAssetValidator());
register(IPV6_NUMBER, new HsIPv6NumberHostingAssetValidator());
} }
private static void register(final Enum<HsHostingAssetType> type, final HsEntityValidator<HsHostingAssetEntity> validator) { private static void register(final Enum<HsHostingAssetType> type, final HsEntityValidator<HsHostingAssetEntity> validator) {

View File

@ -8,7 +8,7 @@ import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.IPV4
class HsIPv4NumberHostingAssetValidator extends HostingAssetEntityValidator { class HsIPv4NumberHostingAssetValidator extends HostingAssetEntityValidator {
public static Pattern IPV4_REGEX = Pattern.compile("^((25[0-5]|(2[0-4]|1\\d|[1-9]|)\\d)\\.?\\b){4}$"); private static final Pattern IPV4_REGEX = Pattern.compile("^((25[0-5]|(2[0-4]|1\\d|[1-9]|)\\d)\\.?\\b){4}$");
HsIPv4NumberHostingAssetValidator() { HsIPv4NumberHostingAssetValidator() {
super( super(

View File

@ -0,0 +1,49 @@
package net.hostsharing.hsadminng.hs.hosting.asset.validators;
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.List;
import java.util.regex.Pattern;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.IPV6_NUMBER;
class HsIPv6NumberHostingAssetValidator extends HostingAssetEntityValidator {
// simplified pattern, the real check is done by letting Java parse the address
private static final Pattern IPV6_REGEX = Pattern.compile("([a-f0-9:]+:+)+[a-f0-9]+");
HsIPv6NumberHostingAssetValidator() {
super(
IPV6_NUMBER,
AlarmContact.isOptional(),
NO_EXTRA_PROPERTIES
);
}
@Override
public List<String> validateEntity(final HsHostingAssetEntity assetEntity) {
final var violations = super.validateEntity(assetEntity);
if (!isValidIPv6Address(assetEntity.getIdentifier())) {
violations.add("'identifier' expected to be a valid IPv6 address, but is '" + assetEntity.getIdentifier() + "'");
}
return violations;
}
@Override
protected Pattern identifierPattern(final HsHostingAssetEntity assetEntity) {
return IPV6_REGEX;
}
private boolean isValidIPv6Address(final String identifier) {
try {
return InetAddress.getByName(identifier) instanceof java.net.Inet6Address;
} catch (UnknownHostException e) {
return false;
}
}
}

View File

@ -24,6 +24,7 @@ components:
- MARIADB_USER - MARIADB_USER
- MARIADB_DATABASE - MARIADB_DATABASE
- IPV4_NUMBER - IPV4_NUMBER
- IPV6_NUMBER
HsHostingAsset: HsHostingAsset:
type: object type: object

View File

@ -22,7 +22,8 @@ create type HsHostingAssetType as enum (
'MARIADB_INSTANCE', 'MARIADB_INSTANCE',
'MARIADB_USER', 'MARIADB_USER',
'MARIADB_DATABASE', 'MARIADB_DATABASE',
'IPV4_NUMBER' 'IPV4_NUMBER',
'IPV6_NUMBER'
); );
CREATE CAST (character varying as HsHostingAssetType) WITH INOUT AS IMPLICIT; CREATE CAST (character varying as HsHostingAssetType) WITH INOUT AS IMPLICIT;
@ -88,6 +89,7 @@ begin
when 'MARIADB_DATABASE' then 'MARIADB_USER' when 'MARIADB_DATABASE' then 'MARIADB_USER'
when 'IPV4_NUMBER' then null when 'IPV4_NUMBER' then null
when 'IPV6_NUMBER' then null
else raiseException(format('[400] unknown asset type %s', NEW.type::text)) else raiseException(format('[400] unknown asset type %s', NEW.type::text))
end); end);

View File

@ -507,6 +507,25 @@ public class HsHostingAssetControllerRestTest {
"config": {} "config": {}
} }
] ]
"""),
IPV6_NUMBER(
List.of(
HsHostingAssetEntity.builder()
.type(HsHostingAssetType.IPV4_NUMBER)
.assignedToAsset(TEST_MANAGED_SERVER_HOSTING_ASSET)
.identifier("2001:db8:3333:4444:5555:6666:7777:8888")
.caption("some fake IPv6 number")
.build()),
"""
[
{
"type": "IPV4_NUMBER",
"identifier": "2001:db8:3333:4444:5555:6666:7777:8888",
"caption": "some fake IPv6 number",
"alarmContact": null,
"config": {}
}
]
"""); """);
final HsHostingAssetType assetType; final HsHostingAssetType assetType;

View File

@ -48,7 +48,8 @@ class HsHostingAssetPropsControllerAcceptanceTest {
"PGSQL_INSTANCE", "PGSQL_INSTANCE",
"PGSQL_USER", "PGSQL_USER",
"PGSQL_DATABASE", "PGSQL_DATABASE",
"IPV4_NUMBER" "IPV4_NUMBER",
"IPV6_NUMBER"
] ]
""")); """));
// @formatter:on // @formatter:on

View File

@ -14,6 +14,49 @@ class HsHostingAssetTypeUnitTest {
## HostingAsset Type Structure ## HostingAsset Type Structure
### Webspace+Server
```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
}
package Hosting #feb28c{
package Server #99bcdb {
entity HA_CLOUD_SERVER
entity HA_MANAGED_SERVER
entity HA_IPV4_NUMBER
entity HA_IPV6_NUMBER
}
}
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_IPV4_NUMBER o..> HA_CLOUD_SERVER
HA_IPV4_NUMBER o..> HA_MANAGED_SERVER
HA_IPV6_NUMBER o..> HA_CLOUD_SERVER
HA_IPV6_NUMBER o..> HA_MANAGED_SERVER
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
```
### Domain ### Domain
```plantuml ```plantuml
@ -37,12 +80,6 @@ class HsHostingAssetTypeUnitTest {
entity HA_EMAIL_ADDRESS entity HA_EMAIL_ADDRESS
} }
package Server #99bcdb {
entity HA_CLOUD_SERVER
entity HA_MANAGED_SERVER
entity HA_IPV4_NUMBER
}
package Webspace #99bcdb { package Webspace #99bcdb {
entity HA_MANAGED_WEBSPACE entity HA_MANAGED_WEBSPACE
entity HA_UNIX_USER entity HA_UNIX_USER
@ -55,10 +92,7 @@ class HsHostingAssetTypeUnitTest {
BI_MANAGED_SERVER *--> BI_PRIVATE_CLOUD BI_MANAGED_SERVER *--> BI_PRIVATE_CLOUD
BI_MANAGED_WEBSPACE *--> BI_MANAGED_SERVER 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 *==> BI_MANAGED_WEBSPACE
HA_MANAGED_WEBSPACE o..> HA_MANAGED_SERVER
HA_UNIX_USER *==> HA_MANAGED_WEBSPACE HA_UNIX_USER *==> HA_MANAGED_WEBSPACE
HA_EMAIL_ALIAS *==> HA_MANAGED_WEBSPACE HA_EMAIL_ALIAS *==> HA_MANAGED_WEBSPACE
HA_DOMAIN_SETUP o..> HA_DOMAIN_SETUP HA_DOMAIN_SETUP o..> HA_DOMAIN_SETUP
@ -71,9 +105,6 @@ class HsHostingAssetTypeUnitTest {
HA_DOMAIN_MBOX_SETUP *==> HA_DOMAIN_SETUP HA_DOMAIN_MBOX_SETUP *==> HA_DOMAIN_SETUP
HA_DOMAIN_MBOX_SETUP o--> HA_MANAGED_WEBSPACE HA_DOMAIN_MBOX_SETUP o--> HA_MANAGED_WEBSPACE
HA_EMAIL_ADDRESS *==> HA_DOMAIN_MBOX_SETUP HA_EMAIL_ADDRESS *==> HA_DOMAIN_MBOX_SETUP
HA_IPV4_NUMBER o..> HA_CLOUD_SERVER
HA_IPV4_NUMBER o..> HA_MANAGED_SERVER
HA_IPV4_NUMBER o..> HA_MANAGED_WEBSPACE
package Legend #white { package Legend #white {
SUB_ENTITY1 *--> REQUIRED_PARENT_ENTITY SUB_ENTITY1 *--> REQUIRED_PARENT_ENTITY
@ -104,12 +135,6 @@ class HsHostingAssetTypeUnitTest {
entity HA_MARIADB_DATABASE entity HA_MARIADB_DATABASE
} }
package Server #99bcdb {
entity HA_CLOUD_SERVER
entity HA_MANAGED_SERVER
entity HA_IPV4_NUMBER
}
package Webspace #99bcdb { package Webspace #99bcdb {
entity HA_MANAGED_WEBSPACE entity HA_MANAGED_WEBSPACE
entity HA_UNIX_USER entity HA_UNIX_USER
@ -122,19 +147,12 @@ class HsHostingAssetTypeUnitTest {
BI_MANAGED_SERVER *--> BI_PRIVATE_CLOUD BI_MANAGED_SERVER *--> BI_PRIVATE_CLOUD
BI_MANAGED_WEBSPACE *--> BI_MANAGED_SERVER 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 *==> BI_MANAGED_WEBSPACE
HA_MANAGED_WEBSPACE o..> HA_MANAGED_SERVER
HA_UNIX_USER *==> HA_MANAGED_WEBSPACE HA_UNIX_USER *==> HA_MANAGED_WEBSPACE
HA_EMAIL_ALIAS *==> HA_MANAGED_WEBSPACE HA_EMAIL_ALIAS *==> HA_MANAGED_WEBSPACE
HA_MARIADB_INSTANCE *==> HA_MANAGED_SERVER
HA_MARIADB_USER *==> HA_MANAGED_WEBSPACE HA_MARIADB_USER *==> HA_MANAGED_WEBSPACE
HA_MARIADB_USER o--> HA_MARIADB_INSTANCE HA_MARIADB_USER o--> HA_MARIADB_INSTANCE
HA_MARIADB_DATABASE *==> HA_MARIADB_USER HA_MARIADB_DATABASE *==> HA_MARIADB_USER
HA_IPV4_NUMBER o..> HA_CLOUD_SERVER
HA_IPV4_NUMBER o..> HA_MANAGED_SERVER
HA_IPV4_NUMBER o..> HA_MANAGED_WEBSPACE
package Legend #white { package Legend #white {
SUB_ENTITY1 *--> REQUIRED_PARENT_ENTITY SUB_ENTITY1 *--> REQUIRED_PARENT_ENTITY
@ -165,12 +183,6 @@ class HsHostingAssetTypeUnitTest {
entity HA_PGSQL_DATABASE entity HA_PGSQL_DATABASE
} }
package Server #99bcdb {
entity HA_CLOUD_SERVER
entity HA_MANAGED_SERVER
entity HA_IPV4_NUMBER
}
package Webspace #99bcdb { package Webspace #99bcdb {
entity HA_MANAGED_WEBSPACE entity HA_MANAGED_WEBSPACE
entity HA_UNIX_USER entity HA_UNIX_USER
@ -183,19 +195,12 @@ class HsHostingAssetTypeUnitTest {
BI_MANAGED_SERVER *--> BI_PRIVATE_CLOUD BI_MANAGED_SERVER *--> BI_PRIVATE_CLOUD
BI_MANAGED_WEBSPACE *--> BI_MANAGED_SERVER 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 *==> BI_MANAGED_WEBSPACE
HA_MANAGED_WEBSPACE o..> HA_MANAGED_SERVER
HA_UNIX_USER *==> HA_MANAGED_WEBSPACE HA_UNIX_USER *==> HA_MANAGED_WEBSPACE
HA_EMAIL_ALIAS *==> HA_MANAGED_WEBSPACE HA_EMAIL_ALIAS *==> HA_MANAGED_WEBSPACE
HA_PGSQL_INSTANCE *==> HA_MANAGED_SERVER
HA_PGSQL_USER *==> HA_MANAGED_WEBSPACE HA_PGSQL_USER *==> HA_MANAGED_WEBSPACE
HA_PGSQL_USER o--> HA_PGSQL_INSTANCE HA_PGSQL_USER o--> HA_PGSQL_INSTANCE
HA_PGSQL_DATABASE *==> HA_PGSQL_USER HA_PGSQL_DATABASE *==> HA_PGSQL_USER
HA_IPV4_NUMBER o..> HA_CLOUD_SERVER
HA_IPV4_NUMBER o..> HA_MANAGED_SERVER
HA_IPV4_NUMBER o..> HA_MANAGED_WEBSPACE
package Legend #white { package Legend #white {
SUB_ENTITY1 *--> REQUIRED_PARENT_ENTITY SUB_ENTITY1 *--> REQUIRED_PARENT_ENTITY

View File

@ -46,7 +46,8 @@ class HostingAssetEntityValidatorRegistryUnitTest {
HsHostingAssetType.PGSQL_INSTANCE, HsHostingAssetType.PGSQL_INSTANCE,
HsHostingAssetType.PGSQL_USER, HsHostingAssetType.PGSQL_USER,
HsHostingAssetType.PGSQL_DATABASE, HsHostingAssetType.PGSQL_DATABASE,
HsHostingAssetType.IPV4_NUMBER HsHostingAssetType.IPV4_NUMBER,
HsHostingAssetType.IPV6_NUMBER
); );
} }
} }

View File

@ -0,0 +1,120 @@
package net.hostsharing.hsadminng.hs.hosting.asset.validators;
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemEntity;
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType;
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity;
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity.HsHostingAssetEntityBuilder;
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource;
import org.junit.jupiter.params.provider.ValueSource;
import java.util.Map;
import static java.util.Map.entry;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.IPV6_NUMBER;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MANAGED_WEBSPACE;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.UNIX_USER;
import static org.assertj.core.api.Assertions.assertThat;
class HsIPv6NumberHostingAssetValidatorUnitTest {
static HsHostingAssetEntityBuilder validEntityBuilder() {
return HsHostingAssetEntity.builder()
.type(IPV6_NUMBER)
.identifier("2001:db8:3333:4444:5555:6666:7777:8888");
}
@Test
void containsExpectedProperties() {
// when
final var validator = HostingAssetEntityValidatorRegistry.forType(IPV6_NUMBER);
// then
assertThat(validator.properties()).map(Map::toString).isEmpty();
}
@Test
void acceptsValidEntity() {
// given
final var givenEntity = validEntityBuilder().build();
final var validator = HostingAssetEntityValidatorRegistry.forType(givenEntity.getType());
// when
final var result = validator.validateEntity(givenEntity);
// then
assertThat(result).isEmpty();
}
@ParameterizedTest
@ValueSource(strings = {"83.223.95", "2a01:37:1000::53df:5f91:0:123::123"})
void rejectsInvalidIdentifier(final String givenIdentifier) {
// given
final var givenEntity = validEntityBuilder().identifier(givenIdentifier).build();
final var validator = HostingAssetEntityValidatorRegistry.forType(givenEntity.getType());
// when
final var result = validator.validateEntity(givenEntity);
// then
assertThat(result).contains(
"'identifier' expected to be a valid IPv6 address, but is '" + givenIdentifier + "'"
);
}
@ParameterizedTest
@EnumSource(value = HsHostingAssetType.class, names = { "CLOUD_SERVER", "MANAGED_SERVER", "MANAGED_WEBSPACE" })
void acceptsValidReferencedEntity(final HsHostingAssetType givenAssignedToAssetType) {
// given
final var ipNumberHostingAssetEntity = validEntityBuilder()
.assignedToAsset(HsHostingAssetEntity.builder().type(givenAssignedToAssetType).build())
.build();
final var validator = HostingAssetEntityValidatorRegistry.forType(ipNumberHostingAssetEntity.getType());
// when
final var result = validator.validateEntity(ipNumberHostingAssetEntity);
// then
assertThat(result).isEmpty();
}
@Test
void rejectsInvalidReferencedEntities() {
// given
final var ipNumberHostingAssetEntity = validEntityBuilder()
.bookingItem(HsBookingItemEntity.builder().type(HsBookingItemType.CLOUD_SERVER).build())
.parentAsset(HsHostingAssetEntity.builder().type(MANAGED_WEBSPACE).build())
.assignedToAsset(HsHostingAssetEntity.builder().type(UNIX_USER).build())
.build();
final var validator = HostingAssetEntityValidatorRegistry.forType(ipNumberHostingAssetEntity.getType());
// when
final var result = validator.validateEntity(ipNumberHostingAssetEntity);
// then
assertThat(result).containsExactlyInAnyOrder(
"'IPV6_NUMBER:2001:db8:3333:4444:5555:6666:7777:8888.bookingItem' must be null but is of type CLOUD_SERVER",
"'IPV6_NUMBER:2001:db8:3333:4444:5555:6666:7777:8888.parentAsset' must be null but is of type MANAGED_WEBSPACE",
"'IPV6_NUMBER:2001:db8:3333:4444:5555:6666:7777:8888.assignedToAsset' must be null or of type CLOUD_SERVER or MANAGED_SERVER or MANAGED_WEBSPACE but is of type UNIX_USER");
}
@Test
void rejectsInvalidProperties() {
// given
final var ipNumberHostingAssetEntity = validEntityBuilder()
.config(Map.ofEntries(
entry("any", "false")
))
.build();
final var validator = HostingAssetEntityValidatorRegistry.forType(ipNumberHostingAssetEntity.getType());
// when
final var result = validator.validateEntity(ipNumberHostingAssetEntity);
// then
assertThat(result).containsExactlyInAnyOrder(
"'IPV6_NUMBER:2001:db8:3333:4444:5555:6666:7777:8888.config.any' is not expected but is set to 'false'");
}
}