mirror of
https://github.com/pockethost/pockethost.git
synced 2025-07-07 13:22:31 +00:00
enh: instance volumes
This commit is contained in:
parent
cc9d1217f4
commit
26d1070c20
5
.changeset/mean-news-sing.md
Normal file
5
.changeset/mean-news-sing.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'pockethost': minor
|
||||||
|
---
|
||||||
|
|
||||||
|
Added support for instances hosted on alternate volumes
|
@ -51,7 +51,7 @@ const checkBun = (
|
|||||||
[`bun.lockb`, `package.json`].includes(maybeImportant || ''))
|
[`bun.lockb`, `package.json`].includes(maybeImportant || ''))
|
||||||
|
|
||||||
if (isImportant) {
|
if (isImportant) {
|
||||||
const logger = InstanceLogWriter(instance.id, `exec`)
|
const logger = InstanceLogWriter(instance.id, instance.volume, `exec`)
|
||||||
logger.info(`${maybeImportant} changed, running bun install`)
|
logger.info(`${maybeImportant} changed, running bun install`)
|
||||||
launchBunInstall(instance, virtualPath, cwd).catch(console.error)
|
launchBunInstall(instance, virtualPath, cwd).catch(console.error)
|
||||||
}
|
}
|
||||||
@ -103,7 +103,7 @@ const launchBunInstall = (() => {
|
|||||||
runCache[cwd] = { runAgain: true }
|
runCache[cwd] = { runAgain: true }
|
||||||
while (runCache[cwd]!.runAgain) {
|
while (runCache[cwd]!.runAgain) {
|
||||||
runCache[cwd]!.runAgain = false
|
runCache[cwd]!.runAgain = false
|
||||||
const logger = InstanceLogWriter(instance.id, `exec`)
|
const logger = InstanceLogWriter(instance.id, instance.volume, `exec`)
|
||||||
logger.info(`Launching 'bun install' in ${virtualPath}`)
|
logger.info(`Launching 'bun install' in ${virtualPath}`)
|
||||||
await runBun(cwd, logger)
|
await runBun(cwd, logger)
|
||||||
}
|
}
|
||||||
@ -174,6 +174,9 @@ export class PhFs implements FileSystem {
|
|||||||
`Instance must be in maintenance mode to access ${instanceRootDir}`,
|
`Instance must be in maintenance mode to access ${instanceRootDir}`,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
if (instance.volume) {
|
||||||
|
fsPathParts.push(instance.volume)
|
||||||
|
}
|
||||||
fsPathParts.push(instance.id)
|
fsPathParts.push(instance.id)
|
||||||
dbg({
|
dbg({
|
||||||
fsPathParts,
|
fsPathParts,
|
||||||
@ -222,6 +225,9 @@ export class PhFs implements FileSystem {
|
|||||||
this.cwd = clientPath
|
this.cwd = clientPath
|
||||||
return this.currentDirectory()
|
return this.currentDirectory()
|
||||||
})
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
throw new Error(`no such file or directory: ${path}`)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async list(path = '.') {
|
async list(path = '.') {
|
||||||
|
@ -33,6 +33,7 @@ export type InstanceFields<TExtra = {}> = BaseFields & {
|
|||||||
dev: boolean
|
dev: boolean
|
||||||
cname_active: boolean
|
cname_active: boolean
|
||||||
notifyMaintenanceMode: boolean
|
notifyMaintenanceMode: boolean
|
||||||
|
volume: string
|
||||||
idleTtl: number
|
idleTtl: number
|
||||||
} & TExtra
|
} & TExtra
|
||||||
|
|
||||||
|
@ -271,8 +271,11 @@ export const mkInstanceUrl = (instance: InstanceFields, ...paths: string[]) =>
|
|||||||
[`${HTTP_PROTOCOL()}//${mkInstanceHostname(instance)}`, paths.join(`/`)]
|
[`${HTTP_PROTOCOL()}//${mkInstanceHostname(instance)}`, paths.join(`/`)]
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.join('/')
|
.join('/')
|
||||||
export const mkInstanceDataPath = (instanceId: string, ...path: string[]) =>
|
export const mkInstanceDataPath = (
|
||||||
join(settings().DATA_ROOT, instanceId, ...path)
|
volume: string,
|
||||||
|
instanceId: string,
|
||||||
|
...path: string[]
|
||||||
|
) => DATA_ROOT(volume, instanceId, ...path)
|
||||||
|
|
||||||
export const logConstants = () => {
|
export const logConstants = () => {
|
||||||
const vars = {
|
const vars = {
|
||||||
|
@ -4,12 +4,13 @@ import { mkInstanceDataPath } from '../constants'
|
|||||||
|
|
||||||
export function ensureInstanceDirectoryStructure(
|
export function ensureInstanceDirectoryStructure(
|
||||||
instanceId: string,
|
instanceId: string,
|
||||||
|
volume: string,
|
||||||
logger: Logger,
|
logger: Logger,
|
||||||
) {
|
) {
|
||||||
const { dbg } = logger
|
const { dbg } = logger
|
||||||
;['pb_data', 'pb_migrations', 'pb_public', 'logs', 'pb_hooks'].forEach(
|
;['pb_data', 'pb_migrations', 'pb_public', 'logs', 'pb_hooks'].forEach(
|
||||||
(dir) => {
|
(dir) => {
|
||||||
const path = mkInstanceDataPath(instanceId, dir)
|
const path = mkInstanceDataPath(volume, instanceId, dir)
|
||||||
if (!existsSync(path)) {
|
if (!existsSync(path)) {
|
||||||
dbg(`Creating ${path}`)
|
dbg(`Creating ${path}`)
|
||||||
mkdirSync(path, { recursive: true })
|
mkdirSync(path, { recursive: true })
|
||||||
|
@ -0,0 +1,52 @@
|
|||||||
|
/// <reference path="../pb_data/types.d.ts" />
|
||||||
|
migrate((db) => {
|
||||||
|
const dao = new Dao(db)
|
||||||
|
const collection = dao.findCollectionByNameOrId("etae8tuiaxl6xfv")
|
||||||
|
|
||||||
|
// remove
|
||||||
|
collection.schema.removeField("1vrc1wfd")
|
||||||
|
|
||||||
|
// add
|
||||||
|
collection.schema.addField(new SchemaField({
|
||||||
|
"system": false,
|
||||||
|
"id": "kd017nrg",
|
||||||
|
"name": "volume",
|
||||||
|
"type": "text",
|
||||||
|
"required": false,
|
||||||
|
"presentable": false,
|
||||||
|
"unique": false,
|
||||||
|
"options": {
|
||||||
|
"min": null,
|
||||||
|
"max": null,
|
||||||
|
"pattern": ""
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
|
||||||
|
return dao.saveCollection(collection)
|
||||||
|
}, (db) => {
|
||||||
|
const dao = new Dao(db)
|
||||||
|
const collection = dao.findCollectionByNameOrId("etae8tuiaxl6xfv")
|
||||||
|
|
||||||
|
// add
|
||||||
|
collection.schema.addField(new SchemaField({
|
||||||
|
"system": false,
|
||||||
|
"id": "1vrc1wfd",
|
||||||
|
"name": "volume",
|
||||||
|
"type": "select",
|
||||||
|
"required": false,
|
||||||
|
"presentable": false,
|
||||||
|
"unique": false,
|
||||||
|
"options": {
|
||||||
|
"maxSelect": 1,
|
||||||
|
"values": [
|
||||||
|
".",
|
||||||
|
"sfo-2-data"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
|
||||||
|
// remove
|
||||||
|
collection.schema.removeField("kd017nrg")
|
||||||
|
|
||||||
|
return dao.saveCollection(collection)
|
||||||
|
})
|
@ -25,13 +25,22 @@ export type LogEntry = {
|
|||||||
time: string
|
time: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export function InstanceLogWriter(instanceId: string, target: string) {
|
export function InstanceLogWriter(
|
||||||
|
instanceId: string,
|
||||||
|
volume: string,
|
||||||
|
target: string,
|
||||||
|
) {
|
||||||
const logger = LoggerService().create(instanceId).breadcrumb({ target })
|
const logger = LoggerService().create(instanceId).breadcrumb({ target })
|
||||||
const { dbg, info, error, warn } = logger
|
const { dbg, info, error, warn } = logger
|
||||||
|
|
||||||
ensureInstanceDirectoryStructure(instanceId, logger)
|
ensureInstanceDirectoryStructure(instanceId, volume, logger)
|
||||||
|
|
||||||
const logFile = mkInstanceDataPath(instanceId, `logs`, `${target}.log`)
|
const logFile = mkInstanceDataPath(
|
||||||
|
volume,
|
||||||
|
instanceId,
|
||||||
|
`logs`,
|
||||||
|
`${target}.log`,
|
||||||
|
)
|
||||||
|
|
||||||
const appendLogEntry = (msg: string, stream: 'stdout' | 'stderr') => {
|
const appendLogEntry = (msg: string, stream: 'stdout' | 'stderr') => {
|
||||||
appendFile(
|
appendFile(
|
||||||
@ -58,15 +67,24 @@ export function InstanceLogWriter(instanceId: string, target: string) {
|
|||||||
return api
|
return api
|
||||||
}
|
}
|
||||||
|
|
||||||
export function InstanceLogReader(instanceId: string, target: string) {
|
export function InstanceLogReader(
|
||||||
|
instanceId: string,
|
||||||
|
volume: string,
|
||||||
|
target: string,
|
||||||
|
) {
|
||||||
const logger = LoggerService().create(instanceId).breadcrumb({ target })
|
const logger = LoggerService().create(instanceId).breadcrumb({ target })
|
||||||
const { dbg, info, error, warn } = logger
|
const { dbg, info, error, warn } = logger
|
||||||
|
|
||||||
ensureInstanceDirectoryStructure(instanceId, logger)
|
ensureInstanceDirectoryStructure(instanceId, volume, logger)
|
||||||
|
|
||||||
const api = {
|
const api = {
|
||||||
tail: (linesBack: number, data: (line: LogEntry) => void): UnsubFunc => {
|
tail: (linesBack: number, data: (line: LogEntry) => void): UnsubFunc => {
|
||||||
const logFile = mkInstanceDataPath(instanceId, `logs`, `${target}.log`)
|
const logFile = mkInstanceDataPath(
|
||||||
|
volume,
|
||||||
|
instanceId,
|
||||||
|
`logs`,
|
||||||
|
`${target}.log`,
|
||||||
|
)
|
||||||
|
|
||||||
let tid: any
|
let tid: any
|
||||||
let unsub: any
|
let unsub: any
|
||||||
|
@ -71,7 +71,11 @@ export const instanceService = mkSingleton(
|
|||||||
`${subdomain}:${id}:${version}`,
|
`${subdomain}:${id}:${version}`,
|
||||||
)
|
)
|
||||||
const { dbg, warn, error, info, trace } = systemInstanceLogger
|
const { dbg, warn, error, info, trace } = systemInstanceLogger
|
||||||
const userInstanceLogger = InstanceLogWriter(instance.id, `exec`)
|
const userInstanceLogger = InstanceLogWriter(
|
||||||
|
instance.id,
|
||||||
|
instance.volume,
|
||||||
|
`exec`,
|
||||||
|
)
|
||||||
|
|
||||||
shutdownManager.push(() => {
|
shutdownManager.push(() => {
|
||||||
dbg(`Shutting down`)
|
dbg(`Shutting down`)
|
||||||
@ -123,6 +127,7 @@ export const instanceService = mkSingleton(
|
|||||||
const spawnArgs: SpawnConfig = {
|
const spawnArgs: SpawnConfig = {
|
||||||
subdomain: instance.subdomain,
|
subdomain: instance.subdomain,
|
||||||
instanceId: instance.id,
|
instanceId: instance.id,
|
||||||
|
volume: instance.volume,
|
||||||
dev: instance.dev,
|
dev: instance.dev,
|
||||||
extraBinds: flatten([
|
extraBinds: flatten([
|
||||||
globSync(join(INSTANCE_APP_MIGRATIONS_DIR(), '*.js')).map(
|
globSync(join(INSTANCE_APP_MIGRATIONS_DIR(), '*.js')).map(
|
||||||
|
@ -23,6 +23,7 @@ export type Env = { [_: string]: string }
|
|||||||
export type SpawnConfig = {
|
export type SpawnConfig = {
|
||||||
subdomain: string
|
subdomain: string
|
||||||
instanceId: string
|
instanceId: string
|
||||||
|
volume: string
|
||||||
version?: string
|
version?: string
|
||||||
extraBinds?: string[]
|
extraBinds?: string[]
|
||||||
env?: Env
|
env?: Env
|
||||||
@ -77,6 +78,7 @@ export const createPocketbaseService = async (
|
|||||||
version,
|
version,
|
||||||
subdomain,
|
subdomain,
|
||||||
instanceId,
|
instanceId,
|
||||||
|
volume,
|
||||||
extraBinds,
|
extraBinds,
|
||||||
env,
|
env,
|
||||||
stderr,
|
stderr,
|
||||||
@ -85,7 +87,7 @@ export const createPocketbaseService = async (
|
|||||||
} = _cfg
|
} = _cfg
|
||||||
|
|
||||||
logger.breadcrumb({ subdomain, instanceId })
|
logger.breadcrumb({ subdomain, instanceId })
|
||||||
const iLogger = InstanceLogWriter(instanceId, 'exec')
|
const iLogger = InstanceLogWriter(instanceId, volume, 'exec')
|
||||||
|
|
||||||
const _version = version || maxVersion // If _version is blank, we use the max version available
|
const _version = version || maxVersion // If _version is blank, we use the max version available
|
||||||
const realVersion = await bot.maxSatisfyingVersion(_version)
|
const realVersion = await bot.maxSatisfyingVersion(_version)
|
||||||
@ -123,7 +125,7 @@ export const createPocketbaseService = async (
|
|||||||
dbg(data.toString())
|
dbg(data.toString())
|
||||||
})
|
})
|
||||||
const Binds = [
|
const Binds = [
|
||||||
`${mkInstanceDataPath(instanceId)}:${mkContainerHomePath()}`,
|
`${mkInstanceDataPath(volume, instanceId)}:${mkContainerHomePath()}`,
|
||||||
`${binPath}:${mkContainerHomePath(`pocketbase`)}:ro`,
|
`${binPath}:${mkContainerHomePath(`pocketbase`)}:ro`,
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -155,6 +157,7 @@ export const createPocketbaseService = async (
|
|||||||
Hard: 4096,
|
Hard: 4096,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
ExtraHosts: [`minio:host-gateway`],
|
||||||
},
|
},
|
||||||
Tty: false,
|
Tty: false,
|
||||||
ExposedPorts: {
|
ExposedPorts: {
|
||||||
|
@ -69,7 +69,11 @@ export const realtimeLog = mkSingleton(async (config: RealtimeLogConfig) => {
|
|||||||
dbg(`Instance is `, instance)
|
dbg(`Instance is `, instance)
|
||||||
|
|
||||||
/** Get a database connection */
|
/** Get a database connection */
|
||||||
const instanceLogger = InstanceLogReader(instance.id, `exec`)
|
const instanceLogger = InstanceLogReader(
|
||||||
|
instance.id,
|
||||||
|
instance.volume,
|
||||||
|
`exec`,
|
||||||
|
)
|
||||||
|
|
||||||
/** Start the stream */
|
/** Start the stream */
|
||||||
res.writeHead(200, {
|
res.writeHead(200, {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user