-
Notifications
You must be signed in to change notification settings - Fork 235
[JDBC] [DO NOT REVIEW] Support multiple Quarkus datasources #1482
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
9de9f51
879378e
5c62e85
f2fa9b5
14ceabd
80304c3
6432732
32bb4b9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
/* | ||
* Licensed to the Apache Software Foundation (ASF) under one | ||
* or more contributor license agreements. See the NOTICE file | ||
* distributed with this work for additional information | ||
* regarding copyright ownership. The ASF licenses this file | ||
* to you under the Apache License, Version 2.0 (the | ||
* "License"); you may not use this file except in compliance | ||
* with the License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, | ||
* software distributed under the License is distributed on an | ||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
* KIND, either express or implied. See the License for the | ||
* specific language governing permissions and limitations | ||
* under the License. | ||
*/ | ||
package org.apache.polaris.core.persistence; | ||
|
||
import javax.sql.DataSource; | ||
|
||
public interface DatasourceSupplier { | ||
DataSource fromRealmId(String realmId); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -50,3 +50,21 @@ quarkus.index-dependency.guava.artifact-id=guava | |
quarkus.index-dependency.protobuf.group-id=com.google.protobuf | ||
quarkus.index-dependency.protobuf.artifact-id=protobuf-java | ||
quarkus.datasource.devservices.image-name=postgres:17-alpine | ||
|
||
#quarkus.datasource.db-kind=pgsql | ||
#quarkus.datasource.jdbc.url=polaris | ||
#quarkus.datasource.username=polaris | ||
#quarkus.datasource.password=polaris | ||
quarkus.datasource.\"realm1_ds\".db-kind=pgsql | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm still not sure why we need the multitude of test-like datasource configs in the production sections of the admin tool properties 🤔 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. not sure whats happening but here is the reason behind : #1482 (comment) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The problem here is that for a Datasource to be created by Quarkus, there has to be at least one build-time property defined for that datasource: And you cannot pass build-time properties through So Thus for tests you have to declare the datasources you intend to use here, along with their db-kind: quarkus.datasource.\"realm1_ds\".db-kind=pgsql
quarkus.datasource.\"realm2_ds\".db-kind=pgsql
quarkus.datasource.\"realm3_ds\".db-kind=pgsql
# etc Other runtime properties, like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If I'm surprised this is required, because the default datasource does not have to be defined at build time, if I'm not mistaken. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
See https://quarkus.io/guides/datasource#configure-multiple-datasources:
This is why I asked this question, I think there is some misunderstanding going on: #1482 (comment)
The default datasource is treated slightly different: if But that doesn't help here, since the intent is to use many named datasources. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. from my POV, it might be fine to support one Data Source (co-located realms) out-of-the-box and instruct users to use custom builds if they want to segregate realms by Data Source (experience similar to EclipseLink). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not configure those DS using a quarkus-test-profile? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @snazy we can't as we need atleast one build time prop please ref this comment from @adutra #1482 (comment) I tried overriding them by quarkus-test-profiles but the override is not able to create named DS There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @singhpk234 : This PR accumulated a lot of comments, some of them about non-trivial issues... Would you mind making a dev email with a summary and options for moving forward? I guess it would be clearer than continuing on GH. Once we have a consensus on how to proceed we can revamp this PR. WDYT? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sounds fair ! its on my list, should be sending out an email soon, meanwhile marking this PR as draft to not draw more attention, |
||
quarkus.datasource.\"realm1_ds\".jdbc.url=polaris | ||
quarkus.datasource.\"realm1_ds\".username=polaris | ||
quarkus.datasource.\"realm1_ds\".password=polaris | ||
quarkus.datasource.\"realm2_ds\".db-kind=pgsql | ||
quarkus.datasource.\"realm2_ds\".jdbc.url=polaris | ||
quarkus.datasource.\"realm2_ds\".username=polaris | ||
quarkus.datasource.\"realm2_ds\".password=polaris | ||
quarkus.datasource.\"realm3_ds\".db-kind=pgsql | ||
quarkus.datasource.\"realm3_ds\".jdbc.url=polaris | ||
quarkus.datasource.\"realm3_ds\".username=polaris | ||
quarkus.datasource.\"realm3_ds\".password=polaris | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
/* | ||
* Licensed to the Apache Software Foundation (ASF) under one | ||
* or more contributor license agreements. See the NOTICE file | ||
* distributed with this work for additional information | ||
* regarding copyright ownership. The ASF licenses this file | ||
* to you under the Apache License, Version 2.0 (the | ||
* "License"); you may not use this file except in compliance | ||
* with the License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, | ||
* software distributed under the License is distributed on an | ||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
* KIND, either express or implied. See the License for the | ||
* specific language governing permissions and limitations | ||
* under the License. | ||
*/ | ||
|
||
-- Create two more databases for testing. The first database, polaris_realm1, is created | ||
-- during container initialization. See PostgresTestResourceLifecycleManager. | ||
|
||
-- Note: the database names must follow the pattern polaris_{realm}. That's the pattern | ||
-- specified by the persistence.xml file used in tests. | ||
|
||
CREATE DATABASE realm2; | ||
GRANT ALL PRIVILEGES ON DATABASE realm2 TO polaris; | ||
|
||
CREATE DATABASE realm3; | ||
GRANT ALL PRIVILEGES ON DATABASE realm3 TO polaris; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
/* | ||
* Licensed to the Apache Software Foundation (ASF) under one | ||
* or more contributor license agreements. See the NOTICE file | ||
* distributed with this work for additional information | ||
* regarding copyright ownership. The ASF licenses this file | ||
* to you under the Apache License, Version 2.0 (the | ||
* "License"); you may not use this file except in compliance | ||
* with the License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, | ||
* software distributed under the License is distributed on an | ||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
* KIND, either express or implied. See the License for the | ||
* specific language governing permissions and limitations | ||
* under the License. | ||
*/ | ||
|
||
plugins { | ||
alias(libs.plugins.jandex) | ||
id("java-test-fixtures") | ||
} | ||
|
||
configurations.all { | ||
exclude(group = "org.antlr", module = "antlr4-runtime") | ||
exclude(group = "org.scala-lang", module = "scala-library") | ||
exclude(group = "org.scala-lang", module = "scala-reflect") | ||
} | ||
|
||
java { | ||
sourceCompatibility = JavaVersion.VERSION_21 | ||
targetCompatibility = JavaVersion.VERSION_21 | ||
} | ||
|
||
dependencies { | ||
implementation(project(":polaris-core")) | ||
implementation(project(":polaris-relational-jdbc")) | ||
|
||
compileOnly(libs.smallrye.config.core) // @ConfigMap | ||
implementation(enforcedPlatform(libs.quarkus.bom)) | ||
implementation("io.quarkus:quarkus-arc") | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
/* | ||
* Licensed to the Apache Software Foundation (ASF) under one | ||
* or more contributor license agreements. See the NOTICE file | ||
* distributed with this work for additional information | ||
* regarding copyright ownership. The ASF licenses this file | ||
* to you under the Apache License, Version 2.0 (the | ||
* "License"); you may not use this file except in compliance | ||
* with the License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, | ||
* software distributed under the License is distributed on an | ||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
* KIND, either express or implied. See the License for the | ||
* specific language governing permissions and limitations | ||
* under the License. | ||
*/ | ||
package org.apache.polaris.common; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Common for everything? |
||
|
||
import io.quarkus.arc.All; | ||
import io.quarkus.arc.InstanceHandle; | ||
import java.util.List; | ||
import javax.sql.DataSource; | ||
|
||
import jakarta.enterprise.context.ApplicationScoped; | ||
import jakarta.inject.Inject; | ||
import org.apache.polaris.core.persistence.DatasourceSupplier; | ||
|
||
@ApplicationScoped | ||
public class QuarkusDatasourceSupplier implements DatasourceSupplier { | ||
private final List<InstanceHandle<DataSource>> dataSources; | ||
private final RelationalJdbcConfiguration relationalJdbcConfiguration; | ||
|
||
private static final String DEFAULT_DATA_SOURCE_NAME = "default"; | ||
|
||
@Inject | ||
public QuarkusDatasourceSupplier( | ||
RelationalJdbcConfiguration relationalJdbcConfiguration, | ||
@All List<InstanceHandle<DataSource>> dataSources) { | ||
this.relationalJdbcConfiguration = relationalJdbcConfiguration; | ||
this.dataSources = dataSources; | ||
} | ||
|
||
@Override | ||
public DataSource fromRealmId(String realmId) { | ||
// check if the mapping of realm to DS exists, otherwise fall back to default | ||
String dataSourceName = relationalJdbcConfiguration.realms().getOrDefault( | ||
realmId, | ||
relationalJdbcConfiguration.defaultDatasource().orElse(null) | ||
); | ||
|
||
// if neither mapping exists nor default DS exists, fail | ||
if (dataSourceName == null) { | ||
throw new IllegalStateException(String.format( | ||
"No datasource configured with name: %s nor default datasource configured", realmId)); | ||
} | ||
|
||
// check if there is actually a datasource of that dataSourceName | ||
return dataSources.stream() | ||
.filter(ds -> { | ||
String name = ds.getBean().getName(); | ||
name = name == null ? DEFAULT_DATA_SOURCE_NAME : name; | ||
return name.equals(dataSourceName); | ||
}) | ||
.map(InstanceHandle::get) | ||
.findFirst() | ||
.orElseThrow(() -> new IllegalStateException(String.format( | ||
"No datasource configured with name: %s", dataSourceName))); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
/* | ||
* Licensed to the Apache Software Foundation (ASF) under one | ||
* or more contributor license agreements. See the NOTICE file | ||
* distributed with this work for additional information | ||
* regarding copyright ownership. The ASF licenses this file | ||
* to you under the Apache License, Version 2.0 (the | ||
* "License"); you may not use this file except in compliance | ||
* with the License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, | ||
* software distributed under the License is distributed on an | ||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
* KIND, either express or implied. See the License for the | ||
* specific language governing permissions and limitations | ||
* under the License. | ||
*/ | ||
package org.apache.polaris.common; | ||
|
||
import io.smallrye.config.ConfigMapping; | ||
import io.smallrye.config.WithParentName; | ||
|
||
import java.util.Map; | ||
import java.util.Optional; | ||
|
||
@ConfigMapping(prefix = "polaris.relational.jdbc.datasource") | ||
public interface RelationalJdbcConfiguration { | ||
/** realmId to configured Datasource name mapping. */ | ||
@WithParentName | ||
Map<String, String> realms(); | ||
|
||
/** | ||
* Default datasource name to be used for a realmId when there is no mapping of realmId to | ||
* Datasource name present. | ||
*/ | ||
Optional<String> defaultDatasource(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So why not throw an exception in that case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Its like we checked and table didn't exists, so this looks up should not fail but rather say that he nothing is bootstrappped and hence trigger actual bootstrap or purge or something
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would returning
null
help with bootstrapping?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes entity null would mean entity not found and this would prompt bootstrap which inturn would run the bootstrap script. Otherwise RTE here is everything broken, i agree this is not an ideal but this is something we have from persistence we expect EntityResult
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this logic is too obscure IMHO. Would it be preferable to have a dedicated
isRealmBootstrapped(realmId)
method?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about if take this is in my MetaStoreManager refactor ? #1462
I have assigned it to me