-
Notifications
You must be signed in to change notification settings - Fork 13
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
Auto migration using flyway #179
base: 5.0
Are you sure you want to change the base?
Changes from all commits
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,66 @@ | ||
/* | ||
* Copyright (c) 2023, VRAI Labs and/or its affiliates. All rights reserved. | ||
* | ||
* This software is licensed under the Apache License, Version 2.0 (the | ||
* "License") as published by the Apache Software Foundation. | ||
* | ||
* 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 io.supertokens.storage.postgresql; | ||
|
||
import io.supertokens.pluginInterface.exceptions.StorageQueryException; | ||
import io.supertokens.storage.postgresql.config.Config; | ||
import io.supertokens.storage.postgresql.output.Logging; | ||
import io.supertokens.storage.postgresql.queries.BaselineMigrationQueries; | ||
import org.flywaydb.core.Flyway; | ||
import java.sql.SQLException; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
|
||
public final class FlywayMigration { | ||
|
||
private static final String LOCATION = "classpath:/io/supertokens/storage/postgresql/migrations"; | ||
private FlywayMigration() {} | ||
|
||
public static void startMigration(Start start) throws SQLException, StorageQueryException { | ||
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 there are multiple tenants, and each of them are going to run their own migration:
What will the log output look like? How long will the API take for creation of a new tenant? |
||
String baseline = BaselineMigrationQueries.getBaselineMigrationVersion(start); | ||
if (Integer.parseInt(baseline) >= BaselineMigrationQueries.LAST_MIGRATION) { | ||
return; | ||
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 we are going to be running v6, then this will have to run. This can be done by getting the baseline from flyway and checking for that as well. Right now We can solve this by checking if there is a baseline in the db from flyway's side, and if there is, we should also check if that is >= V6 (not BaselineMigrationQueries.LAST_MIGRATION), and if it is, then we should return. |
||
} | ||
|
||
Logging.info(start, "Starting migration.", true); | ||
MigrationContextManager.putContext(start.getProcessId(), start); | ||
int maxRetries = 5; | ||
|
||
try { | ||
Flyway flyway = Flyway.configure() | ||
.dataSource(ConnectionPool.getHikariDataSource(start)) | ||
.baselineOnMigrate(true) | ||
.baselineVersion(baseline) | ||
.table(Config.getConfig(start).getFlywaySchemaHistory()) | ||
.connectRetries(maxRetries) | ||
.lockRetryCount(maxRetries) | ||
.locations(LOCATION) | ||
.placeholders(getPlaceholders(start)) | ||
.load(); | ||
flyway.migrate(); | ||
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.
|
||
} finally { | ||
MigrationContextManager.removeContext(start.getProcessId()); | ||
} | ||
} | ||
|
||
private static Map<String, String> getPlaceholders(Start start) { | ||
Map<String, String> ph = new HashMap<>(); | ||
ph.put("process_id", start.getProcessId()); | ||
ph.put("access_token_signing_key_dynamic", String.valueOf( Config.getConfig(start).getAccessTokenSigningKeyDynamic())); | ||
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. this will have to be bought in from the core. As this config is a core config and not a db plugin config 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. this will be removed in the future cause it would be saved inside the start class. Or some other way... |
||
return ph; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
/* | ||
* Copyright (c) 2024, VRAI Labs and/or its affiliates. All rights reserved. | ||
* | ||
* This software is licensed under the Apache License, Version 2.0 (the | ||
* "License") as published by the Apache Software Foundation. | ||
* | ||
* 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 io.supertokens.storage.postgresql; | ||
|
||
import java.util.Map; | ||
import java.util.concurrent.ConcurrentHashMap; | ||
|
||
public class MigrationContextManager { | ||
private static Map<String, Start> contextMap = new ConcurrentHashMap<>(); | ||
|
||
public static void putContext(String key, Start start) { | ||
contextMap.put(key, start); | ||
} | ||
|
||
public static Start getContext(String key) { | ||
return contextMap.get(key); | ||
} | ||
|
||
public static void removeContext(String key) { | ||
contextMap.remove(key); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -115,6 +115,10 @@ public class PostgreSQLConfig { | |
@IgnoreForAnnotationCheck | ||
boolean isValidAndNormalised = false; | ||
|
||
@JsonProperty | ||
@IgnoreForAnnotationCheck | ||
private boolean access_token_signing_key_dynamic = true; | ||
Comment on lines
+118
to
+120
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. this needs to go away and we need to pass it through the plugin interface |
||
|
||
public static Set<String> getValidFields() { | ||
PostgreSQLConfig config = new PostgreSQLConfig(); | ||
JsonObject configObj = new GsonBuilder().serializeNulls().create().toJsonTree(config).getAsJsonObject(); | ||
|
@@ -234,6 +238,10 @@ public String getThirdPartyUsersTable() { | |
return postgresql_thirdparty_users_table_name; | ||
} | ||
|
||
public boolean getAccessTokenSigningKeyDynamic() { | ||
return access_token_signing_key_dynamic; | ||
} | ||
|
||
public String getThirdPartyUserToTenantTable() { | ||
return addSchemaAndPrefixToTableName("thirdparty_user_to_tenant"); | ||
} | ||
|
@@ -302,6 +310,10 @@ public String getTotpUsedCodesTable() { | |
return addSchemaAndPrefixToTableName("totp_used_codes"); | ||
} | ||
|
||
public String getFlywaySchemaHistory() { | ||
return addSchemaAndPrefixToTableName("flyway_schema_history"); | ||
} | ||
|
||
private String addSchemaAndPrefixToTableName(String tableName) { | ||
return addSchemaToTableName(postgresql_table_names_prefix + tableName); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
/* | ||
* Copyright (c) 2024, VRAI Labs and/or its affiliates. All rights reserved. | ||
* | ||
* This software is licensed under the Apache License, Version 2.0 (the | ||
* "License") as published by the Apache Software Foundation. | ||
* | ||
* 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. | ||
*/ | ||
|
||
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. rename all migration files to be VX__A_B_C.java Where VX is V1, V2 and so on.. and A_B_C is the core version that introduced the new changes |
||
package io.supertokens.storage.postgresql.migrations; | ||
|
||
import io.supertokens.storage.postgresql.MigrationContextManager; | ||
import io.supertokens.storage.postgresql.Start; | ||
import io.supertokens.storage.postgresql.queries.GeneralQueries; | ||
import org.flywaydb.core.api.migration.BaseJavaMigration; | ||
import org.flywaydb.core.api.migration.Context; | ||
|
||
import java.util.Map; | ||
|
||
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. need to confirm all these migrations are correctly specified. How can we confirm this? |
||
|
||
public class V1__init_database extends BaseJavaMigration { | ||
|
||
@Override | ||
public void migrate(Context context) throws Exception { | ||
Map<String, String> ph = context.getConfiguration().getPlaceholders(); | ||
Start start = MigrationContextManager.getContext(ph.get("process_id")); | ||
GeneralQueries.createTablesIfNotExists(start); | ||
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. unlike before, there is no index being created in this step. Is that okay? Need to confirm that all necessary indexes are being created in the later on migration steps. |
||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
/* | ||
* Copyright (c) 2023, VRAI Labs and/or its affiliates. All rights reserved. | ||
* | ||
* This software is licensed under the Apache License, Version 2.0 (the | ||
* "License") as published by the Apache Software Foundation. | ||
* | ||
* 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 io.supertokens.storage.postgresql.migrations; | ||
|
||
import io.supertokens.storage.postgresql.MigrationContextManager; | ||
import io.supertokens.storage.postgresql.Start; | ||
import io.supertokens.storage.postgresql.config.Config; | ||
import org.flywaydb.core.api.migration.BaseJavaMigration; | ||
import org.flywaydb.core.api.migration.Context; | ||
import java.sql.Statement; | ||
import java.util.Map; | ||
|
||
public class V2__plugin_version_3_0_0 extends BaseJavaMigration { | ||
|
||
@Override | ||
public void migrate(Context context) throws Exception { | ||
Map<String, String> ph = context.getConfiguration().getPlaceholders(); | ||
Start start = MigrationContextManager.getContext(ph.get("process_id")); | ||
String sessionInfoTable = Config.getConfig(start).getSessionInfoTable(); | ||
String JWTSigningKeysTable = Config.getConfig(start).getJWTSigningKeysTable(); | ||
String accessTokenSigningKeysTable = Config.getConfig(start).getAccessTokenSigningKeysTable(); | ||
|
||
try (Statement statement = context.getConnection().createStatement()) { | ||
// Add a new column with a default value | ||
statement.execute("ALTER TABLE " + sessionInfoTable + " ADD COLUMN IF NOT EXISTS use_static_key BOOLEAN NOT NULL DEFAULT" + | ||
"(" + !Boolean.parseBoolean(ph.get("access_token_signing_key_dynamic")) + ")"); | ||
// Alter the column to drop the default value | ||
statement.execute("ALTER TABLE " + sessionInfoTable + " ALTER COLUMN " + | ||
"use_static_key DROP DEFAULT"); | ||
|
||
// Insert data into jwt_signing_keys from session_access_token_signing_keys | ||
statement.execute("INSERT INTO " + JWTSigningKeysTable + " (key_id, key_string, algorithm, " + | ||
"created_at) " + | ||
"SELECT CONCAT('s-', created_at_time) as key_id, value as key_string, 'RS256' as algorithm, created_at_time as created_at " + | ||
"FROM " + accessTokenSigningKeysTable); | ||
} | ||
} | ||
} |
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.
add all dependencies of this too