diff --git a/dbrepo-auth-service/dbrepo-realm.json b/dbrepo-auth-service/dbrepo-realm.json index 2c6effa792933ab8d68cf8286a6d5417e5119bfe..e057f778d4796aa1fd90c94c920a4abcec720de2 100644 --- a/dbrepo-auth-service/dbrepo-realm.json +++ b/dbrepo-auth-service/dbrepo-realm.json @@ -530,7 +530,7 @@ "description" : "${default-container-handling}", "composite" : true, "composites" : { - "realm" : [ "find-container", "list-containers" ] + "realm" : [ "find-container" ] }, "clientRole" : false, "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", @@ -2143,7 +2143,7 @@ "subType" : "anonymous", "subComponents" : { }, "config" : { - "allowed-protocol-mapper-types" : [ "oidc-usermodel-attribute-mapper", "saml-user-attribute-mapper", "oidc-usermodel-property-mapper", "saml-role-list-mapper", "oidc-address-mapper", "oidc-full-name-mapper", "oidc-sha256-pairwise-sub-mapper", "saml-user-property-mapper" ] + "allowed-protocol-mapper-types" : [ "saml-user-attribute-mapper", "oidc-full-name-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-address-mapper", "saml-user-property-mapper", "oidc-usermodel-property-mapper", "oidc-usermodel-attribute-mapper", "saml-role-list-mapper" ] } }, { "id" : "1849e52a-b8c9-44a8-af3d-ee19376a1ed1", @@ -2169,7 +2169,7 @@ "subType" : "authenticated", "subComponents" : { }, "config" : { - "allowed-protocol-mapper-types" : [ "oidc-sha256-pairwise-sub-mapper", "oidc-full-name-mapper", "saml-user-property-mapper", "saml-user-attribute-mapper", "saml-role-list-mapper", "oidc-usermodel-attribute-mapper", "oidc-usermodel-property-mapper", "oidc-address-mapper" ] + "allowed-protocol-mapper-types" : [ "saml-role-list-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-full-name-mapper", "oidc-usermodel-property-mapper", "oidc-usermodel-attribute-mapper", "saml-user-property-mapper", "saml-user-attribute-mapper", "oidc-address-mapper" ] } } ], "org.keycloak.storage.UserStorageProvider" : [ { @@ -2185,8 +2185,8 @@ "config" : { "ldap.attribute" : [ "createTimestamp" ], "is.mandatory.in.ldap" : [ "false" ], - "always.read.value.from.ldap" : [ "true" ], "read.only" : [ "true" ], + "always.read.value.from.ldap" : [ "true" ], "user.model.attribute" : [ "createTimestamp" ] } }, { @@ -2221,8 +2221,8 @@ "config" : { "ldap.attribute" : [ "mail" ], "is.mandatory.in.ldap" : [ "false" ], - "read.only" : [ "false" ], "always.read.value.from.ldap" : [ "false" ], + "read.only" : [ "false" ], "user.model.attribute" : [ "email" ] } }, { @@ -2233,17 +2233,17 @@ "config" : { "membership.attribute.type" : [ "DN" ], "group.name.ldap.attribute" : [ "cn" ], - "membership.user.ldap.attribute" : [ "uid" ], "preserve.group.inheritance" : [ "false" ], + "membership.user.ldap.attribute" : [ "uid" ], "groups.dn" : [ "ou=users,dc=dbrepo,dc=at" ], "mode" : [ "LDAP_ONLY" ], "user.roles.retrieve.strategy" : [ "LOAD_GROUPS_BY_MEMBER_ATTRIBUTE" ], "ignore.missing.groups" : [ "false" ], "membership.ldap.attribute" : [ "member" ], - "group.object.classes" : [ "groupOfNames" ], "memberof.ldap.attribute" : [ "memberOf" ], - "drop.non.existing.groups.during.sync" : [ "false" ], - "groups.path" : [ "/" ] + "group.object.classes" : [ "groupOfNames" ], + "groups.path" : [ "/" ], + "drop.non.existing.groups.during.sync" : [ "false" ] } }, { "id" : "b6ff3285-35af-4e86-8bb4-d94b8e0d70bb", @@ -2253,8 +2253,8 @@ "config" : { "ldap.attribute" : [ "modifyTimestamp" ], "is.mandatory.in.ldap" : [ "false" ], - "always.read.value.from.ldap" : [ "true" ], "read.only" : [ "true" ], + "always.read.value.from.ldap" : [ "true" ], "user.model.attribute" : [ "modifyTimestamp" ] } }, { @@ -2277,21 +2277,21 @@ "fullSyncPeriod" : [ "-1" ], "pagination" : [ "false" ], "startTls" : [ "false" ], - "connectionPooling" : [ "true" ], "usersDn" : [ "ou=users,dc=dbrepo,dc=at" ], + "connectionPooling" : [ "true" ], "cachePolicy" : [ "DEFAULT" ], "useKerberosForPasswordAuthentication" : [ "false" ], "importEnabled" : [ "true" ], "enabled" : [ "true" ], - "changedSyncPeriod" : [ "-1" ], - "usernameLDAPAttribute" : [ "uid" ], "bindDn" : [ "cn=admin,dc=dbrepo,dc=at" ], "bindCredential" : [ "admin" ], + "usernameLDAPAttribute" : [ "uid" ], + "changedSyncPeriod" : [ "-1" ], "lastSync" : [ "1719252666" ], "vendor" : [ "other" ], "uuidLDAPAttribute" : [ "entryUUID" ], - "allowKerberosAuthentication" : [ "false" ], "connectionUrl" : [ "ldap://identity-service:1389" ], + "allowKerberosAuthentication" : [ "false" ], "syncRegistrations" : [ "true" ], "authType" : [ "simple" ], "useTruststoreSpi" : [ "always" ], diff --git a/dbrepo-metadata-db/1_setup-schema.sql b/dbrepo-metadata-db/1_setup-schema.sql index f83d7d68964c5400a14542683f6866e69a02362b..47ee3a95e2b88a62d4a2405f9c0f4d088167d748 100644 --- a/dbrepo-metadata-db/1_setup-schema.sql +++ b/dbrepo-metadata-db/1_setup-schema.sql @@ -27,10 +27,12 @@ CREATE TABLE IF NOT EXISTS `mdb_images` dialect character varying(255) NOT NULL, driver_class character varying(255) NOT NULL, jdbc_method character varying(255) NOT NULL, + is_default BOOLEAN NOT NULL DEFAULT FALSE, created timestamp NOT NULL DEFAULT NOW(), last_modified timestamp, PRIMARY KEY (id), - UNIQUE (name, version) + UNIQUE (name, version), + UNIQUE (is_default) ) WITH SYSTEM VERSIONING; CREATE TABLE IF NOT EXISTS `mdb_images_date` diff --git a/dbrepo-metadata-db/2_setup-data.sql b/dbrepo-metadata-db/2_setup-data.sql index 24e587fc50cb9beb6363c6bc562c7120a9d9a714..e806e1e181dbdcc3f0e4e29f837bffac7123317c 100644 --- a/dbrepo-metadata-db/2_setup-data.sql +++ b/dbrepo-metadata-db/2_setup-data.sql @@ -2,7 +2,7 @@ BEGIN; INSERT INTO `mdb_containers` (name, internal_name, image_id, host, port, ui_host, ui_port, sidecar_host, sidecar_port, privileged_username, privileged_password) -VALUES ('MariaDB 11.1.3', 'mariadb_11_1_3', 1, 'data-db', 3306, 'localhost', 3306, 'data-db-sidecar', 8080, +VALUES ('mariadb:11.1.3-debian-11-r6', 'mariadb_11_1_3', 1, 'data-db', 3306, 'localhost', 3306, 'data-db-sidecar', 8080, 'root', 'dbrepo'); COMMIT; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageBriefDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageBriefDto.java index e336f3d47a9444aace3e2c66acffe825c1bae128..38adbd6f0d6592a0e802d2bf33147916bbd9f139 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageBriefDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageBriefDto.java @@ -32,4 +32,9 @@ public class ImageBriefDto { @Schema(example = "mariadb") private String jdbcMethod; + @NotNull + @JsonProperty("default") + @Schema(example = "false") + private Boolean isDefault; + } diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageDto.java index 3d766e3abae3379636e6c541d094a89f354dfce3..c0cf7f3bceebc8aefa73c267e422d0cb7e9fa3d0 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageDto.java @@ -50,6 +50,11 @@ public class ImageDto { @Schema(example = "mariadb") private String jdbcMethod; + @NotNull + @JsonProperty("default") + @Schema(example = "false") + private Boolean isDefault; + @NotNull @JsonProperty("default_port") @Schema(example = "3306") diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/container/image/ContainerImage.java b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/container/image/ContainerImage.java index 568e16e4749c810ef8eae67872d4b2be9e29ddf3..78510d51c268967c846ff81fb772409d610c797e 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/container/image/ContainerImage.java +++ b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/container/image/ContainerImage.java @@ -5,8 +5,6 @@ import com.fasterxml.jackson.annotation.JsonFormat; import jakarta.persistence.*; import lombok.*; import org.hibernate.annotations.GenericGenerator; -import org.hibernate.annotations.OnDelete; -import org.hibernate.annotations.OnDeleteAction; import org.springframework.data.annotation.CreatedDate; import org.springframework.data.annotation.LastModifiedDate; import org.springframework.data.jpa.domain.support.AuditingEntityListener; @@ -56,6 +54,9 @@ public class ContainerImage { @Column(nullable = false) private Integer defaultPort; + @Column(nullable = false, columnDefinition = "BOOLEAN DEFAULT FALSE") + private Boolean isDefault = false; + @OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.ALL, CascadeType.PERSIST}, mappedBy = "image") private List<ContainerImageDate> dateFormats; diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/init/InitHandler.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/init/InitHandler.java deleted file mode 100644 index 1f7c8ced0a84bf4dc37f41b36b46408a68aa42df..0000000000000000000000000000000000000000 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/init/InitHandler.java +++ /dev/null @@ -1,59 +0,0 @@ -package at.tuwien.init; - -import at.tuwien.api.keycloak.UserDto; -import at.tuwien.config.GatewayConfig; -import at.tuwien.config.MetadataConfig; -import at.tuwien.entities.user.User; -import at.tuwien.exception.AuthServiceConnectionException; -import at.tuwien.exception.AuthServiceException; -import at.tuwien.exception.UserNotFoundException; -import at.tuwien.gateway.KeycloakGateway; -import at.tuwien.repository.UserRepository; -import at.tuwien.service.UserService; -import jakarta.annotation.PostConstruct; -import lombok.extern.log4j.Log4j2; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Profile; -import org.springframework.stereotype.Component; - -@Log4j2 -@Component -@Profile("!junit") -public class InitHandler { - - private final UserService userService; - private final GatewayConfig gatewayConfig; - private final MetadataConfig metadataConfig; - private final UserRepository userRepository; - private final KeycloakGateway keycloakGateway; - - @Autowired - public InitHandler(UserService userService, GatewayConfig gatewayConfig, MetadataConfig metadataConfig, - UserRepository userRepository, KeycloakGateway keycloakGateway) { - this.userService = userService; - this.gatewayConfig = gatewayConfig; - this.metadataConfig = metadataConfig; - this.userRepository = userRepository; - this.keycloakGateway = keycloakGateway; - } - - @PostConstruct - public void init() throws UserNotFoundException, AuthServiceException, AuthServiceConnectionException { - try { - userService.findByUsername(gatewayConfig.getSystemUsername()); - } catch (UserNotFoundException e) { - log.warn("Failed to find system user with username {} in metadata database", gatewayConfig.getSystemUsername()); - final UserDto user = keycloakGateway.findByUsername(gatewayConfig.getSystemUsername()); - final User entity = User.builder() - .id(user.getId()) - .username(user.getUsername()) - .email(metadataConfig.getAdminEmail()) - .theme("light") - .mariadbPassword(userService.getMariaDbPassword(gatewayConfig.getSystemPassword())) - .language("en") - .build(); - userRepository.save(entity); - log.info("Saved system user with username: {}", gatewayConfig.getSystemUsername()); - } - } -} diff --git a/dbrepo-ui/components/container/ContainerCard.vue b/dbrepo-ui/components/container/ContainerCard.vue index f10e6c27834fcea0d82e0a39440bb7bea9ea78e7..b2937cf6b4fb7f1a243056ea52ccd4649e205772 100644 --- a/dbrepo-ui/components/container/ContainerCard.vue +++ b/dbrepo-ui/components/container/ContainerCard.vue @@ -6,7 +6,7 @@ <v-divider class="mx-4" /> <v-card-title v-text="container.name" /> - <v-card-subtitle>Container</v-card-subtitle> + <v-card-subtitle v-text="$t('pages.container.subtitle.text')" /> <v-card-text> <v-progress-linear v-model="utilization" diff --git a/dbrepo-ui/components/database/DatabaseCreate.vue b/dbrepo-ui/components/database/DatabaseCreate.vue index 1ae15aa766b57bd7fa3c3fb81f1669cfeac59259..8d909b4da350c1cbc10dfad7d595799aa3adee4e 100644 --- a/dbrepo-ui/components/database/DatabaseCreate.vue +++ b/dbrepo-ui/components/database/DatabaseCreate.vue @@ -40,7 +40,17 @@ item-value="id" :rules="[v => !!v || $t('validation.required')]" return-object - required /> + required> + <template + v-slot:selection> + <span>{{ engine.name }}</span> + </template> + <template + v-if="engine" + v-slot:details> + {{ $t('pages.database.subpages.create.utilization.label') }} {{ engine.count }}/{{ engine.quota }} + </template> + </v-select> </v-col> </v-row> </v-card-text> @@ -106,7 +116,13 @@ export default { this.loadingContainers = true containerService.findAll() .then((containers) => { - this.engines = containers.filter(c => c.count < c.quota) + const freeContainers = containers.filter(c => c.count < c.quota) + const defaultContainers = freeContainers.filter(c => c.image.default) + defaultContainers.sort(this.compareContainerUtilization) + this.engines = defaultContainers + const other = freeContainers.filter(c => !c.image.default) + other.sort(this.compareContainerUtilization) + other.forEach(c => this.engines.push(c)) if (this.engines.length > 0) { this.engine = this.engines[0] } @@ -139,6 +155,9 @@ export default { toast.error(this.$t(code)) }) }, + compareContainerUtilization (container, other) { + return Math.round(container.count / container.quota) < Math.round(other.count / other.quota) + }, notEmpty } } diff --git a/dbrepo-ui/layouts/default.vue b/dbrepo-ui/layouts/default.vue index 2c11a99e78fca08bec4b0b67f4724419fcc5403d..fef6700c4f95024619ae0563533a9a42fd3425a7 100644 --- a/dbrepo-ui/layouts/default.vue +++ b/dbrepo-ui/layouts/default.vue @@ -38,7 +38,7 @@ <v-list-item v-if="canListContainers" to="/container" - prepend-icon="mdi-docker" + prepend-icon="mdi-database-settings" :title="$t('navigation.container')" /> </v-list> <template v-slot:append> diff --git a/dbrepo-ui/locales/en-US.json b/dbrepo-ui/locales/en-US.json index 809a65289ab072294aaa50b5b0fea6f93158cd14..847bf3652b8c507b1a6be7b9e1553b2cd5dfb91c 100644 --- a/dbrepo-ui/locales/en-US.json +++ b/dbrepo-ui/locales/en-US.json @@ -2,7 +2,7 @@ "navigation": { "information": "Information", "search": "Search", - "container": "Containers", + "container": "Engines", "ontologies": "Ontologies", "logout": "Logout", "login": "Login", @@ -642,6 +642,9 @@ }, "submit": { "text": "Create" + }, + "utilization": { + "label": "Utilization" } }, "tables": { @@ -1034,10 +1037,13 @@ } }, "container": { - "title": "Containers", + "title": "Engines", "name": { "title": "Name" }, + "subtitle": { + "text": "Engine" + }, "internal-name": { "title": "Internal Name" }, diff --git a/docker-compose.yml b/docker-compose.yml index 96fb14f99510d4be52433188cf1b38b04f6228b6..9fcad8c366fe46d31ad22f381c686afc0d27badb 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,8 @@ volumes: metadata-db-data: data-db-data: + data2-db-data: + data3-db-data: auth-db-data: broker-service-data: upload-service-data: @@ -51,6 +53,42 @@ services: logging: driver: json-file + dbrepo-data2-db: + restart: "no" + container_name: dbrepo-data2-db + hostname: data2-db + image: docker.io/bitnami/mariadb:10.5.26-debian-12-r2 + volumes: + - data2-db-data:/bitnami/mariadb + - "${SHARED_VOLUME:-/tmp}:/tmp" + environment: + MARIADB_ROOT_PASSWORD: "${DATA_DB_PASSWORD:-dbrepo}" + healthcheck: + test: mysqladmin ping --user=root --password="${DATA_DB_PASSWORD:-dbrepo}" --silent + interval: 10s + timeout: 5s + retries: 12 + logging: + driver: json-file + + dbrepo-data3-db: + restart: "no" + container_name: dbrepo-data3-db + hostname: data3-db + image: docker.io/bitnami/mariadb:11.4.3-debian-12-r1 + volumes: + - data3-db-data:/bitnami/mariadb + - "${SHARED_VOLUME:-/tmp}:/tmp" + environment: + MARIADB_ROOT_PASSWORD: "${DATA_DB_PASSWORD:-dbrepo}" + healthcheck: + test: mysqladmin ping --user=root --password="${DATA_DB_PASSWORD:-dbrepo}" --silent + interval: 10s + timeout: 5s + retries: 12 + logging: + driver: json-file + dbrepo-auth-db: restart: "no" container_name: dbrepo-auth-db