@@ -2,17 +2,23 @@ import { Listr } from 'listr2';
22import { runRemoteCommand } from '../runner.js' ;
33import { ui } from '../ui.js' ;
44import type { RemoteExecutor } from '../../domain/remote/executor.js' ;
5- import type { ShipnodeConfig , DatabaseConfig , NetworkDatabaseConfig , RedisConfig } from '../../shared/types.js' ;
5+ import type { ShipnodeConfig , NetworkDatabaseConfig } from '../../shared/types.js' ;
6+ import {
7+ buildDbInstallCommand ,
8+ buildDbCreateCommand ,
9+ buildDbProbeCommand ,
10+ buildRedisInstallCommand ,
11+ buildRedisConfigureCommand ,
12+ buildRedisProbeCommand ,
13+ } from '../../infrastructure/provisioning/commands.js' ;
614
715export async function cmdSetup ( cwd : string , options : { config ?: string } ) : Promise < void > {
816 await runRemoteCommand (
917 cwd ,
1018 async ( { config, executor } ) => {
1119 ui . banner ( ) ;
1220 ui . step ( `Setting up ${ config . ssh . user } @${ config . ssh . host } ` ) ;
13-
1421 await buildTasks ( executor , config ) . run ( ) ;
15-
1622 ui . outro ( 'Server ready — run: shipnode deploy' ) ;
1723 } ,
1824 { configPath : options . config } ,
@@ -163,138 +169,3 @@ function buildTasks(executor: RemoteExecutor, config: ShipnodeConfig) {
163169 { rendererOptions : { collapseErrors : false } } ,
164170 ) ;
165171}
166-
167-
168- function sh ( s : string ) : string {
169- return s . replace ( / ' / g, "'\"'\"'" ) ;
170- }
171-
172- function shDq ( s : string ) : string {
173- return s . replace ( / \\ / g, '\\\\' ) . replace ( / " / g, '\\"' ) . replace ( / \$ / g, '\\$' ) . replace ( / ` / g, '\\`' ) ;
174- }
175-
176- export function buildDbInstallCommand ( db : NetworkDatabaseConfig ) : string {
177- const preamble = 'SUDO=""; [ "$EUID" -ne 0 ] && SUDO="sudo"' ;
178-
179- if ( db . type === 'postgres' ) {
180- return `${ preamble } ; $SUDO apt-get install -y postgresql postgresql-contrib && $SUDO systemctl enable postgresql && $SUDO systemctl start postgresql` ;
181- }
182-
183- if ( db . type === 'mysql' ) {
184- return `${ preamble } ; $SUDO apt-get install -y mysql-server && $SUDO systemctl enable mysql && $SUDO systemctl start mysql` ;
185- }
186-
187- if ( db . type === 'mongodb' ) {
188- const installCmd =
189- 'if ! command -v mongod &>/dev/null; then ' +
190- 'curl -fsSL https://www.mongodb.org/static/pgp/server-7.0.asc | $SUDO gpg --dearmor -o /usr/share/keyrings/mongodb-server-7.0.gpg; ' +
191- 'echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-7.0.gpg ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/7.0 multiverse" | $SUDO tee /etc/apt/sources.list.d/mongodb-org-7.0.list; ' +
192- '$SUDO apt-get update -qq && $SUDO apt-get install -y mongodb-org; ' +
193- 'fi' ;
194- return `${ preamble } ; ${ installCmd } && $SUDO systemctl enable mongod && $SUDO systemctl start mongod` ;
195- }
196-
197- throw new Error ( `Unsupported database type: ${ ( db as DatabaseConfig ) . type } ` ) ;
198- }
199-
200- export function buildDbCreateCommand ( db : NetworkDatabaseConfig ) : string {
201- // preamble uses ';' so the conditional SUDO/PG_RUN assignments don't break
202- // the '&&' chain when running as root (EUID=0 makes [ -ne 0 ] exit 1)
203- const preamble = 'SUDO=""; [ "$EUID" -ne 0 ] && SUDO="sudo"; PG_RUN="runuser -u postgres --"; [ "$EUID" -ne 0 ] && PG_RUN="sudo -u postgres"' ;
204-
205- if ( db . type === 'postgres' ) {
206- const userDq = shDq ( db . user ) ;
207- const nameDq = shDq ( db . name ) ;
208- const createUser = db . password
209- ? `$PG_RUN psql -c "CREATE USER \\"${ userDq } \\" WITH PASSWORD '${ shDq ( db . password ) } ';" 2>/dev/null || true`
210- : `$PG_RUN psql -c "CREATE USER \\"${ userDq } \\";" 2>/dev/null || true` ;
211- const commands = [
212- createUser ,
213- `$PG_RUN psql -tc "SELECT 1 FROM pg_database WHERE datname='${ nameDq } '" | grep -q 1 || $PG_RUN createdb -O "${ userDq } " "${ nameDq } "` ,
214- ] ;
215- return `${ preamble } ; ${ commands . join ( ' && ' ) } ` ;
216- }
217-
218- if ( db . type === 'mysql' ) {
219- const userDq = shDq ( db . user ) ;
220- const nameDq = shDq ( db . name ) ;
221- const pwClause = db . password ? `IDENTIFIED BY '${ shDq ( db . password ) } '` : '' ;
222- const commands = [
223- `$SUDO mysql -e "CREATE USER IF NOT EXISTS '${ userDq } '@'localhost' ${ pwClause } ;"` ,
224- `$SUDO mysql -e "CREATE DATABASE IF NOT EXISTS \\\`${ nameDq } \\\`;"` ,
225- `$SUDO mysql -e "GRANT ALL PRIVILEGES ON \\\`${ nameDq } \\\`.* TO '${ userDq } '@'localhost';"` ,
226- `$SUDO mysql -e "FLUSH PRIVILEGES;"` ,
227- ] ;
228- return `${ preamble } ; ${ commands . join ( ' && ' ) } ` ;
229- }
230-
231- if ( db . type === 'mongodb' ) {
232- if ( ! db . password ) return 'true' ;
233- const nameDq = shDq ( db . name ) ;
234- const userDq = shDq ( db . user ) ;
235- const pwdDq = shDq ( db . password ) ;
236- const commands = [
237- `if ! grep -q "authorization: enabled" /etc/mongod.conf 2>/dev/null; then echo -e "\\nsecurity:\\n authorization: enabled" | $SUDO tee -a /etc/mongod.conf > /dev/null && $SUDO systemctl restart mongod; fi` ,
238- `mongosh "${ nameDq } " --eval "db.createUser({user:'${ userDq } ',pwd:'${ pwdDq } ',roles:[{role:'readWrite',db:'${ nameDq } '}]})" 2>/dev/null || true` ,
239- ] ;
240- return `${ preamble } ; ${ commands . join ( ' && ' ) } ` ;
241- }
242-
243- throw new Error ( `Unsupported database type: ${ ( db as DatabaseConfig ) . type } ` ) ;
244- }
245-
246- export function buildDbProbeCommand ( db : NetworkDatabaseConfig ) : string | null {
247- if ( ! db . password ) return null ;
248-
249- if ( db . type === 'postgres' ) {
250- return `PGPASSWORD='${ sh ( db . password ) } ' psql -h localhost -U '${ sh ( db . user ) } ' -d '${ sh ( db . name ) } ' -c "SELECT 1" > /dev/null` ;
251- }
252-
253- if ( db . type === 'mysql' ) {
254- return `MYSQL_PWD='${ sh ( db . password ) } ' mysql -h 127.0.0.1 -u '${ sh ( db . user ) } ' '${ sh ( db . name ) } ' -e "SELECT 1" > /dev/null` ;
255- }
256-
257- if ( db . type === 'mongodb' ) {
258- return `mongosh --host localhost '${ sh ( db . name ) } ' -u '${ sh ( db . user ) } ' -p '${ sh ( db . password ) } ' --authenticationDatabase '${ sh ( db . name ) } ' --eval "db.runCommand({ping:1})" --quiet > /dev/null` ;
259- }
260-
261- throw new Error ( `Unsupported database type: ${ ( db as DatabaseConfig ) . type } ` ) ;
262- }
263-
264- export function buildDbSetupCommand ( db : DatabaseConfig ) : string {
265- if ( db . type === 'sqlite' ) {
266- throw new Error ( `buildDbSetupCommand called for sqlite — caller should guard against this` ) ;
267- }
268- const install = buildDbInstallCommand ( db ) ;
269- const create = buildDbCreateCommand ( db ) ;
270- const probe = buildDbProbeCommand ( db ) ;
271- return [ install , create , ...( probe ? [ probe ] : [ ] ) ] . join ( ' && ' ) ;
272- }
273-
274- export function buildRedisInstallCommand ( _redis : RedisConfig ) : string {
275- const preamble = 'SUDO=""; [ "$EUID" -ne 0 ] && SUDO="sudo"' ;
276- return `${ preamble } ; $SUDO apt-get install -y redis-server && $SUDO systemctl enable redis-server && $SUDO systemctl start redis-server` ;
277- }
278-
279- export function buildRedisConfigureCommand ( redis : RedisConfig ) : string {
280- const preamble = 'SUDO=""; [ "$EUID" -ne 0 ] && SUDO="sudo"' ;
281- if ( ! redis . password ) return 'true' ;
282- const parts = [
283- `$SUDO sed -i '/^#* *requirepass/d' /etc/redis/redis.conf` ,
284- `echo "requirepass ${ shDq ( redis . password ) } " | $SUDO tee -a /etc/redis/redis.conf > /dev/null` ,
285- '$SUDO systemctl restart redis-server' ,
286- ] ;
287- return `${ preamble } ; ${ parts . join ( ' && ' ) } ` ;
288- }
289-
290- export function buildRedisProbeCommand ( redis : RedisConfig ) : string | null {
291- if ( ! redis . password ) return null ;
292- return `redis-cli -h localhost -p ${ redis . port } -a '${ sh ( redis . password ) } ' PING > /dev/null 2>&1` ;
293- }
294-
295- export function buildRedisSetupCommand ( redis : RedisConfig ) : string {
296- const install = buildRedisInstallCommand ( redis ) ;
297- const configure = buildRedisConfigureCommand ( redis ) ;
298- const probe = buildRedisProbeCommand ( redis ) ;
299- return [ install , configure , ...( probe ? [ probe ] : [ ] ) ] . join ( ' && ' ) ;
300- }
0 commit comments