feat: add option to enable namespaces

This commit is contained in:
Oliver Geneser
2025-09-13 13:45:19 +02:00
parent 4b1f359cb6
commit 803577a403
10 changed files with 300 additions and 110 deletions

View File

@@ -1,5 +1,5 @@
import { relations } from "drizzle-orm";
import { integer, json, pgTable, text } from "drizzle-orm/pg-core";
import { boolean, integer, json, pgTable, text } from "drizzle-orm/pg-core";
import { createInsertSchema } from "drizzle-zod";
import { nanoid } from "nanoid";
import { z } from "zod";
@@ -41,6 +41,7 @@ export const libsql = pgTable("libsql", {
databasePassword: text("databasePassword").notNull(),
sqldNode: sqldNode("sqldNode").notNull().default("primary"),
sqldPrimaryUrl: text("sqldPrimaryUrl"),
enableNamespaces: boolean("enableNamespaces").notNull().default(false),
dockerImage: text("dockerImage").notNull(),
command: text("command"),
env: text("env"),
@@ -52,6 +53,7 @@ export const libsql = pgTable("libsql", {
//
externalPort: integer("externalPort"),
externalGRPCPort: integer("externalGRPCPort"),
externalAdminPort: integer("externalAdminPort"),
applicationStatus: applicationStatus("applicationStatus")
.notNull()
.default("idle"),
@@ -102,7 +104,8 @@ const createSchema = createInsertSchema(libsql, {
"Password contains invalid characters. Please avoid: $ ! ' \" \\ / and space characters for database compatibility",
}),
sqldNode: z.enum(sqldNode.enumValues),
sqldPrimaryUrl: z.string().optional(),
sqldPrimaryUrl: z.string().nullable(),
enableNamespaces: z.boolean().default(false),
dockerImage: z.string().default("ghcr.io/tursodatabase/libsql-server:latest"),
command: z.string().optional(),
env: z.string().optional(),
@@ -114,6 +117,7 @@ const createSchema = createInsertSchema(libsql, {
applicationStatus: z.enum(["idle", "running", "done", "error"]),
externalPort: z.number(),
externalGRPCPort: z.number(),
externalAdminPort: z.number(),
description: z.string().optional(),
serverId: z.string().optional(),
healthCheckSwarm: HealthCheckSwarmSchema.nullable(),
@@ -137,6 +141,7 @@ export const apiCreateLibsql = createSchema
databasePassword: true,
sqldNode: true,
sqldPrimaryUrl: true,
enableNamespaces: true,
serverId: true,
})
.required()
@@ -183,14 +188,20 @@ export const apiSaveExternalPortsLibsql = createSchema
libsqlId: true,
externalPort: true,
externalGRPCPort: true,
externalAdminPort: true,
})
.required({ libsqlId: true })
.superRefine((data, ctx) => {
if (data.externalPort === null && data.externalGRPCPort === null) {
if (
data.externalPort === null &&
data.externalGRPCPort === null &&
data.externalAdminPort === null
) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "Either externalPort or externalGRPCPort must be provided.",
path: ["externalPort", "externalGRPCPort"],
message:
"Either externalPort, externalGRPCPort or externalAdminPort must be provided.",
path: ["externalPort", "externalGRPCPort", "externalAdminPort"],
});
}
});

View File

@@ -8,8 +8,27 @@ import {
generateVolumeMounts,
prepareEnvironmentVariables,
} from "../docker/utils";
import { execAsync, execAsyncRemote } from "../process/execAsync";
import { getRemoteDocker } from "../servers/remote-docker";
const getServerArchitecture = async (
serverId?: string | null,
): Promise<string> => {
if (!serverId) {
const { stdout } = await execAsync("uname -m");
return stdout.trim();
}
const { stdout } = await execAsyncRemote(serverId, "uname -m");
return stdout.trim();
};
const getLibsqlImage = (arch: string): string => {
if (arch === "aarch64" || arch === "arm64") {
return "ghcr.io/tursodatabase/libsql-server:latest-arm";
}
return "ghcr.io/tursodatabase/libsql-server:latest";
};
export type LibsqlNested = InferResultType<
"libsql",
{ mounts: true; environment: { with: { project: true } } }
@@ -20,6 +39,7 @@ export const buildLibsql = async (libsql: LibsqlNested) => {
env,
externalPort,
externalGRPCPort,
externalAdminPort,
dockerImage,
memoryLimit,
memoryReservation,
@@ -31,8 +51,16 @@ export const buildLibsql = async (libsql: LibsqlNested) => {
cpuReservation,
command,
mounts,
serverId,
enableNamespaces,
} = libsql;
let finalDockerImage = dockerImage;
if (dockerImage === "ghcr.io/tursodatabase/libsql-server:latest") {
const arch = await getServerArchitecture(serverId);
finalDockerImage = getLibsqlImage(arch);
}
const basicAuth = Buffer.from(
`${databaseUser}:${databasePassword}`,
"utf-8",
@@ -69,18 +97,25 @@ export const buildLibsql = async (libsql: LibsqlNested) => {
const docker = await getRemoteDocker(libsql.serverId);
let finalCommand =
command ??
"sqld --db-path iku.db --http-listen-addr 0.0.0.0:8080 --grpc-listen-addr 0.0.0.0:5001 --admin-listen-addr 0.0.0.0:5000";
if (enableNamespaces) {
finalCommand += " --enable-namespaces";
}
const settings: CreateServiceOptions = {
Name: appName,
TaskTemplate: {
ContainerSpec: {
HealthCheck,
Image: dockerImage,
Image: finalDockerImage,
Env: envVariables,
Mounts: [...volumesMount, ...bindsMount, ...filesMount],
...(command
...(finalCommand
? {
Command: ["/bin/sh"],
Args: ["-c", command],
Args: ["-c", finalCommand],
}
: {}),
Labels,
@@ -117,6 +152,16 @@ export const buildLibsql = async (libsql: LibsqlNested) => {
} as PortConfig,
]
: []),
...(externalAdminPort
? [
{
Protocol: "tcp",
TargetPort: 5000,
PublishedPort: externalAdminPort,
PublishMode: "host",
} as PortConfig,
]
: []),
],
},
UpdateConfig,