diff options
author | Chocobozzz <me@florianbigard.com> | 2023-07-12 10:53:46 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2023-07-12 10:56:07 +0200 |
commit | d959b763f089ed4c1087aa4aeb824a8ef6743111 (patch) | |
tree | f4b5e77757fde022c91e415906bcf4619f8ec31c | |
parent | 88cde4392a27d5d37685a471f9bf83d537282c43 (diff) | |
download | PeerTube-d959b763f089ed4c1087aa4aeb824a8ef6743111.tar.gz PeerTube-d959b763f089ed4c1087aa4aeb824a8ef6743111.tar.zst PeerTube-d959b763f089ed4c1087aa4aeb824a8ef6743111.zip |
Avoid duplicate runner names
-rw-r--r-- | server/initializers/constants.ts | 2 | ||||
-rw-r--r-- | server/initializers/migrations/0795-duplicate-runner-name.ts | 24 | ||||
-rw-r--r-- | server/middlewares/validators/runners/runners.ts | 9 | ||||
-rw-r--r-- | server/models/runner/runner.ts | 12 | ||||
-rw-r--r-- | server/tests/api/check-params/runners.ts | 9 | ||||
-rw-r--r-- | shared/server-commands/runners/runners-command.ts | 3 |
6 files changed, 57 insertions, 2 deletions
diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts index 03ae94d35..e09f0e3c6 100644 --- a/server/initializers/constants.ts +++ b/server/initializers/constants.ts | |||
@@ -27,7 +27,7 @@ import { CONFIG, registerConfigChangedHandler } from './config' | |||
27 | 27 | ||
28 | // --------------------------------------------------------------------------- | 28 | // --------------------------------------------------------------------------- |
29 | 29 | ||
30 | const LAST_MIGRATION_VERSION = 790 | 30 | const LAST_MIGRATION_VERSION = 795 |
31 | 31 | ||
32 | // --------------------------------------------------------------------------- | 32 | // --------------------------------------------------------------------------- |
33 | 33 | ||
diff --git a/server/initializers/migrations/0795-duplicate-runner-name.ts b/server/initializers/migrations/0795-duplicate-runner-name.ts new file mode 100644 index 000000000..dd15a8157 --- /dev/null +++ b/server/initializers/migrations/0795-duplicate-runner-name.ts | |||
@@ -0,0 +1,24 @@ | |||
1 | import * as Sequelize from 'sequelize' | ||
2 | |||
3 | async function up (utils: { | ||
4 | transaction: Sequelize.Transaction | ||
5 | queryInterface: Sequelize.QueryInterface | ||
6 | sequelize: Sequelize.Sequelize | ||
7 | }): Promise<void> { | ||
8 | const { transaction } = utils | ||
9 | |||
10 | const query = 'DELETE FROM "runner" r1 ' + | ||
11 | 'USING (SELECT MIN(id) as id, "name" FROM "runner" GROUP BY "name" HAVING COUNT(*) > 1) r2 ' + | ||
12 | 'WHERE r1."name" = r2."name" AND r1.id <> r2.id' | ||
13 | |||
14 | await utils.sequelize.query(query, { transaction }) | ||
15 | } | ||
16 | |||
17 | function down (options) { | ||
18 | throw new Error('Not implemented.') | ||
19 | } | ||
20 | |||
21 | export { | ||
22 | up, | ||
23 | down | ||
24 | } | ||
diff --git a/server/middlewares/validators/runners/runners.ts b/server/middlewares/validators/runners/runners.ts index 71a1275d2..4d4d79b4c 100644 --- a/server/middlewares/validators/runners/runners.ts +++ b/server/middlewares/validators/runners/runners.ts | |||
@@ -35,6 +35,15 @@ const registerRunnerValidator = [ | |||
35 | }) | 35 | }) |
36 | } | 36 | } |
37 | 37 | ||
38 | const existing = await RunnerModel.loadByName(body.name) | ||
39 | if (existing) { | ||
40 | return res.fail({ | ||
41 | status: HttpStatusCode.BAD_REQUEST_400, | ||
42 | message: 'This runner name already exists on this instance', | ||
43 | tags | ||
44 | }) | ||
45 | } | ||
46 | |||
38 | res.locals.runnerRegistrationToken = runnerRegistrationToken | 47 | res.locals.runnerRegistrationToken = runnerRegistrationToken |
39 | 48 | ||
40 | return next() | 49 | return next() |
diff --git a/server/models/runner/runner.ts b/server/models/runner/runner.ts index 1ef0018b4..4d07707d8 100644 --- a/server/models/runner/runner.ts +++ b/server/models/runner/runner.ts | |||
@@ -16,6 +16,10 @@ import { CONSTRAINTS_FIELDS } from '@server/initializers/constants' | |||
16 | }, | 16 | }, |
17 | { | 17 | { |
18 | fields: [ 'runnerRegistrationTokenId' ] | 18 | fields: [ 'runnerRegistrationTokenId' ] |
19 | }, | ||
20 | { | ||
21 | fields: [ 'name' ], | ||
22 | unique: true | ||
19 | } | 23 | } |
20 | ] | 24 | ] |
21 | }) | 25 | }) |
@@ -74,6 +78,14 @@ export class RunnerModel extends Model<Partial<AttributesOnly<RunnerModel>>> { | |||
74 | return RunnerModel.findOne(query) | 78 | return RunnerModel.findOne(query) |
75 | } | 79 | } |
76 | 80 | ||
81 | static loadByName (name: string) { | ||
82 | const query = { | ||
83 | where: { name } | ||
84 | } | ||
85 | |||
86 | return RunnerModel.findOne(query) | ||
87 | } | ||
88 | |||
77 | static listForApi (options: { | 89 | static listForApi (options: { |
78 | start: number | 90 | start: number |
79 | count: number | 91 | count: number |
diff --git a/server/tests/api/check-params/runners.ts b/server/tests/api/check-params/runners.ts index 4ba90802f..7d70c412e 100644 --- a/server/tests/api/check-params/runners.ts +++ b/server/tests/api/check-params/runners.ts | |||
@@ -177,6 +177,15 @@ describe('Test managing runners', function () { | |||
177 | 177 | ||
178 | toDeleteId = id | 178 | toDeleteId = id |
179 | }) | 179 | }) |
180 | |||
181 | it('Should fail with the same runner name', async function () { | ||
182 | await server.runners.register({ | ||
183 | name, | ||
184 | description: 'super description', | ||
185 | registrationToken, | ||
186 | expectedStatus: HttpStatusCode.BAD_REQUEST_400 | ||
187 | }) | ||
188 | }) | ||
180 | }) | 189 | }) |
181 | 190 | ||
182 | describe('Delete', function () { | 191 | describe('Delete', function () { |
diff --git a/shared/server-commands/runners/runners-command.ts b/shared/server-commands/runners/runners-command.ts index ca9a1d7a3..b0083e841 100644 --- a/shared/server-commands/runners/runners-command.ts +++ b/shared/server-commands/runners/runners-command.ts | |||
@@ -1,4 +1,5 @@ | |||
1 | import { pick } from '@shared/core-utils' | 1 | import { pick } from '@shared/core-utils' |
2 | import { buildUUID } from '@shared/extra-utils' | ||
2 | import { HttpStatusCode, RegisterRunnerBody, RegisterRunnerResult, ResultList, Runner, UnregisterRunnerBody } from '@shared/models' | 3 | import { HttpStatusCode, RegisterRunnerBody, RegisterRunnerResult, ResultList, Runner, UnregisterRunnerBody } from '@shared/models' |
3 | import { unwrapBody } from '../requests' | 4 | import { unwrapBody } from '../requests' |
4 | import { AbstractCommand, OverrideCommandOptions } from '../shared' | 5 | import { AbstractCommand, OverrideCommandOptions } from '../shared' |
@@ -68,7 +69,7 @@ export class RunnersCommand extends AbstractCommand { | |||
68 | const { data } = await this.server.runnerRegistrationTokens.list({ sort: 'createdAt' }) | 69 | const { data } = await this.server.runnerRegistrationTokens.list({ sort: 'createdAt' }) |
69 | 70 | ||
70 | const { runnerToken } = await this.register({ | 71 | const { runnerToken } = await this.register({ |
71 | name: 'runner', | 72 | name: 'runner ' + buildUUID(), |
72 | registrationToken: data[0].registrationToken | 73 | registrationToken: data[0].registrationToken |
73 | }) | 74 | }) |
74 | 75 | ||