-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Deploy infisical instance as a service #3141
base: main
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
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import { Knex } from "knex"; | ||
import { TableName } from "../schemas"; | ||
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils"; | ||
|
||
export async function up(knex: Knex): Promise<void> { | ||
const isTablePresent = await knex.schema.hasTable(TableName.DedicatedInstances); | ||
if (!isTablePresent) { | ||
await knex.schema.createTable(TableName.DedicatedInstances, (t) => { | ||
t.uuid("id").primary().defaultTo(knex.fn.uuid()); | ||
t.uuid("orgId").notNullable(); | ||
t.string("instanceName").notNullable(); | ||
t.string("subdomain").notNullable().unique(); | ||
t.enum("status", ["RUNNING", "UPGRADING", "PROVISIONING", "FAILED"]).notNullable(); | ||
t.string("rdsInstanceType").notNullable(); | ||
t.string("elasticCacheType").notNullable(); | ||
t.integer("elasticContainerMemory").notNullable(); | ||
t.integer("elasticContainerCpu").notNullable(); | ||
t.string("region").notNullable(); | ||
t.string("version").notNullable(); | ||
t.integer("backupRetentionDays").defaultTo(7); | ||
t.timestamp("lastBackupTime").nullable(); | ||
t.timestamp("lastUpgradeTime").nullable(); | ||
t.boolean("publiclyAccessible").defaultTo(false); | ||
t.string("vpcId").nullable(); | ||
t.specificType("subnetIds", "text[]").nullable(); | ||
t.jsonb("tags").nullable(); | ||
t.boolean("multiAz").defaultTo(true); | ||
t.integer("rdsAllocatedStorage").defaultTo(50); | ||
t.integer("rdsBackupRetentionDays").defaultTo(7); | ||
t.integer("redisNumCacheNodes").defaultTo(1); | ||
t.integer("desiredContainerCount").defaultTo(1); | ||
t.string("stackName").nullable(); | ||
t.text("rdsInstanceId").nullable(); | ||
t.text("redisClusterId").nullable(); | ||
t.text("ecsClusterArn").nullable(); | ||
t.text("ecsServiceArn").nullable(); | ||
t.specificType("securityGroupIds", "text[]").nullable(); | ||
t.text("error").nullable(); | ||
t.timestamps(true, true, true); | ||
|
||
t.foreign("orgId") | ||
.references("id") | ||
.inTable(TableName.Organization) | ||
.onDelete("CASCADE"); | ||
|
||
t.unique(["orgId", "instanceName"]); | ||
}); | ||
} | ||
|
||
await createOnUpdateTrigger(knex, TableName.DedicatedInstances); | ||
} | ||
|
||
export async function down(knex: Knex): Promise<void> { | ||
await dropOnUpdateTrigger(knex, TableName.DedicatedInstances); | ||
await knex.schema.dropTableIfExists(TableName.DedicatedInstances); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { Knex } from "knex"; | ||
import { TableName } from "../schemas"; | ||
|
||
export async function up(knex: Knex): Promise<void> { | ||
// First drop the existing constraint | ||
await knex.raw(`ALTER TABLE ${TableName.DedicatedInstances} DROP CONSTRAINT IF EXISTS dedicated_instances_status_check`); | ||
|
||
// Add the new constraint with updated enum values | ||
await knex.raw(`ALTER TABLE ${TableName.DedicatedInstances} ADD CONSTRAINT dedicated_instances_status_check CHECK (status IN ('RUNNING', 'UPGRADING', 'PROVISIONING', 'FAILED'))`); | ||
} | ||
|
||
export async function down(knex: Knex): Promise<void> { | ||
// Revert back to original constraint | ||
await knex.raw(`ALTER TABLE ${TableName.DedicatedInstances} DROP CONSTRAINT IF EXISTS dedicated_instances_status_check`); | ||
await knex.raw(`ALTER TABLE ${TableName.DedicatedInstances} ADD CONSTRAINT dedicated_instances_status_check CHECK (status IN ('RUNNING', 'UPGRADING', 'PROVISIONING'))`); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
// Code generated by automation script, DO NOT EDIT. | ||
// Automated by pulling database and generating zod schema | ||
// To update. Just run npm run generate:schema | ||
// Written by akhilmhdh. | ||
|
||
import { z } from "zod"; | ||
|
||
import { TImmutableDBKeys } from "./models"; | ||
|
||
export const DedicatedInstancesSchema = z.object({ | ||
id: z.string().uuid(), | ||
orgId: z.string().uuid(), | ||
instanceName: z.string(), | ||
status: z.string(), | ||
rdsInstanceType: z.string(), | ||
elasticCacheType: z.string(), | ||
elasticContainerMemory: z.number(), | ||
elasticContainerCpu: z.number(), | ||
region: z.string(), | ||
version: z.string(), | ||
backupRetentionDays: z.number().default(7).nullable().optional(), | ||
lastBackupTime: z.date().nullable().optional(), | ||
lastUpgradeTime: z.date().nullable().optional(), | ||
publiclyAccessible: z.boolean().default(false).nullable().optional(), | ||
vpcId: z.string().nullable().optional(), | ||
subnetIds: z.string().array().nullable().optional(), | ||
tags: z.unknown().nullable().optional(), | ||
createdAt: z.date(), | ||
updatedAt: z.date() | ||
}); | ||
|
||
export type TDedicatedInstances = z.infer<typeof DedicatedInstancesSchema>; | ||
export type TDedicatedInstancesInsert = Omit<z.input<typeof DedicatedInstancesSchema>, TImmutableDBKeys>; | ||
export type TDedicatedInstancesUpdate = Partial<Omit<z.input<typeof DedicatedInstancesSchema>, TImmutableDBKeys>>; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,141 @@ | ||||||||||||||||||||||||||||||||||||||||||
import { z } from "zod"; | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; | ||||||||||||||||||||||||||||||||||||||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; | ||||||||||||||||||||||||||||||||||||||||||
import { AuthMode } from "@app/services/auth/auth-type"; | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
const DedicatedInstanceSchema = z.object({ | ||||||||||||||||||||||||||||||||||||||||||
id: z.string().uuid(), | ||||||||||||||||||||||||||||||||||||||||||
orgId: z.string().uuid(), | ||||||||||||||||||||||||||||||||||||||||||
instanceName: z.string().min(1), | ||||||||||||||||||||||||||||||||||||||||||
subdomain: z.string().min(1), | ||||||||||||||||||||||||||||||||||||||||||
status: z.enum(["RUNNING", "UPGRADING", "PROVISIONING", "FAILED"]), | ||||||||||||||||||||||||||||||||||||||||||
rdsInstanceType: z.string(), | ||||||||||||||||||||||||||||||||||||||||||
elasticCacheType: z.string(), | ||||||||||||||||||||||||||||||||||||||||||
elasticContainerMemory: z.number(), | ||||||||||||||||||||||||||||||||||||||||||
elasticContainerCpu: z.number(), | ||||||||||||||||||||||||||||||||||||||||||
region: z.string(), | ||||||||||||||||||||||||||||||||||||||||||
version: z.string(), | ||||||||||||||||||||||||||||||||||||||||||
backupRetentionDays: z.number(), | ||||||||||||||||||||||||||||||||||||||||||
lastBackupTime: z.date().nullable(), | ||||||||||||||||||||||||||||||||||||||||||
lastUpgradeTime: z.date().nullable(), | ||||||||||||||||||||||||||||||||||||||||||
publiclyAccessible: z.boolean(), | ||||||||||||||||||||||||||||||||||||||||||
vpcId: z.string().nullable(), | ||||||||||||||||||||||||||||||||||||||||||
subnetIds: z.array(z.string()).nullable(), | ||||||||||||||||||||||||||||||||||||||||||
tags: z.record(z.string()).nullable(), | ||||||||||||||||||||||||||||||||||||||||||
createdAt: z.date(), | ||||||||||||||||||||||||||||||||||||||||||
updatedAt: z.date() | ||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
const CreateDedicatedInstanceSchema = z.object({ | ||||||||||||||||||||||||||||||||||||||||||
instanceName: z.string().min(1), | ||||||||||||||||||||||||||||||||||||||||||
subdomain: z.string().min(1), | ||||||||||||||||||||||||||||||||||||||||||
provider: z.literal('aws'), // Only allow 'aws' as provider | ||||||||||||||||||||||||||||||||||||||||||
region: z.string(), | ||||||||||||||||||||||||||||||||||||||||||
publiclyAccessible: z.boolean().default(false) | ||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
const DedicatedInstanceDetailsSchema = DedicatedInstanceSchema.extend({ | ||||||||||||||||||||||||||||||||||||||||||
stackStatus: z.string().optional(), | ||||||||||||||||||||||||||||||||||||||||||
stackStatusReason: z.string().optional(), | ||||||||||||||||||||||||||||||||||||||||||
error: z.string().nullable(), | ||||||||||||||||||||||||||||||||||||||||||
events: z.array( | ||||||||||||||||||||||||||||||||||||||||||
z.object({ | ||||||||||||||||||||||||||||||||||||||||||
timestamp: z.date().optional(), | ||||||||||||||||||||||||||||||||||||||||||
logicalResourceId: z.string().optional(), | ||||||||||||||||||||||||||||||||||||||||||
resourceType: z.string().optional(), | ||||||||||||||||||||||||||||||||||||||||||
resourceStatus: z.string().optional(), | ||||||||||||||||||||||||||||||||||||||||||
resourceStatusReason: z.string().optional() | ||||||||||||||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||||||||||||||
).optional() | ||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
export const registerDedicatedInstanceRouter = async (server: FastifyZodProvider) => { | ||||||||||||||||||||||||||||||||||||||||||
server.route({ | ||||||||||||||||||||||||||||||||||||||||||
method: "GET", | ||||||||||||||||||||||||||||||||||||||||||
url: "/:organizationId/dedicated-instances", | ||||||||||||||||||||||||||||||||||||||||||
config: { | ||||||||||||||||||||||||||||||||||||||||||
rateLimit: readLimit | ||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||
schema: { | ||||||||||||||||||||||||||||||||||||||||||
params: z.object({ | ||||||||||||||||||||||||||||||||||||||||||
organizationId: z.string().uuid() | ||||||||||||||||||||||||||||||||||||||||||
}), | ||||||||||||||||||||||||||||||||||||||||||
response: { | ||||||||||||||||||||||||||||||||||||||||||
200: z.object({ | ||||||||||||||||||||||||||||||||||||||||||
instances: DedicatedInstanceSchema.array() | ||||||||||||||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||
onRequest: verifyAuth([AuthMode.JWT]), | ||||||||||||||||||||||||||||||||||||||||||
handler: async (req) => { | ||||||||||||||||||||||||||||||||||||||||||
const instances = await server.services.dedicatedInstance.listInstances({ | ||||||||||||||||||||||||||||||||||||||||||
orgId: req.params.organizationId | ||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||
return { instances }; | ||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
server.route({ | ||||||||||||||||||||||||||||||||||||||||||
method: "POST", | ||||||||||||||||||||||||||||||||||||||||||
url: "/:organizationId/dedicated-instances", | ||||||||||||||||||||||||||||||||||||||||||
config: { | ||||||||||||||||||||||||||||||||||||||||||
rateLimit: writeLimit | ||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||
schema: { | ||||||||||||||||||||||||||||||||||||||||||
params: z.object({ | ||||||||||||||||||||||||||||||||||||||||||
organizationId: z.string().uuid() | ||||||||||||||||||||||||||||||||||||||||||
}), | ||||||||||||||||||||||||||||||||||||||||||
body: CreateDedicatedInstanceSchema | ||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||
onRequest: verifyAuth([AuthMode.JWT]), | ||||||||||||||||||||||||||||||||||||||||||
handler: async (req) => { | ||||||||||||||||||||||||||||||||||||||||||
const { organizationId } = req.params; | ||||||||||||||||||||||||||||||||||||||||||
const { instanceName, subdomain, region, publiclyAccessible, provider} = req.body; | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
const instance = await server.services.dedicatedInstance.createInstance({ | ||||||||||||||||||||||||||||||||||||||||||
orgId: organizationId, | ||||||||||||||||||||||||||||||||||||||||||
instanceName, | ||||||||||||||||||||||||||||||||||||||||||
subdomain, | ||||||||||||||||||||||||||||||||||||||||||
region, | ||||||||||||||||||||||||||||||||||||||||||
publiclyAccessible, | ||||||||||||||||||||||||||||||||||||||||||
provider: provider, | ||||||||||||||||||||||||||||||||||||||||||
dryRun: false, | ||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+96
to
+105
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. Fix type mismatch in The pipeline error indicates that the argument passed to const instance = await server.services.dedicatedInstance.createInstance({
orgId: organizationId,
instanceName,
subdomain,
region,
publiclyAccessible,
provider: provider,
- dryRun: false,
+ // If 'dryRun' is part of the service definition, add it to the interface. Otherwise remove it.
+ // clusterSize, if needed, must be passed here to match the updated schema:
+ // clusterSize,
}); 📝 Committable suggestion
Suggested change
🧰 Tools🪛 GitHub Actions: Check Backend PR types and lint[error] 96-96: Argument of type '{ orgId: string; instanceName: string; subdomain: string; region: string; publiclyAccessible: boolean; provider: "aws"; dryRun: false; }' is not assignable to parameter of type 'CreateInstanceParams'. |
||||||||||||||||||||||||||||||||||||||||||
return instance; | ||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
server.route({ | ||||||||||||||||||||||||||||||||||||||||||
method: "GET", | ||||||||||||||||||||||||||||||||||||||||||
url: "/:organizationId/dedicated-instances/:instanceId", | ||||||||||||||||||||||||||||||||||||||||||
config: { | ||||||||||||||||||||||||||||||||||||||||||
rateLimit: readLimit | ||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||
schema: { | ||||||||||||||||||||||||||||||||||||||||||
params: z.object({ | ||||||||||||||||||||||||||||||||||||||||||
organizationId: z.string().uuid(), | ||||||||||||||||||||||||||||||||||||||||||
instanceId: z.string().uuid() | ||||||||||||||||||||||||||||||||||||||||||
}), | ||||||||||||||||||||||||||||||||||||||||||
response: { | ||||||||||||||||||||||||||||||||||||||||||
200: DedicatedInstanceDetailsSchema | ||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||
onRequest: verifyAuth([AuthMode.JWT]), | ||||||||||||||||||||||||||||||||||||||||||
handler: async (req) => { | ||||||||||||||||||||||||||||||||||||||||||
const { organizationId, instanceId } = req.params; | ||||||||||||||||||||||||||||||||||||||||||
const { instance, stackStatus, stackStatusReason, events } = await server.services.dedicatedInstance.getInstance({ | ||||||||||||||||||||||||||||||||||||||||||
orgId: organizationId, | ||||||||||||||||||||||||||||||||||||||||||
instanceId | ||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
return { | ||||||||||||||||||||||||||||||||||||||||||
...instance, | ||||||||||||||||||||||||||||||||||||||||||
stackStatus, | ||||||||||||||||||||||||||||||||||||||||||
stackStatusReason, | ||||||||||||||||||||||||||||||||||||||||||
events | ||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import { Knex } from "knex"; | ||
|
||
import { TDbClient } from "@app/db"; | ||
import { TableName } from "@app/db/schemas"; | ||
import { DatabaseError } from "@app/lib/errors"; | ||
import { ormify } from "@app/lib/knex"; | ||
|
||
export type TDedicatedInstanceDALFactory = ReturnType<typeof dedicatedInstanceDALFactory>; | ||
|
||
export const dedicatedInstanceDALFactory = (db: TDbClient) => { | ||
const dedicatedInstanceOrm = ormify(db, TableName.DedicatedInstances); | ||
|
||
const findInstancesByOrgId = async (orgId: string, tx?: Knex) => { | ||
try { | ||
const instances = await (tx || db.replicaNode())(TableName.DedicatedInstances) | ||
.where({ orgId }) | ||
.select("*"); | ||
return instances; | ||
} catch (error) { | ||
throw new DatabaseError({ error, name: "Find instances by org ID" }); | ||
} | ||
}; | ||
|
||
return { | ||
...dedicatedInstanceOrm, | ||
findInstancesByOrgId | ||
}; | ||
}; |
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.
Include
clusterSize
in schema to match frontend payload.The frontend sends a
clusterSize
field, but the current schema doesn't accept it. Consider adding it for consistency if the backend is meant to handle it.const CreateDedicatedInstanceSchema = z.object({ instanceName: z.string().min(1), subdomain: z.string().min(1), provider: z.literal('aws'), // Only allow 'aws' as provider region: z.string(), publiclyAccessible: z.boolean().default(false), + clusterSize: z.enum(["small", "medium", "large"]).default("small") });
📝 Committable suggestion