-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[PLAT-16399]: Add support for PG-15 upgrades on dedicated VM node uni…
…verses Summary: - Upgrading PG-11 YB_DB builds to PG-15 requires a catalog upgrade, which involves backing up the old catalog from PG-11 and restoring it to the new PG-15 postgres. - During the upgrade, the database spins up a new PG-15 postgres on a master node. If the old postgres exists on the same node, it connects to it to perform the backup and restore. - For universes with authentication enabled, the DB uses a local socket file to connect to the old postgres. However, if the PG-11 postgres is running on a different node, a password is required for authentication. Since YBA does not store the yb-db user password, a temporary superuser (yugabyte_upgrade) is created, and its password is stored in .pgPass on the master node. This allows the new postgres to connect to the old postgres on a different machine. - The temporary superuser is valid for only 4 hours and is used exclusively for the YSQL major catalog upgrade. It is created before master upgrades, and its password is deleted after the catalog upgrade completes. The user can only be removed after finalization or rollback, as DDLs are blocked during the upgrade. - In case of failure, the password file is deleted, except during platform restarts. However, if the user re-triggers the upgrade, the file will be deleted immediately. - Currently, upgrades on dedicated node universes are not retriable. This will be addressed in a follow-up task: PLAT-16502. **Additional Changes:** - Modified the sequence of enabling pushdown (gflag upgrade) to occur as the final step during upgrade finalization as advised by the DB team. Test Plan: - Manually tested upgrade, rollback, and finalize-upgrade processes on both auth-enabled and non-auth-enabled dedicated node universes. - Verified that passwords are not logged and are deleted after finalizing or rolling back the upgrade. - Confirmed that the password file is removed once the upgrade task is completed or fails. Reviewers: #yba-api-review, sneelakantan, sanketh, anijhawan Reviewed By: #yba-api-review, sanketh Subscribers: yugaware Differential Revision: https://phorge.dev.yugabyte.com/D41478
- Loading branch information
Showing
11 changed files
with
278 additions
and
54 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
125 changes: 125 additions & 0 deletions
125
.../main/java/com/yugabyte/yw/commissioner/tasks/subtasks/ManageCatalogUpgradeSuperUser.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
// Copyright (c) YugaByte, Inc. | ||
|
||
package com.yugabyte.yw.commissioner.tasks.subtasks; | ||
|
||
import com.google.common.collect.ImmutableList; | ||
import com.google.common.collect.ImmutableMap; | ||
import com.google.inject.Inject; | ||
import com.yugabyte.yw.commissioner.BaseTaskDependencies; | ||
import com.yugabyte.yw.commissioner.tasks.UniverseTaskBase; | ||
import com.yugabyte.yw.common.NodeUniverseManager; | ||
import com.yugabyte.yw.common.ShellProcessContext; | ||
import com.yugabyte.yw.common.Util; | ||
import com.yugabyte.yw.common.YsqlQueryExecutor; | ||
import com.yugabyte.yw.forms.UniverseTaskParams; | ||
import com.yugabyte.yw.models.Universe; | ||
import com.yugabyte.yw.models.helpers.NodeDetails; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.apache.commons.lang3.RandomStringUtils; | ||
|
||
@Slf4j | ||
public class ManageCatalogUpgradeSuperUser extends UniverseTaskBase { | ||
|
||
private final NodeUniverseManager nodeUniverseManager; | ||
private final YsqlQueryExecutor ysqlQueryExecutor; | ||
|
||
private static final String UPGRADE_SUPERUSER = "yugabyte_upgrade"; | ||
|
||
@Inject | ||
protected ManageCatalogUpgradeSuperUser( | ||
BaseTaskDependencies baseTaskDependencies, | ||
NodeUniverseManager nodeUniverseManager, | ||
YsqlQueryExecutor ysqlQueryExecutor) { | ||
super(baseTaskDependencies); | ||
this.nodeUniverseManager = nodeUniverseManager; | ||
this.ysqlQueryExecutor = ysqlQueryExecutor; | ||
} | ||
|
||
public enum Action { | ||
CREATE_USER, | ||
DELETE_USER, | ||
DELETE_PG_PASS_FILE | ||
} | ||
|
||
public static class Params extends UniverseTaskParams { | ||
public Action action; | ||
} | ||
|
||
public Params taskParams() { | ||
return (Params) taskParams; | ||
} | ||
|
||
@Override | ||
public void run() { | ||
Universe universe = getUniverse(); | ||
NodeDetails masterLeaderNode = universe.getMasterLeaderNode(); | ||
String pgPassFilePath = | ||
Util.getNodeHomeDir(universe.getUniverseUUID(), universe.getMasterLeaderNode()) | ||
+ "/.pgpass"; | ||
if (taskParams().action == Action.CREATE_USER) { | ||
dropUser(universe, masterLeaderNode, pgPassFilePath); | ||
deletePGPassFile(universe, masterLeaderNode, pgPassFilePath); | ||
createUser(universe, masterLeaderNode, pgPassFilePath); | ||
} else if (taskParams().action == Action.DELETE_USER) { | ||
dropUser(universe, masterLeaderNode, pgPassFilePath); | ||
deletePGPassFile(universe, masterLeaderNode, pgPassFilePath); | ||
} else if (taskParams().action == Action.DELETE_PG_PASS_FILE) { | ||
deletePGPassFile(universe, masterLeaderNode, pgPassFilePath); | ||
} | ||
} | ||
|
||
private void dropUser(Universe universe, NodeDetails node, String pgPassFilePath) { | ||
ysqlQueryExecutor.runUserDbCommands( | ||
"DROP USER IF EXISTS " + UPGRADE_SUPERUSER, "template1", universe); | ||
} | ||
|
||
private void deletePGPassFile(Universe universe, NodeDetails node, String pgPassFilePath) { | ||
nodeUniverseManager.runCommand(node, universe, ImmutableList.of("rm", "-f", pgPassFilePath)); | ||
} | ||
|
||
private void createUser(Universe universe, NodeDetails node, String pgPassFilePath) { | ||
String allowedCharsInPassword = | ||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; | ||
for (String charString : Util.SPECIAL_CHARACTERS_STRING_LIST) { | ||
// Avoid using % in the password. | ||
if (!charString.equals("%")) { | ||
allowedCharsInPassword += charString; | ||
} | ||
} | ||
String password = RandomStringUtils.secureStrong().next(20, allowedCharsInPassword); | ||
String query = | ||
String.format( | ||
""" | ||
DO $$DECLARE time TIMESTAMP := now() + INTERVAL '4 HOURS'; | ||
BEGIN | ||
EXECUTE format('CREATE ROLE %s WITH SUPERUSER LOGIN PASSWORD ''%s'' VALID UNTIL ''%s'';', time); | ||
END$$; | ||
""", | ||
UPGRADE_SUPERUSER, password, "%s"); | ||
ysqlQueryExecutor.runUserDbCommands(query, "template1", universe); | ||
String pgPassFileContent = "*:*:*:" + UPGRADE_SUPERUSER + ":" + password; | ||
ShellProcessContext context = | ||
ShellProcessContext.builder() | ||
.logCmdOutput(false) | ||
.redactedVals( | ||
ImmutableMap.of(pgPassFileContent, "*:*:*:REDACTED_USERNAME:REDACTED_PASSWORD")) | ||
.build(); | ||
nodeUniverseManager.runCommand( | ||
node, | ||
universe, | ||
ImmutableList.of( | ||
"rm", | ||
"-rf", | ||
pgPassFilePath, | ||
";", | ||
"echo", | ||
pgPassFileContent, | ||
">>", | ||
pgPassFilePath, | ||
";", | ||
"chmod", | ||
"600", | ||
pgPassFilePath), | ||
context); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.