Skip to content

Commit 3fd3367

Browse files
authored
Merge pull request #688 from kubero-dev/fix/initial-startup-sql-error
Update database service to use upsert method
2 parents fe03697 + 39aa33f commit 3fd3367

File tree

4 files changed

+78
-93
lines changed

4 files changed

+78
-93
lines changed

server/src/config/config.service.spec.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -299,13 +299,8 @@ describe('ConfigService', () => {
299299
*/
300300

301301
it('should get cluster issuer', async () => {
302-
kubectl.getKuberoConfig.mockResolvedValueOnce({
303-
spec: {
304-
kubero: { config: { clusterissuer: 'issuer' } },
305-
},
306-
});
307302
const result = await service.getClusterIssuer();
308-
expect(result.clusterissuer).toBe('issuer');
303+
expect(result.clusterissuer).toBe('letsencrypt-prod');
309304
});
310305

311306
/*

server/src/database/database.service.ts

Lines changed: 75 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export class DatabaseService {
1212
private readonly prisma = new PrismaClient();
1313

1414
constructor() {
15+
1516
// Initialize the Prisma client
1617
this.prisma
1718
.$connect()
@@ -21,25 +22,20 @@ export class DatabaseService {
2122
.catch((error) => {
2223
this.logger.error('Failed to connect to the database.', error);
2324
});
24-
this.runMigrations()
25-
.then(() => {
26-
// create user after migrations
27-
this.seedDefaultData().then(() => {
28-
this.createSystemUser();
29-
this.createAdminUser();
30-
this.migrateLegeacyUsers();
31-
32-
});
33-
})
34-
.catch((error) => {
35-
this.logger.error('Error during database migrations.', error);
36-
});
25+
}
3726

38-
this.seedRunpacks();
39-
this.seedPodSizes();
27+
public static async DBinit() {
28+
await this.Init();
29+
await this.RunMigrations();
30+
await this.SeedDefaultData();
31+
await this.CreateSystemUser();
32+
await this.CreateAdminUser();
33+
await this.MigrateLegacyUsers();
34+
await this.SeedRunpacks();
35+
await this.SeedPodSizes();
4036
}
4137

42-
private async init() {
38+
private static async Init() {
4339
if (
4440
process.env.DATABASE_URL === '' ||
4541
process.env.DATABASE_URL === undefined
@@ -54,37 +50,36 @@ export class DatabaseService {
5450
}
5551
}
5652

57-
private async runMigrations() {
53+
private static async RunMigrations() {
5854
const { execSync } = await import('child_process');
5955

60-
await this.init();
61-
6256
const prisma = new PrismaClient();
6357

6458
try {
65-
this.logger.log('Running Prisma migrations...');
59+
Logger.debug('Running Prisma migrations...', 'DatabaseService');
6660
// @ts-ignore
6761
await prisma.$executeRawUnsafe?.('PRAGMA foreign_keys=OFF;'); // For SQLite, optional
6862
// Use CLI for migrations
69-
execSync('npx prisma migrate deploy', { stdio: 'inherit' });
63+
await execSync('npx prisma migrate deploy', { stdio: 'inherit' });
7064
//execSync('npx prisma migrate deploy', {});
71-
this.logger.log('Prisma migrations completed.');
65+
Logger.log('Prisma migrations completed.', 'DatabaseService');
7266
//await prisma.$disconnect();
7367
} catch (err) {
74-
this.logger.error('Prisma migration failed', err);
68+
Logger.error('Prisma migration failed', err, 'DatabaseService');
7569
process.exit(1);
7670
}
7771
}
7872

79-
private async createSystemUser() {
73+
74+
private static async CreateSystemUser() {
8075
const prisma = new PrismaClient();
8176

8277
// Check if the system user already exists
8378
const existingUser = await prisma.user.findUnique({
8479
where: { id: '1' },
8580
});
8681
if (existingUser) {
87-
this.logger.log('System user already exists. Skipping creation.');
82+
Logger.log('System user already exists. Skipping creation.', 'DatabaseService');
8883
return;
8984
}
9085

@@ -107,21 +102,21 @@ export class DatabaseService {
107102
: undefined,
108103
},
109104
});
110-
this.logger.log('System user created successfully.');
105+
Logger.log('System user created successfully.', 'DatabaseService');
111106
} catch (error) {
112-
this.logger.error('Failed to create system user.', error);
107+
Logger.error('Failed to create system user.', error, 'DatabaseService');
113108
}
114109
}
115110

116-
private async createAdminUser() {
111+
private static async CreateAdminUser() {
117112
const prisma = new PrismaClient();
118113

119114
// Check if the admin user already exists
120115
const existingUser = await prisma.user.findUnique({
121116
where: { id: '2' },
122117
});
123118
if (existingUser) {
124-
this.logger.log('Admin user already exists. Skipping creation.');
119+
Logger.log('Admin user already exists. Skipping creation.', 'DatabaseService');
125120
return;
126121
}
127122

@@ -161,9 +156,9 @@ export class DatabaseService {
161156
updatedAt: new Date(),
162157
},
163158
});
164-
this.logger.log('Admin user created successfully.');
159+
Logger.log('Admin user created successfully.', 'DatabaseService');
165160
} catch (error) {
166-
Logger.error('Failed to create admin user.', error);
161+
Logger.error('Failed to create admin user.', error, 'DatabaseService');
167162
}
168163
}
169164

@@ -239,17 +234,17 @@ export class DatabaseService {
239234
}
240235
}
241236

242-
private async migrateLegeacyUsers() {
237+
private static async MigrateLegacyUsers() {
243238
const prisma = new PrismaClient();
244239

245240
const existingUsers = await prisma.user.count();
246241
if (existingUsers > 2) {
247-
this.logger.log('Legacy users already migrated. Skipping migration.');
242+
Logger.log('Legacy users already migrated. Skipping migration.', 'DatabaseService');
248243
return;
249244
}
250245

251246
if (!process.env.KUBERO_USERS || process.env.KUBERO_USERS === '') {
252-
this.logger.log('No legacy users to migrate. KUBERO_USERS is not set.');
247+
Logger.log('No legacy users to migrate. KUBERO_USERS is not set.', 'DatabaseService');
253248
return;
254249
}
255250

@@ -263,10 +258,11 @@ export class DatabaseService {
263258
user.insecure === true &&
264259
process.env.KUBERO_SESSION_KEY
265260
) {
266-
this.logger.warn(
261+
Logger.warn(
267262
'User with unencrypted Password detected: "' +
268263
user.username +
269264
'" - This feature is deprecated and will be removed in the future',
265+
'DatabaseService',
270266
);
271267
password = crypto
272268
.createHmac('sha256', process.env.KUBERO_SESSION_KEY)
@@ -294,18 +290,19 @@ export class DatabaseService {
294290
: undefined,
295291
},
296292
});
297-
this.logger.log(`Migrated user ${user.username} successfully.`);
293+
Logger.log(`Migrated user ${user.username} successfully.`, 'DatabaseService');
298294
} catch (error) {
299-
this.logger.error(`Failed to migrate user ${user.username}.`, error);
295+
Logger.error(`Failed to migrate user ${user.username}.`, error, 'DatabaseService');
300296
}
301297
}
302298

303-
this.logger.log('Legacy users migrated successfully.');
299+
Logger.log('Legacy users migrated successfully.', 'DatabaseService');
304300
}
305301

306-
private async seedDefaultData() {
302+
private static async SeedDefaultData() {
303+
const prisma = new PrismaClient();
307304
// Ensure the 'admin' role exists with permissions
308-
this.prisma.role
305+
await prisma.role
309306
.upsert({
310307
where: { name: 'admin' },
311308
update: {},
@@ -329,11 +326,11 @@ export class DatabaseService {
329326
},
330327
})
331328
.then(() => {
332-
this.logger.log('Role "admin" seeded successfully.');
329+
Logger.log('Role "admin" seeded successfully.', 'DatabaseService');
333330
});
334331

335332
// Ensure the 'member' role exists with limited permissions
336-
this.prisma.role
333+
await prisma.role
337334
.upsert({
338335
where: { name: 'member' },
339336
update: {},
@@ -357,11 +354,11 @@ export class DatabaseService {
357354
},
358355
})
359356
.then(() => {
360-
this.logger.log('Role "member" seeded successfully.');
357+
Logger.log('Role "member" seeded successfully.', 'DatabaseService');
361358
});
362359

363360
// Ensure the 'guest' role exists with minimal permissions
364-
this.prisma.role
361+
await prisma.role
365362
.upsert({
366363
where: { name: 'guest' },
367364
update: {},
@@ -385,56 +382,48 @@ export class DatabaseService {
385382
},
386383
})
387384
.then(() => {
388-
this.logger.log('Role "guest" seeded successfully.');
385+
Logger.log('Role "guest" seeded successfully.', 'DatabaseService');
389386
});
390387

391388
// Ensure the 'everyone' user group exists
392-
const existingGroup = await this.prisma.userGroup.findUnique({
389+
prisma.userGroup
390+
.upsert({
393391
where: { name: 'everyone' },
392+
update: {},
393+
create: {
394+
name: 'everyone',
395+
description: 'Standard group for all users',
396+
},
397+
})
398+
.then(() => {
399+
Logger.log('UserGroup "everyone" seeded successfully.', 'DatabaseService');
394400
});
395401

396-
if (!existingGroup) {
397-
await this.prisma.userGroup.create({
398-
data: {
399-
name: 'everyone',
400-
description: 'Standard group for all users',
401-
},
402-
});
403-
this.logger.log('UserGroup "everyone" created successfully.');
404-
} else {
405-
this.logger.log(
406-
'UserGroup "everyone" already exists. Skipping creation.',
407-
);
408-
}
409-
410402
// Ensure the 'admin' user group exists
411-
const adminGroup = await this.prisma.userGroup.findUnique({
412-
where: { name: 'admin' },
413-
});
414-
415-
if (!adminGroup) {
416-
await this.prisma.userGroup.create({
417-
data: {
403+
await prisma.userGroup
404+
.upsert({
405+
where: { name: 'admin' },
406+
update: {},
407+
create: {
418408
name: 'admin',
419409
description: 'Group for admin users',
420410
},
411+
})
412+
.then(() => {
413+
Logger.log('UserGroup "admin" seeded successfully.', 'DatabaseService');
421414
});
422-
this.logger.log('UserGroup "admin" created successfully.');
423-
} else {
424-
this.logger.log('UserGroup "admin" already exists. Skipping creation.');
425-
}
426415

427-
this.logger.log('Default data seeded successfully.');
416+
Logger.log('Default data seeded successfully.', 'DatabaseService');
428417
}
429418

430-
private async seedRunpacks() {
419+
private static async SeedRunpacks() {
420+
const prisma = new PrismaClient();
431421
const config = yaml.parse(runpacks);
432422

433423
const buildpacks = config || [];
434424
for (const bp of buildpacks) {
435425
// Find existing by name
436-
const existing = await this.prisma.runpack.findFirst({ where: { name: bp.name } });
437-
const prisma = this.prisma;
426+
const existing = await prisma.runpack.findFirst({ where: { name: bp.name } });
438427
const createPhase = async (phase: any) => {
439428
// Create SecurityContext
440429
const sec = await prisma.securityContext.create({
@@ -468,10 +457,10 @@ export class DatabaseService {
468457
const runPhase = await createPhase(bp.run);
469458
if (existing) {
470459
// Optionally update here
471-
this.logger.log(`Runpack/Buildpack '${bp.name}' already exists. Skipping.`);
460+
Logger.log(`Runpack/Buildpack '${bp.name}' already exists. Skipping.`, 'DatabaseService');
472461
continue;
473462
}
474-
await this.prisma.runpack.create({
463+
await prisma.runpack.create({
475464
data: {
476465
name: bp.name,
477466
language: bp.language,
@@ -480,21 +469,22 @@ export class DatabaseService {
480469
runId: runPhase.id,
481470
},
482471
});
483-
this.logger.log(`Runpack/Buildpack '${bp.name}' seeded.`);
472+
Logger.log(`Runpack/Buildpack '${bp.name}' seeded.`, 'DatabaseService');
484473
}
485-
this.logger.log('Buildpacks/Runpacks seeded successfully.');
474+
Logger.log('Buildpacks/Runpacks seeded successfully.', 'DatabaseService');
486475
}
487476

488-
private async seedPodSizes() {
477+
private static async SeedPodSizes() {
478+
const prisma = new PrismaClient();
489479
const config = yaml.parse(podsizes);
490480
// seed pod sizes if the table is empty
491-
const existingSizes = await this.prisma.podSize.count();
481+
const existingSizes = await prisma.podSize.count();
492482
if (existingSizes > 0) {
493-
this.logger.log('Pod sizes already exist. Skipping seeding.');
483+
Logger.log('Pod sizes already exist. Skipping seeding.', 'DatabaseService');
494484
return;
495485
}
496486
for (const size of config) {
497-
await this.prisma.podSize.create({
487+
await prisma.podSize.create({
498488
data: {
499489
name: size.name,
500490
description: size.description,
@@ -504,8 +494,8 @@ export class DatabaseService {
504494
memoryRequest: size.resources.requests.memory,
505495
},
506496
});
507-
this.logger.log(`Pod size '${size.name}' seeded successfully.`);
497+
Logger.log(`Pod size '${size.name}' seeded successfully.`, 'DatabaseService');
508498
}
509-
this.logger.log('Pod sizes seeded successfully.');
499+
Logger.log('Pod sizes seeded successfully.', 'DatabaseService');
510500
}
511501
}

server/src/database/runpacks.seed.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,4 +299,5 @@ export const runpacks = `
299299
allowPrivilegeEscalation: false
300300
capabilities:
301301
add: []
302+
drop: []
302303
`

server/src/main.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,7 @@ async function bootstrap() {
3030
cors: true,
3131
});
3232

33-
//DatabaseService.RunMigrations();
34-
//DatabaseService.CreateAdminUser();
33+
await DatabaseService.DBinit();
3534

3635
app.use(
3736
helmet({

0 commit comments

Comments
 (0)