Merge pull request #1313 from akhilmhdh/feat/migration-mode

feat(infisical-pg): added migration mode env and page
This commit is contained in:
Maidul Islam
2024-01-27 00:58:58 -05:00
committed by GitHub
8 changed files with 57 additions and 12 deletions
+3
View File
@@ -6,6 +6,9 @@ export const client = new InfisicalClient({
token: process.env.INFISICAL_TOKEN! token: process.env.INFISICAL_TOKEN!
}); });
export const getIsMigrationMode = async () =>
(await client.getSecret("MIGRATION_MODE")).secretValue === "true";
export const getPort = async () => (await client.getSecret("PORT")).secretValue || 4000; export const getPort = async () => (await client.getSecret("PORT")).secretValue || 4000;
export const getEncryptionKey = async () => { export const getEncryptionKey = async () => {
const secretValue = (await client.getSecret("ENCRYPTION_KEY")).secretValue; const secretValue = (await client.getSecret("ENCRYPTION_KEY")).secretValue;
+3 -3
View File
@@ -3,11 +3,11 @@ import { IServerConfig, ServerConfig } from "../models/serverConfig";
let serverConfig: IServerConfig; let serverConfig: IServerConfig;
export const serverConfigInit = async () => { export const serverConfigInit = async () => {
const cfg = await ServerConfig.findOne({}); const cfg = await ServerConfig.findOne({}).lean();
if (!cfg) { if (!cfg) {
const cfg = new ServerConfig(); const cfg = new ServerConfig();
await cfg.save(); await cfg.save();
serverConfig = cfg; serverConfig = cfg.toObject();
} else { } else {
serverConfig = cfg; serverConfig = cfg;
} }
@@ -19,6 +19,6 @@ export const getServerConfig = () => serverConfig;
export const updateServerConfig = async (data: Partial<IServerConfig>) => { export const updateServerConfig = async (data: Partial<IServerConfig>) => {
const cfg = await ServerConfig.findByIdAndUpdate(serverConfig._id, data, { new: true }); const cfg = await ServerConfig.findByIdAndUpdate(serverConfig._id, data, { new: true });
if (!cfg) throw new Error("Failed to update server config"); if (!cfg) throw new Error("Failed to update server config");
serverConfig = cfg; serverConfig = cfg.toObject();
return serverConfig; return serverConfig;
}; };
@@ -1,5 +1,5 @@
import { Request, Response } from "express"; import { Request, Response } from "express";
import { getHttpsEnabled } from "../../config"; import { getHttpsEnabled, getIsMigrationMode } from "../../config";
import { getServerConfig, updateServerConfig as setServerConfig } from "../../config/serverConfig"; import { getServerConfig, updateServerConfig as setServerConfig } from "../../config/serverConfig";
import { initializeDefaultOrg, issueAuthTokens } from "../../helpers"; import { initializeDefaultOrg, issueAuthTokens } from "../../helpers";
import { validateRequest } from "../../helpers/validation"; import { validateRequest } from "../../helpers/validation";
@@ -8,9 +8,10 @@ import { TelemetryService } from "../../services";
import { BadRequestError, UnauthorizedRequestError } from "../../utils/errors"; import { BadRequestError, UnauthorizedRequestError } from "../../utils/errors";
import * as reqValidator from "../../validation/admin"; import * as reqValidator from "../../validation/admin";
export const getServerConfigInfo = (_req: Request, res: Response) => { export const getServerConfigInfo = async (_req: Request, res: Response) => {
const config = getServerConfig(); const config = getServerConfig();
return res.send({ config }); const isMigrationModeOn = await getIsMigrationMode();
return res.send({ config: { ...config, isMigrationModeOn } });
}; };
export const updateServerConfig = async (req: Request, res: Response) => { export const updateServerConfig = async (req: Request, res: Response) => {
+15 -2
View File
@@ -83,6 +83,7 @@ import { healthCheck } from "./routes/status";
import { RouteNotFoundError } from "./utils/errors"; import { RouteNotFoundError } from "./utils/errors";
import { requestErrorHandler } from "./middleware/requestErrorHandler"; import { requestErrorHandler } from "./middleware/requestErrorHandler";
import { import {
getIsMigrationMode,
getMongoURL, getMongoURL,
getNodeEnv, getNodeEnv,
getPort, getPort,
@@ -107,8 +108,8 @@ const main = async () => {
const port = await getPort(); const port = await getPort();
// initializing the database connection + redis // initializing the database connection + redis
await initRedis() await initRedis();
await DatabaseService.initDatabase(await getMongoURL()); await DatabaseService.initDatabase(await getMongoURL());
const serverCfg = await serverConfigInit(); const serverCfg = await serverConfigInit();
await setup(); await setup();
@@ -198,6 +199,18 @@ const main = async () => {
handler = nextApp.getRequestHandler(); handler = nextApp.getRequestHandler();
} }
app.use((req, _res, next) => {
getIsMigrationMode()
.then((el) => {
if (el && req.method !== "GET") {
next(new Error("Migration mode"));
} else {
next();
}
})
.catch(next);
});
// (EE) routes // (EE) routes
app.use("/api/v1/identities", v1IdentitiesRouter); app.use("/api/v1/identities", v1IdentitiesRouter);
app.use("/api/v1/secret", eeSecretRouter); app.use("/api/v1/secret", eeSecretRouter);
Binary file not shown.

After

Width:  |  Height:  |  Size: 708 KiB

@@ -1,4 +1,5 @@
import { createContext, ReactNode, useContext, useEffect, useMemo } from "react"; import { createContext, ReactNode, useContext, useEffect, useMemo } from "react";
import Head from "next/head";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { ContentLoader } from "@app/components/v2/ContentLoader"; import { ContentLoader } from "@app/components/v2/ContentLoader";
@@ -27,11 +28,37 @@ export const ServerConfigProvider = ({ children }: Props): JSX.Element => {
}, [data]); }, [data]);
useEffect(() => { useEffect(() => {
if (!isLoading && data && !data.initialized) { if (!isLoading && data && !data.initialized && !data.isMigrationModeOn) {
router.push("/admin/signup"); router.push("/admin/signup");
} }
}, [isLoading, data]); }, [isLoading, data]);
if (!isLoading && data?.isMigrationModeOn) {
return (
<div className="relative mx-auto flex h-screen w-full flex-col items-center justify-center space-y-8 bg-bunker-800 px-8 text-mineshaft-50 dark:[color-scheme:dark]">
<Head>
<title>Infisical Maintenance Mode</title>
<link rel='icon' href='/infisical.ico' />
</Head>
<img src="/images/maintenance.png" height={175} width={300} alt="maintenance mode" className="w-[40rem]"/>
<p className="mx-8 mb-4 flex justify-center bg-gradient-to-tr from-mineshaft-300 to-white bg-clip-text text-4xl font-bold text-transparent md:mx-16">
Scheduled Maintenance
</p>
<div className="mt-2 text-center text-lg text-bunker-300">
Infisical is undergoing planned maintenance. <br /> No action is required on your end — your applications will continue to fetch secrets.
<br /> If you have questions, please <a
className="text-bunker-300 underline underline-offset-4 decoration-primary-800 hover:decoration-primary-600 hover:text-mineshaft-100 duration-200"
href="https://infisical.com/slack"
target="_blank"
rel="noopener noreferrer"
>
join our Slack community
</a>.
</div>
</div>
);
}
if (isLoading || (!data?.initialized && router.pathname !== "/admin/signup")) { if (isLoading || (!data?.initialized && router.pathname !== "/admin/signup")) {
return ( return (
<div className="bg-bunker-800"> <div className="bg-bunker-800">
+1
View File
@@ -1,6 +1,7 @@
export type TServerConfig = { export type TServerConfig = {
initialized: boolean; initialized: boolean;
allowSignUp: boolean; allowSignUp: boolean;
isMigrationModeOn?: boolean;
}; };
export type TCreateAdminUserDTO = { export type TCreateAdminUserDTO = {
@@ -61,7 +61,7 @@ export const SignUpPage = () => {
router.push("/login"); router.push("/login");
} }
} }
}, []); }, [config?.initialized]);
const { mutateAsync: createAdminUser } = useCreateAdminUser(); const { mutateAsync: createAdminUser } = useCreateAdminUser();
@@ -117,7 +117,7 @@ export const SignUpPage = () => {
return <ContentLoader text="Redirecting to admin page..." />; return <ContentLoader text="Redirecting to admin page..." />;
return ( return (
<div className="flex justify-center items-center"> <div className="flex items-center justify-center">
<AnimatePresence exitBeforeEnter> <AnimatePresence exitBeforeEnter>
{step === SignupSteps.DetailsForm && ( {step === SignupSteps.DetailsForm && (
<motion.div <motion.div
@@ -128,7 +128,7 @@ export const SignUpPage = () => {
animate={{ opacity: 1, translateX: 0 }} animate={{ opacity: 1, translateX: 0 }}
exit={{ opacity: 0, translateX: 30 }} exit={{ opacity: 0, translateX: 30 }}
> >
<div className="text-center flex flex-col items-center space-y-4"> <div className="flex flex-col items-center space-y-4 text-center">
<img src="/images/gradientLogo.svg" height={90} width={120} alt="Infisical logo" /> <img src="/images/gradientLogo.svg" height={90} width={120} alt="Infisical logo" />
<div className="text-4xl">Welcome to Infisical</div> <div className="text-4xl">Welcome to Infisical</div>
<div>Create your first Admin Account</div> <div>Create your first Admin Account</div>