diff --git a/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HostingAssetEntityValidatorRegistry.java b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HostingAssetEntityValidatorRegistry.java index c44bf92a..aa4657b4 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HostingAssetEntityValidatorRegistry.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HostingAssetEntityValidatorRegistry.java @@ -26,6 +26,7 @@ public class HostingAssetEntityValidatorRegistry { register(DOMAIN_SMTP_SETUP, new HsDomainSmtpSetupHostingAssetValidator()); register(DOMAIN_MBOX_SETUP, new HsDomainMboxSetupHostingAssetValidator()); register(EMAIL_ADDRESS, new HsEMailAddressHostingAssetValidator()); + register(MARIADB_INSTANCE, new HsMariaDbInstanceHostingAssetValidator()); } private static void register(final Enum type, final HsEntityValidator validator) { diff --git a/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsMariaDbInstanceHostingAssetValidator.java b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsMariaDbInstanceHostingAssetValidator.java new file mode 100644 index 00000000..88bfb50d --- /dev/null +++ b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsMariaDbInstanceHostingAssetValidator.java @@ -0,0 +1,37 @@ +package net.hostsharing.hsadminng.hs.hosting.asset.validators; + +import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity; + +import java.util.regex.Pattern; + +import static java.util.Optional.ofNullable; +import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MARIADB_INSTANCE; + +class HsMariaDbInstanceHostingAssetValidator extends HostingAssetEntityValidator { + + final static String DEFAULT_INSTANCE_IDENTIFIER_SUFFIX = "|MariaDB.default"; // TODO.spec: specify instance naming + + public HsMariaDbInstanceHostingAssetValidator() { + super( + MARIADB_INSTANCE, + AlarmContact.isOptional(), // hostmaster alert address is implicitly added + NO_EXTRA_PROPERTIES); // TODO.spec: specify instance properties, e.g. installed extensions + } + + @Override + protected Pattern identifierPattern(final HsHostingAssetEntity assetEntity) { + return Pattern.compile( + "^" + Pattern.quote(assetEntity.getParentAsset().getIdentifier() + + DEFAULT_INSTANCE_IDENTIFIER_SUFFIX) + + "$"); + } + + @Override + public void preprocessEntity(final HsHostingAssetEntity entity) { + super.preprocessEntity(entity); + if (entity.getIdentifier() == null) { + ofNullable(entity.getParentAsset()).ifPresent(pa -> entity.setIdentifier( + pa.getIdentifier() + DEFAULT_INSTANCE_IDENTIFIER_SUFFIX)); + } + } +} diff --git a/src/main/resources/api-definition/hs-hosting/hs-hosting-asset-schemas.yaml b/src/main/resources/api-definition/hs-hosting/hs-hosting-asset-schemas.yaml index f4a25607..d467031f 100644 --- a/src/main/resources/api-definition/hs-hosting/hs-hosting-asset-schemas.yaml +++ b/src/main/resources/api-definition/hs-hosting/hs-hosting-asset-schemas.yaml @@ -19,6 +19,7 @@ components: - EMAIL_ADDRESS - PGSQL_USER - PGSQL_DATABASE + - MARIADB_INSTANCE - MARIADB_USER - MARIADB_DATABASE diff --git a/src/main/resources/db/changelog/7-hs-hosting/701-hosting-asset/7010-hs-hosting-asset.sql b/src/main/resources/db/changelog/7-hs-hosting/701-hosting-asset/7010-hs-hosting-asset.sql index c1b4bbcc..70f102c2 100644 --- a/src/main/resources/db/changelog/7-hs-hosting/701-hosting-asset/7010-hs-hosting-asset.sql +++ b/src/main/resources/db/changelog/7-hs-hosting/701-hosting-asset/7010-hs-hosting-asset.sql @@ -18,6 +18,7 @@ create type HsHostingAssetType as enum ( 'EMAIL_ADDRESS', 'PGSQL_USER', 'PGSQL_DATABASE', + 'MARIADB_INSTANCE', 'MARIADB_USER', 'MARIADB_DATABASE' ); @@ -74,6 +75,7 @@ begin when 'EMAIL_ADDRESS' then 'DOMAIN_MBOX_SETUP' when 'PGSQL_USER' then 'MANAGED_WEBSPACE' when 'PGSQL_DATABASE' then 'MANAGED_WEBSPACE' + when 'MARIADB_INSTANCE' then 'MANAGED_SERVER' when 'MARIADB_USER' then 'MANAGED_WEBSPACE' when 'MARIADB_DATABASE' then 'MANAGED_WEBSPACE' else raiseException(format('[400] unknown asset type %s', NEW.type::text)) diff --git a/src/main/resources/db/changelog/7-hs-hosting/701-hosting-asset/7018-hs-hosting-asset-test-data.sql b/src/main/resources/db/changelog/7-hs-hosting/701-hosting-asset/7018-hs-hosting-asset-test-data.sql index f43edef0..0d4b6a91 100644 --- a/src/main/resources/db/changelog/7-hs-hosting/701-hosting-asset/7018-hs-hosting-asset-test-data.sql +++ b/src/main/resources/db/changelog/7-hs-hosting/701-hosting-asset/7018-hs-hosting-asset-test-data.sql @@ -25,6 +25,7 @@ declare webUnixUserUuid uuid; domainSetupUuid uuid; domainMBoxSetupUuid uuid; + mariaDbInstanceUuid uuid; begin currentTask := 'creating hosting-asset test-data ' || givenProjectCaption; call defineContext(currentTask, null, 'superuser-alex@hostsharing.net', 'global#global:ADMIN'); @@ -69,22 +70,25 @@ begin select uuid_generate_v4() into webUnixUserUuid; select uuid_generate_v4() into domainSetupUuid; select uuid_generate_v4() into domainMBoxSetupUuid; + select uuid_generate_v4() into mariaDbInstanceUuid; debitorNumberSuffix := relatedDebitor.debitorNumberSuffix; defaultPrefix := relatedDebitor.defaultPrefix; insert into hs_hosting_asset - (uuid, bookingitemuuid, type, parentAssetUuid, assignedToAssetUuid, identifier, caption, config) - 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), - (managedWebspaceUuid, managedWebspaceBI.uuid, 'MANAGED_WEBSPACE', managedServerUuid, null, defaultPrefix || '01', 'some Webspace', '{}'::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), - (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|HTTP', 'some Domain-HTTP-Setup', '{ "option-htdocsfallback": true, "use-fcgiphpbin": "/usr/lib/cgi-bin/php", "validsubdomainnames": "*"}'::jsonb), - (uuid_generate_v4(), null, 'DOMAIN_SMTP_SETUP', domainSetupUuid, managedWebspaceUuid, defaultPrefix || '.example.org|DNS', 'some Domain-SMPT-Setup', '{}'::jsonb), - (domainMBoxSetupUuid, null, 'DOMAIN_MBOX_SETUP', domainSetupUuid, managedWebspaceUuid, defaultPrefix || '.example.org|DNS', 'some Domain-MBOX-Setup', '{}'::jsonb), - (uuid_generate_v4(), null, 'EMAIL_ADDRESS', domainMBoxSetupUuid, null, 'test@' || defaultPrefix || '.example.org', 'some E-Mail-Address', '{}'::jsonb); + (uuid, bookingitemuuid, type, parentAssetUuid, assignedToAssetUuid, identifier, caption, config) + 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), + (managedWebspaceUuid, managedWebspaceBI.uuid, 'MANAGED_WEBSPACE', managedServerUuid, null, defaultPrefix || '01', 'some Webspace', '{}'::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), + (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|HTTP', 'some Domain-HTTP-Setup', '{ "option-htdocsfallback": true, "use-fcgiphpbin": "/usr/lib/cgi-bin/php", "validsubdomainnames": "*"}'::jsonb), + (uuid_generate_v4(), null, 'DOMAIN_SMTP_SETUP', domainSetupUuid, managedWebspaceUuid, defaultPrefix || '.example.org|DNS', 'some Domain-SMPT-Setup', '{}'::jsonb), + (domainMBoxSetupUuid, null, 'DOMAIN_MBOX_SETUP', domainSetupUuid, managedWebspaceUuid, defaultPrefix || '.example.org|DNS', 'some Domain-MBOX-Setup', '{}'::jsonb), + (uuid_generate_v4(), null, 'EMAIL_ADDRESS', domainMBoxSetupUuid, null, 'test@' || defaultPrefix || '.example.org', 'some E-Mail-Address', '{}'::jsonb); end; $$; --// diff --git a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetControllerRestTest.java b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetControllerRestTest.java index 4a5bc04c..0dc425f8 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetControllerRestTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetControllerRestTest.java @@ -30,6 +30,7 @@ import java.util.Map; 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_MANAGED_SERVER_BOOKING_ITEM; +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.hs.office.contact.TestHsOfficeContact.TEST_CONTACT; import static net.hostsharing.hsadminng.rbac.test.JsonMatcher.lenientlyEquals; @@ -363,6 +364,25 @@ public class HsHostingAssetControllerRestTest { } } ] + """), + MARIADB_INSTANCE( + List.of( + HsHostingAssetEntity.builder() + .type(HsHostingAssetType.MARIADB_INSTANCE) + .parentAsset(TEST_MANAGED_SERVER_HOSTING_ASSET) + .identifier("vm1234|MariaDB.default") + .caption("some fake MariaDB instance") + .build()), + """ + [ + { + "type": "MARIADB_INSTANCE", + "identifier": "vm1234|MariaDB.default", + "caption": "some fake MariaDB instance", + "alarmContact": null, + "config": {} + } + ] """); final HsHostingAssetType assetType; diff --git a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetPropsControllerAcceptanceTest.java b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetPropsControllerAcceptanceTest.java index 290777ea..9020d076 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetPropsControllerAcceptanceTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetPropsControllerAcceptanceTest.java @@ -41,7 +41,8 @@ class HsHostingAssetPropsControllerAcceptanceTest { "DOMAIN_HTTP_SETUP", "DOMAIN_SMTP_SETUP", "DOMAIN_MBOX_SETUP", - "EMAIL_ADDRESS" + "EMAIL_ADDRESS", + "MARIADB_INSTANCE" ] """)); // @formatter:on diff --git a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetRepositoryIntegrationTest.java index 40f38d7b..8d62e4cb 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetRepositoryIntegrationTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetRepositoryIntegrationTest.java @@ -245,7 +245,8 @@ class HsHostingAssetRepositoryIntegrationTest extends ContextBasedTestWithCleanu // then exactlyTheseAssetsAreReturned( result, - "HsHostingAssetEntity(MANAGED_WEBSPACE, sec01, some Webspace, MANAGED_SERVER:vm1012, D-1000212:D-1000212 default project:separate ManagedWebspace)"); + "HsHostingAssetEntity(MANAGED_WEBSPACE, sec01, some Webspace, MANAGED_SERVER:vm1012, D-1000212:D-1000212 default project:separate ManagedWebspace)", + "HsHostingAssetEntity(MARIADB_INSTANCE, vm1012.MariaDB.default, some default MariaDB instance, MANAGED_SERVER:vm1012)"); } } diff --git a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HostingAssetEntityValidatorRegistryUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HostingAssetEntityValidatorRegistryUnitTest.java index c1c8a53c..887a0368 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HostingAssetEntityValidatorRegistryUnitTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HostingAssetEntityValidatorRegistryUnitTest.java @@ -39,7 +39,8 @@ class HostingAssetEntityValidatorRegistryUnitTest { HsHostingAssetType.DOMAIN_HTTP_SETUP, HsHostingAssetType.DOMAIN_SMTP_SETUP, HsHostingAssetType.DOMAIN_MBOX_SETUP, - HsHostingAssetType.EMAIL_ADDRESS + HsHostingAssetType.EMAIL_ADDRESS, + HsHostingAssetType.MARIADB_INSTANCE ); } } diff --git a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsMariaDbInstanceHostingAssetValidatorUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsMariaDbInstanceHostingAssetValidatorUnitTest.java new file mode 100644 index 00000000..24d8b4d1 --- /dev/null +++ b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsMariaDbInstanceHostingAssetValidatorUnitTest.java @@ -0,0 +1,116 @@ +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 org.junit.jupiter.api.Test; + +import java.util.Map; + +import static java.util.Map.entry; +import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.DOMAIN_SMTP_SETUP; +import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MANAGED_WEBSPACE; +import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MARIADB_INSTANCE; +import static net.hostsharing.hsadminng.hs.hosting.asset.TestHsHostingAssetEntities.TEST_MANAGED_SERVER_HOSTING_ASSET; +import static net.hostsharing.hsadminng.hs.hosting.asset.validators.HsMariaDbInstanceHostingAssetValidator.DEFAULT_INSTANCE_IDENTIFIER_SUFFIX; +import static org.assertj.core.api.Assertions.assertThat; + +class HsMariaDbInstanceHostingAssetValidatorUnitTest { + + static HsHostingAssetEntityBuilder validEntityBuilder() { + return HsHostingAssetEntity.builder() + .type(MARIADB_INSTANCE) + .parentAsset(TEST_MANAGED_SERVER_HOSTING_ASSET) + .identifier(TEST_MANAGED_SERVER_HOSTING_ASSET.getIdentifier() + DEFAULT_INSTANCE_IDENTIFIER_SUFFIX); + } + + @Test + void containsExpectedProperties() { + // when + final var validator = HostingAssetEntityValidatorRegistry.forType(DOMAIN_SMTP_SETUP); + + // then + assertThat(validator.properties()).map(Map::toString).isEmpty(); + } + + @Test + void preprocessesTakesIdentifierFromParent() { + // given + final var givenEntity = validEntityBuilder().build(); + assertThat(givenEntity.getParentAsset().getIdentifier()).as("precondition failed").isEqualTo("vm1234"); + final var validator = HostingAssetEntityValidatorRegistry.forType(givenEntity.getType()); + + // when + validator.preprocessEntity(givenEntity); + + // then + assertThat(givenEntity.getIdentifier()).isEqualTo("vm1234|MariaDB.default"); + } + + @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(); + } + + @Test + void rejectsInvalidIdentifier() { + // given + final var givenEntity = validEntityBuilder().identifier("example.org").build(); + final var validator = HostingAssetEntityValidatorRegistry.forType(givenEntity.getType()); + + // when + final var result = validator.validateEntity(givenEntity); + + // then + assertThat(result).containsExactly( + "'identifier' expected to match '^\\Qvm1234|MariaDB.default\\E$', but is 'example.org'" + ); + } + + @Test + void rejectsInvalidReferencedEntities() { + // given + final var mangedServerHostingAssetEntity = validEntityBuilder() + .bookingItem(HsBookingItemEntity.builder().type(HsBookingItemType.CLOUD_SERVER).build()) + .parentAsset(HsHostingAssetEntity.builder().type(MANAGED_WEBSPACE).build()) + .assignedToAsset(HsHostingAssetEntity.builder().type(MANAGED_WEBSPACE).build()) + .build(); + final var validator = HostingAssetEntityValidatorRegistry.forType(mangedServerHostingAssetEntity.getType()); + + // when + final var result = validator.validateEntity(mangedServerHostingAssetEntity); + + // then + assertThat(result).containsExactlyInAnyOrder( + "'MARIADB_INSTANCE:vm1234|MariaDB.default.bookingItem' must be null but is of type CLOUD_SERVER", + "'MARIADB_INSTANCE:vm1234|MariaDB.default.parentAsset' must be of type MANAGED_SERVER but is of type MANAGED_WEBSPACE", + "'MARIADB_INSTANCE:vm1234|MariaDB.default.assignedToAsset' must be null but is of type MANAGED_WEBSPACE"); + } + + @Test + void rejectsInvalidProperties() { + // given + final var mangedServerHostingAssetEntity = validEntityBuilder() + .config(Map.ofEntries( + entry("any", "false") + )) + .build(); + final var validator = HostingAssetEntityValidatorRegistry.forType(mangedServerHostingAssetEntity.getType()); + + // when + final var result = validator.validateEntity(mangedServerHostingAssetEntity); + + // then + assertThat(result).containsExactlyInAnyOrder( + "'MARIADB_INSTANCE:vm1234|MariaDB.default.config.any' is not expected but is set to 'false'"); + } +}