Add StartOS 0.4 package scaffold (manifest, main, interfaces, 2 actions)
- package/Makefile + s9pk.mk + package.json + tsconfig.json - startos/manifest: dockerBuild source pointing at ../image/Dockerfile - startos/main: reads /data/config.yaml reactively, passes env vars to container - startos/interfaces: binds port 9999 as HTTP UI - startos/actions: showPublicKey (read /data/ssh/id_ed25519.pub), configureSparks - TS + JS bundle compile clean (tsc --noEmit, ncc build)
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
import { sdk } from '../sdk'
|
||||
import { sparkConfigYaml } from '../fileModels/sparkConfig.yaml'
|
||||
|
||||
const { InputSpec, Value } = sdk
|
||||
|
||||
const inputSpec = InputSpec.of({
|
||||
spark1_host: Value.text({
|
||||
name: 'Spark 1 hostname or IP',
|
||||
description: 'Head node. Example: <spark-1-ip>',
|
||||
required: true,
|
||||
default: null,
|
||||
placeholder: '<spark-1-ip>',
|
||||
masked: false,
|
||||
}),
|
||||
spark1_user: Value.text({
|
||||
name: 'Spark 1 SSH user',
|
||||
description: 'Usually "<spark-user>".',
|
||||
required: true,
|
||||
default: '<spark-user>',
|
||||
placeholder: '<spark-user>',
|
||||
masked: false,
|
||||
}),
|
||||
spark2_host: Value.text({
|
||||
name: 'Spark 2 hostname or IP',
|
||||
description: 'Worker node. Example: <spark-2-ip>',
|
||||
required: true,
|
||||
default: null,
|
||||
placeholder: '<spark-2-ip>',
|
||||
masked: false,
|
||||
}),
|
||||
spark2_user: Value.text({
|
||||
name: 'Spark 2 SSH user',
|
||||
description: 'Usually "<spark-user>".',
|
||||
required: true,
|
||||
default: '<spark-user>',
|
||||
placeholder: '<spark-user>',
|
||||
masked: false,
|
||||
}),
|
||||
})
|
||||
|
||||
export const configureSparks = sdk.Action.withInput(
|
||||
'configure-sparks',
|
||||
async () => ({
|
||||
name: 'Configure Sparks',
|
||||
description: 'Set the hostnames and SSH users for your two Spark nodes.',
|
||||
warning: null,
|
||||
visibility: 'enabled',
|
||||
allowedStatuses: 'any',
|
||||
group: null,
|
||||
}),
|
||||
async () => inputSpec,
|
||||
async ({ effects }) => {
|
||||
const cfg = await sparkConfigYaml.read().once()
|
||||
return cfg ?? null
|
||||
},
|
||||
async ({ effects, input }) => {
|
||||
await sparkConfigYaml.merge(effects, input)
|
||||
return null
|
||||
},
|
||||
)
|
||||
@@ -0,0 +1,7 @@
|
||||
import { sdk } from '../sdk'
|
||||
import { configureSparks } from './configureSparks'
|
||||
import { showPublicKey } from './showPublicKey'
|
||||
|
||||
export const actions = sdk.Actions.of()
|
||||
.addAction(showPublicKey)
|
||||
.addAction(configureSparks)
|
||||
@@ -0,0 +1,54 @@
|
||||
import { sdk } from '../sdk'
|
||||
import { promises as fs } from 'fs'
|
||||
import * as path from 'path'
|
||||
|
||||
export const showPublicKey = sdk.Action.withoutInput(
|
||||
'show-public-key',
|
||||
async () => ({
|
||||
name: 'Show Public Key',
|
||||
description:
|
||||
'Display the SSH public key. Paste it into ~/.ssh/authorized_keys on each Spark to grant access.',
|
||||
warning: null,
|
||||
visibility: 'enabled',
|
||||
allowedStatuses: 'any',
|
||||
group: null,
|
||||
}),
|
||||
async () => {
|
||||
// The container generates the key under /data/ssh/id_ed25519.pub on first boot.
|
||||
// The volume "main" is mounted at the host path that StartOS exposes via `sdk.volumes.main`.
|
||||
// For an Action running in the host, we read the file directly through the volume path.
|
||||
const pubKeyPath = path.join(
|
||||
sdk.volumes.main.path,
|
||||
'ssh',
|
||||
'id_ed25519.pub',
|
||||
)
|
||||
let key: string
|
||||
try {
|
||||
key = (await fs.readFile(pubKeyPath, 'utf8')).trim()
|
||||
} catch (e) {
|
||||
return {
|
||||
version: '1' as const,
|
||||
title: 'Public Key Not Found',
|
||||
message:
|
||||
'The container has not yet generated its SSH keypair. Start the service, wait a few seconds, and try again.',
|
||||
result: null,
|
||||
}
|
||||
}
|
||||
return {
|
||||
version: '1' as const,
|
||||
title: 'SSH Public Key',
|
||||
message:
|
||||
'Append this single line to ~/.ssh/authorized_keys on EACH Spark (<spark-user> user):\n\n' +
|
||||
key,
|
||||
result: {
|
||||
type: 'single' as const,
|
||||
name: 'Public Key',
|
||||
description: 'Copy this line to each Spark.',
|
||||
value: key,
|
||||
masked: false,
|
||||
copyable: true,
|
||||
qr: false,
|
||||
},
|
||||
}
|
||||
},
|
||||
)
|
||||
Reference in New Issue
Block a user