do migration in one transaction with rollback

This commit is contained in:
Milo Schwartz 2025-01-29 19:55:08 -05:00
parent 34c8c0db70
commit bdf72662bf
No known key found for this signature in database
3 changed files with 183 additions and 187 deletions

View file

@ -49,13 +49,20 @@ jobs:
LATEST_TAG=$(curl -s https://api.github.com/repos/fosrl/gerbil/tags | jq -r '.[0].name')
echo "LATEST_GERBIL_TAG=$LATEST_TAG" >> $GITHUB_ENV
- name: Pull latest Badger version
id: get-badger-tag
run: |
LATEST_TAG=$(curl -s https://api.github.com/repos/fosrl/badger/tags | jq -r '.[0].name')
echo "LATEST_BADGER_TAG=$LATEST_TAG" >> $GITHUB_ENV
- name: Update install/main.go
run: |
PANGOLIN_VERSION=${{ env.TAG }}
GERBIL_VERSION=${{ env.LATEST_GERBIL_TAG }}
sed -i "s/config.PangolinVersion = \".*\"/config.PangolinVersion = \"$PANGOLIN_VERSION\"/" install/main.go
sed -i "s/config.GerbilVersion = \".*\"/config.GerbilVersion = \"$GERBIL_VERSION\"/" install/main.go
echo "Updated install/main.go with Pangolin version $PANGOLIN_VERSION and Gerbil version $GERBIL_VERSION"
sed -i "s/config.BadgerVersion = \".*\"/config.BadgerVersion = \"$BADGER_VERSION\"/" install/main.go
echo "Updated install/main.go with Pangolin version $PANGOLIN_VERSION, Gerbil version $GERBIL_VERSION, and Badger version $BADGER_VERSION"
cat install/main.go
- name: Build and push Docker images

View file

@ -21,6 +21,7 @@ import (
func loadVersions(config *Config) {
config.PangolinVersion = "replaceme"
config.GerbilVersion = "replaceme"
// config.BadgerVersion = "replaceme"
}
//go:embed fs/*

View file

@ -20,96 +20,7 @@ import { fromZodError } from "zod-validation-error";
export default async function migration() {
console.log("Running setup script 1.0.0-beta.9...");
try {
await db.transaction(async (trx) => {
trx.run(sql`UPDATE ${users} SET email = LOWER(email);`);
trx.run(
sql`UPDATE ${emailVerificationCodes} SET email = LOWER(email);`
);
trx.run(
sql`UPDATE ${passwordResetTokens} SET email = LOWER(email);`
);
trx.run(sql`UPDATE ${userInvites} SET email = LOWER(email);`);
trx.run(sql`UPDATE ${resourceWhitelist} SET email = LOWER(email);`);
trx.run(sql`UPDATE ${resourceOtp} SET email = LOWER(email);`);
});
} catch (error) {
console.log(
"We were unable to make all emails lower case in the database. You can safely ignore this error."
);
console.error(error);
}
try {
await db.transaction(async (trx) => {
const resourcesAll = await trx.select({
resourceId: resources.resourceId,
fullDomain: resources.fullDomain,
subdomain: resources.subdomain
}).from(resources);
trx.run(`DROP INDEX resources_fullDomain_unique;`)
trx.run(`ALTER TABLE resources
DROP COLUMN fullDomain;
`)
trx.run(`ALTER TABLE resources
DROP COLUMN subdomain;
`)
trx.run(sql`ALTER TABLE resources
ADD COLUMN fullDomain TEXT;
`)
trx.run(sql`ALTER TABLE resources
ADD COLUMN subdomain TEXT;
`)
trx.run(sql`ALTER TABLE resources
ADD COLUMN http INTEGER DEFAULT true NOT NULL;
`)
trx.run(sql`ALTER TABLE resources
ADD COLUMN protocol TEXT DEFAULT 'tcp' NOT NULL;
`)
trx.run(sql`ALTER TABLE resources
ADD COLUMN proxyPort INTEGER;
`)
// write the new fullDomain and subdomain values back to the database
for (const resource of resourcesAll) {
await trx.update(resources).set({
fullDomain: resource.fullDomain,
subdomain: resource.subdomain
}).where(eq(resources.resourceId, resource.resourceId));
}
const targetsAll = await trx.select({
targetId: targets.targetId,
method: targets.method
}).from(targets);
trx.run(`ALTER TABLE targets
DROP COLUMN method;
`)
trx.run(`ALTER TABLE targets
DROP COLUMN protocol;
`)
trx.run(sql`ALTER TABLE targets
ADD COLUMN method TEXT;
`)
// write the new method and protocol values back to the database
for (const target of targetsAll) {
await trx.update(targets).set({
method: target.method
}).where(eq(targets.targetId, target.targetId));
}
});
} catch (error) {
console.log(
"We were unable to make the changes to the targets and resources tables."
);
throw error;
}
try {
// Determine which config file exists
const filePaths = [configFilePath1, configFilePath2];
@ -132,7 +43,8 @@ export default async function migration() {
const fileContents = fs.readFileSync(filePath, "utf8");
rawConfig = yaml.load(fileContents);
rawConfig.server.resource_session_request_param = "p_session_request";
rawConfig.server.resource_session_request_param =
"p_session_request";
rawConfig.server.session_cookie_name = "p_session_token"; // rename to prevent conflicts
delete rawConfig.server.resource_session_cookie_name;
@ -143,7 +55,8 @@ export default async function migration() {
console.log(
`Failed to add resource_session_request_param to config. Please add it manually. https://docs.fossorial.io/Pangolin/Configuration/config`
);
throw e;
trx.rollback();
return;
}
try {
@ -186,10 +99,7 @@ export default async function migration() {
const parsedConfig = schema.safeParse(traefikConfig);
if (!parsedConfig.success) {
throw new Error(fromZodError(parsedConfig.error).toString());
}
if (parsedConfig.success) {
// Ensure websecure entrypoint exists
if (traefikConfig.entryPoints?.websecure) {
// Add transport configuration
@ -200,7 +110,8 @@ export default async function migration() {
};
}
traefikConfig.experimental.plugins.badger.version = "v1.0.0-beta.3";
traefikConfig.experimental.plugins.badger.version =
"v1.0.0-beta.3";
const updatedTraefikYaml = yaml.dump(traefikConfig);
fs.writeFileSync(traefikPath, updatedTraefikYaml, "utf8");
@ -208,15 +119,98 @@ export default async function migration() {
console.log(
"Updated the version of Badger in your Traefik configuration to v1.0.0-beta.3 and added readTimeout to websecure entrypoint in your Traefik configuration.."
);
} else {
console.log(fromZodError(parsedConfig.error));
console.log(
"We were unable to update the version of Badger in your Traefik configuration. Please update it manually to at least v1.0.0-beta.3. https://github.com/fosrl/badger"
);
}
} catch (e) {
console.log(
"We were unable to update the version of Badger in your Traefik configuration. Please update it manually to at least v1.0.0-beta.3. https://github.com/fosrl/badger"
);
throw e;
trx.rollback();
return;
}
trx.run(sql`UPDATE ${users} SET email = LOWER(email);`);
trx.run(
sql`UPDATE ${emailVerificationCodes} SET email = LOWER(email);`
);
trx.run(sql`UPDATE ${passwordResetTokens} SET email = LOWER(email);`);
trx.run(sql`UPDATE ${userInvites} SET email = LOWER(email);`);
trx.run(sql`UPDATE ${resourceWhitelist} SET email = LOWER(email);`);
trx.run(sql`UPDATE ${resourceOtp} SET email = LOWER(email);`);
const resourcesAll = await trx
.select({
resourceId: resources.resourceId,
fullDomain: resources.fullDomain,
subdomain: resources.subdomain
})
.from(resources);
trx.run(`DROP INDEX resources_fullDomain_unique;`);
trx.run(`ALTER TABLE resources
DROP COLUMN fullDomain;
`);
trx.run(`ALTER TABLE resources
DROP COLUMN subdomain;
`);
trx.run(sql`ALTER TABLE resources
ADD COLUMN fullDomain TEXT;
`);
trx.run(sql`ALTER TABLE resources
ADD COLUMN subdomain TEXT;
`);
trx.run(sql`ALTER TABLE resources
ADD COLUMN http INTEGER DEFAULT true NOT NULL;
`);
trx.run(sql`ALTER TABLE resources
ADD COLUMN protocol TEXT DEFAULT 'tcp' NOT NULL;
`);
trx.run(sql`ALTER TABLE resources
ADD COLUMN proxyPort INTEGER;
`);
// write the new fullDomain and subdomain values back to the database
for (const resource of resourcesAll) {
await trx
.update(resources)
.set({
fullDomain: resource.fullDomain,
subdomain: resource.subdomain
})
.where(eq(resources.resourceId, resource.resourceId));
}
const targetsAll = await trx
.select({
targetId: targets.targetId,
method: targets.method
})
.from(targets);
trx.run(`ALTER TABLE targets
DROP COLUMN method;
`);
trx.run(`ALTER TABLE targets
DROP COLUMN protocol;
`);
trx.run(sql`ALTER TABLE targets
ADD COLUMN method TEXT;
`);
// write the new method and protocol values back to the database
for (const target of targetsAll) {
await trx
.update(targets)
.set({
method: target.method
})
.where(eq(targets.targetId, target.targetId));
}
try {
await db.transaction(async (trx) => {
trx.run(
sql`ALTER TABLE 'resourceSessions' ADD 'isRequestToken' integer;`
);
@ -224,12 +218,6 @@ export default async function migration() {
sql`ALTER TABLE 'resourceSessions' ADD 'userSessionId' text REFERENCES session(id);`
);
});
} catch (e) {
console.log(
"We were unable to add columns to the resourceSessions table."
);
throw e;
}
console.log("Done.");
}