add-mariadb-instance-database-and-user-validations #75

Merged
hsh-michaelhoennig merged 6 commits from add-mariadb-instance-database-and-user-validations into master 2024-07-12 10:54:47 +02:00
9 changed files with 186 additions and 8 deletions
Showing only changes of commit 95b830322a - Show all commits

View File

@ -105,8 +105,8 @@ public enum HsHostingAssetType implements Node {
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?
requiredParent(MARIADB_INSTANCE), // TODO.spec: or MARIADB_USER?
assignedTo(MARIADB_USER)), // TODO.spec: or swapping parent+assignedTo?
IP_NUMBER(
inGroup("Server"),

View File

@ -28,6 +28,7 @@ public class HostingAssetEntityValidatorRegistry {
register(EMAIL_ADDRESS, new HsEMailAddressHostingAssetValidator());
register(MARIADB_INSTANCE, new HsMariaDbInstanceHostingAssetValidator());
register(MARIADB_USER, new HsMariaDbUserHostingAssetValidator());
register(MARIADB_DATABASE, new HsMariaDbDatabaseHostingAssetValidator());
}
private static void register(final Enum<HsHostingAssetType> type, final HsEntityValidator<HsHostingAssetEntity> validator) {

View File

@ -0,0 +1,26 @@
package net.hostsharing.hsadminng.hs.hosting.asset.validators;
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity;
import java.util.regex.Pattern;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MARIADB_DATABASE;
import static net.hostsharing.hsadminng.hs.validation.StringProperty.stringProperty;
class HsMariaDbDatabaseHostingAssetValidator extends HostingAssetEntityValidator {
public HsMariaDbDatabaseHostingAssetValidator() {
super(
MARIADB_DATABASE,
AlarmContact.isOptional(),
stringProperty("encoding").matchesRegEx("[a-z0-9_]+").maxLength(24).provided("latin2", "utf8").withDefault("utf8"),
stringProperty("collation").matchesRegEx("[a-z0-9_]+").maxLength(24).provided("latin2", "utf8").withDefault("utf8"));
}
@Override
protected Pattern identifierPattern(final HsHostingAssetEntity assetEntity) {
final var webspaceIdentifier = assetEntity.getAssignedToAsset().getAssignedToAsset().getIdentifier();
return Pattern.compile("^"+webspaceIdentifier+"$|^"+webspaceIdentifier+"_[a-z0-9]+$");
}
}

View File

@ -26,6 +26,7 @@ declare
domainSetupUuid uuid;
domainMBoxSetupUuid uuid;
mariaDbInstanceUuid uuid;
mariaDbUserUuid uuid;
begin
currentTask := 'creating hosting-asset test-data ' || givenProjectCaption;
call defineContext(currentTask, null, 'superuser-alex@hostsharing.net', 'global#global:ADMIN');
@ -71,6 +72,7 @@ begin
select uuid_generate_v4() into domainSetupUuid;
select uuid_generate_v4() into domainMBoxSetupUuid;
select uuid_generate_v4() into mariaDbInstanceUuid;
select uuid_generate_v4() into mariaDbUserUuid;
debitorNumberSuffix := relatedDebitor.debitorNumberSuffix;
defaultPrefix := relatedDebitor.defaultPrefix;
@ -79,9 +81,10 @@ begin
values
(managedServerUuid, managedServerBI.uuid, 'MANAGED_SERVER', null, null, 'vm10' || debitorNumberSuffix, 'some ManagedServer', '{ "monit_max_cpu_usage": 90, "monit_max_ram_usage": 80, "monit_max_ssd_usage": 70 }'::jsonb),
(uuid_generate_v4(), cloudServerBI.uuid, 'CLOUD_SERVER', null, null, 'vm20' || debitorNumberSuffix, 'another CloudServer', '{}'::jsonb),
(mariaDbInstanceUuid, null, 'MARIADB_INSTANCE', managedServerUuid, null, 'vm10' || debitorNumberSuffix || '.MariaDB.default', 'some default MariaDB instance','{}'::jsonb),
(uuid_generate_v4(), null, 'MARIADB_USER', mariaDbInstanceUuid, null, defaultPrefix || '01_web', 'some default MariaDB user', '{ "password": "<TODO:replace-by-encrypted-mariadb-password"}'::jsonb ),
(managedWebspaceUuid, managedWebspaceBI.uuid, 'MANAGED_WEBSPACE', managedServerUuid, null, defaultPrefix || '01', 'some Webspace', '{}'::jsonb),
(mariaDbInstanceUuid, null, 'MARIADB_INSTANCE', managedServerUuid, null, 'vm10' || debitorNumberSuffix || '.MariaDB.default', 'some default MariaDB instance','{}'::jsonb),
(mariaDbUserUuid, null, 'MARIADB_USER', mariaDbInstanceUuid, managedWebspaceUuid, defaultPrefix || '01_web', 'some default MariaDB user', '{ "password": "<TODO:replace-by-encrypted-mariadb-password"}'::jsonb ),
(uuid_generate_v4(), null, 'MARIADB_DATABASE', mariaDbInstanceUuid, mariaDbUserUuid, defaultPrefix || '01_web', 'some default MariaDB database','{ "encryption": "utf8", "collation": "utf8"}'::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),
(domainSetupUuid, null, 'DOMAIN_SETUP', null, null, defaultPrefix || '.example.org', 'some Domain-Setup', '{}'::jsonb),

View File

@ -401,6 +401,31 @@ public class HsHostingAssetControllerRestTest {
"config": {}
}
]
"""),
MARIADB_DATABASE(
List.of(
HsHostingAssetEntity.builder()
.type(HsHostingAssetType.MARIADB_DATABASE)
.identifier("xyz00_temp")
.caption("some fake MariaDB database")
.config(Map.ofEntries(
entry("encoding", "latin1"),
entry("collation", "latin2")
))
.build()),
"""
[
{
"type": "MARIADB_DATABASE",
"identifier": "xyz00_temp",
"caption": "some fake MariaDB database",
"alarmContact": null,
"config": {
"encoding": "latin1",
"collation": "latin2"
}
}
]
""");
final HsHostingAssetType assetType;

View File

@ -43,7 +43,8 @@ class HsHostingAssetPropsControllerAcceptanceTest {
"DOMAIN_MBOX_SETUP",
"EMAIL_ADDRESS",
"MARIADB_INSTANCE",
"MARIADB_USER"
"MARIADB_USER",
"MARIADB_DATABASE"
]
"""));
// @formatter:on

View File

@ -131,8 +131,8 @@ class HsHostingAssetTypeUnitTest {
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_MARIADB_DATABASE *==> HA_MARIADB_INSTANCE
HA_MARIADB_DATABASE o..> HA_MARIADB_USER
HA_IP_NUMBER o..> HA_CLOUD_SERVER
HA_IP_NUMBER o..> HA_MANAGED_SERVER
HA_IP_NUMBER o..> HA_MANAGED_WEBSPACE

View File

@ -41,7 +41,8 @@ class HostingAssetEntityValidatorRegistryUnitTest {
HsHostingAssetType.DOMAIN_MBOX_SETUP,
HsHostingAssetType.EMAIL_ADDRESS,
HsHostingAssetType.MARIADB_INSTANCE,
HsHostingAssetType.MARIADB_USER
HsHostingAssetType.MARIADB_USER,
HsHostingAssetType.MARIADB_DATABASE
);
}
}

View File

@ -0,0 +1,121 @@
package net.hostsharing.hsadminng.hs.hosting.asset.validators;
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity;
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity.HsHostingAssetEntityBuilder;
import org.junit.jupiter.api.Test;
import java.util.HashMap;
import java.util.stream.Stream;
import static java.util.Map.ofEntries;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MARIADB_DATABASE;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MARIADB_INSTANCE;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MARIADB_USER;
import static net.hostsharing.hsadminng.hs.hosting.asset.TestHsHostingAssetEntities.TEST_MANAGED_SERVER_HOSTING_ASSET;
import static net.hostsharing.hsadminng.hs.hosting.asset.TestHsHostingAssetEntities.TEST_MANAGED_WEBSPACE_HOSTING_ASSET;
import static net.hostsharing.hsadminng.mapper.PatchMap.entry;
import static org.assertj.core.api.Assertions.assertThat;
class HsMariaDbDatabaseHostingAssetValidatorUnitTest {
private static final HsHostingAssetEntity GIVEN_MARIADB_INSTANCE = HsHostingAssetEntity.builder()
.type(MARIADB_INSTANCE)
.parentAsset(TEST_MANAGED_SERVER_HOSTING_ASSET)
.identifier("vm1234|MariaDB.default")
.caption("some valid test MariaDB-Instance")
.build();
private static final HsHostingAssetEntity GIVEN_MARIADB_USER = HsHostingAssetEntity.builder()
.type(MARIADB_USER)
.parentAsset(GIVEN_MARIADB_INSTANCE)
.assignedToAsset(TEST_MANAGED_WEBSPACE_HOSTING_ASSET)
.identifier("xyz00_temp")
.caption("some valid test MariaDB-User")
.config(new HashMap<>(ofEntries(
entry("password", "Hallo Datenbank, lass mich rein!")
)))
.build();
private static HsHostingAssetEntityBuilder givenValidMariaDbDatabaseBuilder() {
return HsHostingAssetEntity.builder()
.type(MARIADB_DATABASE)
.parentAsset(GIVEN_MARIADB_INSTANCE)
.assignedToAsset(GIVEN_MARIADB_USER)
.identifier("xyz00_temp")
.caption("some valid test MariaDB-Database")
.config(new HashMap<>(ofEntries(
entry("encoding", "latin1"),
entry("collation", "latin1")
)));
}
@Test
void describesItsProperties() {
// given
final var validator = HostingAssetEntityValidatorRegistry.forType(givenValidMariaDbDatabaseBuilder().build().getType());
// when
final var props = validator.properties();
// then
assertThat(props).extracting(Object::toString).containsExactlyInAnyOrder(
"{type=string, propertyName=encoding, matchesRegEx=[[a-z0-9_]+], maxLength=24, provided=[latin2, utf8], defaultValue=utf8}",
"{type=string, propertyName=collation, matchesRegEx=[[a-z0-9_]+], maxLength=24, provided=[latin2, utf8], defaultValue=utf8}"
);
}
@Test
void validatesValidEntity() {
// given
final var givenMariaDbUserHostingAsset = givenValidMariaDbDatabaseBuilder().build();
final var validator = HostingAssetEntityValidatorRegistry.forType(givenMariaDbUserHostingAsset.getType());
// when
final var result = Stream.concat(
validator.validateEntity(givenMariaDbUserHostingAsset).stream(),
validator.validateContext(givenMariaDbUserHostingAsset).stream()
).toList();
// then
assertThat(result).isEmpty();
}
@Test
void rejectsInvalidProperties() {
// given
final var givenMariaDbUserHostingAsset = givenValidMariaDbDatabaseBuilder()
.config(ofEntries(
entry("unknown", "wrong"),
entry("encoding", 10),
entry("collation", 20)
))
.build();
final var validator = HostingAssetEntityValidatorRegistry.forType(givenMariaDbUserHostingAsset.getType());
// when
final var result = validator.validateEntity(givenMariaDbUserHostingAsset);
// then
assertThat(result).containsExactlyInAnyOrder(
"'MARIADB_DATABASE:xyz00_temp.config.unknown' is not expected but is set to 'wrong'",
"'MARIADB_DATABASE:xyz00_temp.config.encoding' is expected to be of type String, but is of type Integer",
"'MARIADB_DATABASE:xyz00_temp.config.collation' is expected to be of type String, but is of type Integer"
);
}
@Test
void rejectsInvalidIdentifier() {
// given
final var givenMariaDbUserHostingAsset = givenValidMariaDbDatabaseBuilder()
.identifier("xyz99-temp")
.build();
final var validator = HostingAssetEntityValidatorRegistry.forType(givenMariaDbUserHostingAsset.getType());
// when
final var result = validator.validateEntity(givenMariaDbUserHostingAsset);
// then
assertThat(result).containsExactly(
"'identifier' expected to match '^xyz00$|^xyz00_[a-z0-9]+$', but is 'xyz99-temp'");
}
}