Skip to content
Snippets Groups Projects
Commit bf967633 authored by michael.minelli's avatar michael.minelli
Browse files

Assignment/Exercise creation => Add error management and timeout on creation

parent 871a0aab
No related branches found
No related tags found
No related merge requests found
Pipeline #26769 passed
...@@ -23,6 +23,8 @@ import GitlabVisibility from '../shared/types/Gitlab/GitlabVisibil ...@@ -23,6 +23,8 @@ import GitlabVisibility from '../shared/types/Gitlab/GitlabVisibil
import fs from 'fs'; import fs from 'fs';
import path from 'path'; import path from 'path';
import SharedAssignmentHelper from '../shared/helpers/Dojo/SharedAssignmentHelper'; import SharedAssignmentHelper from '../shared/helpers/Dojo/SharedAssignmentHelper';
import GlobalHelper from '../helpers/GlobalHelper';
import DojoStatusCode from '../shared/types/Dojo/DojoStatusCode';
class AssignmentRoutes implements RoutesManager { class AssignmentRoutes implements RoutesManager {
...@@ -86,11 +88,10 @@ class AssignmentRoutes implements RoutesManager { ...@@ -86,11 +88,10 @@ class AssignmentRoutes implements RoutesManager {
let repository: GitlabRepository; let repository: GitlabRepository;
try { try {
repository = await GitlabManager.createRepository(params.name, Config.assignment.default.description.replace('{{ASSIGNMENT_NAME}}', params.name), Config.assignment.default.visibility, Config.assignment.default.initReadme, Config.gitlab.group.assignments, Config.assignment.default.sharedRunnersEnabled, Config.assignment.default.wikiEnabled, params.template); repository = await GitlabManager.createRepository(params.name, Config.assignment.default.description.replace('{{ASSIGNMENT_NAME}}', params.name), Config.assignment.default.visibility, Config.assignment.default.initReadme, Config.gitlab.group.assignments, Config.assignment.default.sharedRunnersEnabled, Config.assignment.default.wikiEnabled, params.template);
await GitlabManager.protectBranch(repository.id, '*', true, GitlabAccessLevel.DEVELOPER, GitlabAccessLevel.DEVELOPER, GitlabAccessLevel.OWNER);
await GitlabManager.addRepositoryBadge(repository.id, Config.gitlab.badges.pipeline.link, Config.gitlab.badges.pipeline.imageUrl, 'Pipeline Status');
} catch ( error ) { } catch ( error ) {
logger.error('Repo creation error');
logger.error(error);
if ( error instanceof AxiosError ) { if ( error instanceof AxiosError ) {
if ( error.response?.data.message.name && error.response.data.message.name == 'has already been taken' ) { if ( error.response?.data.message.name && error.response.data.message.name == 'has already been taken' ) {
return res.status(StatusCodes.CONFLICT).send(); return res.status(StatusCodes.CONFLICT).send();
...@@ -99,27 +100,32 @@ class AssignmentRoutes implements RoutesManager { ...@@ -99,27 +100,32 @@ class AssignmentRoutes implements RoutesManager {
return res.status(error.response?.status ?? HttpStatusCode.InternalServerError).send(); return res.status(error.response?.status ?? HttpStatusCode.InternalServerError).send();
} }
logger.error(error);
return res.status(StatusCodes.INTERNAL_SERVER_ERROR).send(); return res.status(StatusCodes.INTERNAL_SERVER_ERROR).send();
} }
await new Promise(resolve => setTimeout(resolve, Config.gitlab.repository.timeoutAfterCreation));
try { try {
await GitlabManager.createFile(repository.id, '.gitlab-ci.yml', fs.readFileSync(path.join(__dirname, '../../assets/assignment_gitlab_ci.yml'), 'base64'), 'Add .gitlab-ci.yml (DO NOT MODIFY THIS FILE)'); await GitlabManager.protectBranch(repository.id, '*', true, GitlabAccessLevel.DEVELOPER, GitlabAccessLevel.DEVELOPER, GitlabAccessLevel.OWNER);
} catch ( error ) {
logger.error(error);
if ( error instanceof AxiosError ) { await GitlabManager.addRepositoryBadge(repository.id, Config.gitlab.badges.pipeline.link, Config.gitlab.badges.pipeline.imageUrl, 'Pipeline Status');
return res.status(error.response?.status ?? HttpStatusCode.InternalServerError).send(); } catch ( error ) {
return GlobalHelper.repositoryCreationError('Repo params error', error, req, res, DojoStatusCode.ASSIGNMENT_CREATION_GITLAB_ERROR, DojoStatusCode.ASSIGNMENT_CREATION_INTERNAL_ERROR, repository);
} }
return res.status(StatusCodes.INTERNAL_SERVER_ERROR).send(); try {
await GitlabManager.createFile(repository.id, '.gitlab-ci.yml', fs.readFileSync(path.join(__dirname, '../../assets/assignment_gitlab_ci.yml'), 'base64'), 'Add .gitlab-ci.yml (DO NOT MODIFY THIS FILE)');
} catch ( error ) {
return GlobalHelper.repositoryCreationError('CI file error', error, req, res, DojoStatusCode.ASSIGNMENT_CREATION_GITLAB_ERROR, DojoStatusCode.ASSIGNMENT_CREATION_INTERNAL_ERROR, repository);
} }
try { try {
await Promise.all(params.members.map(member => member.id).map(async (memberId: number): Promise<GitlabMember | false> => { await Promise.all(params.members.map(member => member.id).map(async (memberId: number): Promise<GitlabMember | false> => {
try { try {
return await GitlabManager.addRepositoryMember(repository.id, memberId, GitlabAccessLevel.DEVELOPER); return await GitlabManager.addRepositoryMember(repository.id, memberId, GitlabAccessLevel.DEVELOPER);
} catch ( e ) { } catch ( error ) {
logger.error('Add member error');
logger.error(error);
return false; return false;
} }
})); }));
...@@ -150,12 +156,7 @@ class AssignmentRoutes implements RoutesManager { ...@@ -150,12 +156,7 @@ class AssignmentRoutes implements RoutesManager {
return req.session.sendResponse(res, StatusCodes.OK, assignment); return req.session.sendResponse(res, StatusCodes.OK, assignment);
} catch ( error ) { } catch ( error ) {
if ( error instanceof AxiosError ) { return GlobalHelper.repositoryCreationError('DB error', error, req, res, DojoStatusCode.ASSIGNMENT_CREATION_GITLAB_ERROR, DojoStatusCode.ASSIGNMENT_CREATION_INTERNAL_ERROR, repository);
return res.status(error.response?.status ?? HttpStatusCode.InternalServerError).send();
}
logger.error(error);
return res.status(StatusCodes.INTERNAL_SERVER_ERROR).send();
} }
} }
......
...@@ -9,7 +9,7 @@ import GitlabUser from '../shared/types/Gitlab/GitlabUser'; ...@@ -9,7 +9,7 @@ import GitlabUser from '../shared/types/Gitlab/GitlabUser';
import GitlabManager from '../managers/GitlabManager'; import GitlabManager from '../managers/GitlabManager';
import Config from '../config/Config'; import Config from '../config/Config';
import GitlabRepository from '../shared/types/Gitlab/GitlabRepository'; import GitlabRepository from '../shared/types/Gitlab/GitlabRepository';
import { AxiosError, HttpStatusCode } from 'axios'; import { AxiosError } from 'axios';
import logger from '../shared/logging/WinstonLogger'; import logger from '../shared/logging/WinstonLogger';
import DojoValidators from '../helpers/DojoValidators'; import DojoValidators from '../helpers/DojoValidators';
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
...@@ -27,6 +27,8 @@ import fs from 'fs'; ...@@ -27,6 +27,8 @@ import fs from 'fs';
import path from 'path'; import path from 'path';
import AssignmentFile from '../shared/types/Dojo/AssignmentFile'; import AssignmentFile from '../shared/types/Dojo/AssignmentFile';
import ExerciseResultsFile from '../shared/types/Dojo/ExerciseResultsFile'; import ExerciseResultsFile from '../shared/types/Dojo/ExerciseResultsFile';
import DojoStatusCode from '../shared/types/Dojo/DojoStatusCode';
import GlobalHelper from '../helpers/GlobalHelper';
class ExerciseRoutes implements RoutesManager { class ExerciseRoutes implements RoutesManager {
...@@ -95,50 +97,55 @@ class ExerciseRoutes implements RoutesManager { ...@@ -95,50 +97,55 @@ class ExerciseRoutes implements RoutesManager {
do { do {
try { try {
repository = await GitlabManager.forkRepository((assignment.gitlabCreationInfo as unknown as GitlabRepository).id, this.getExerciseName(assignment, params.members, suffix), this.getExercisePath(req.boundParams.assignment!, exerciseId), Config.exercise.default.description.replace('{{ASSIGNMENT_NAME}}', assignment.name), Config.exercise.default.visibility, Config.gitlab.group.exercises); repository = await GitlabManager.forkRepository((assignment.gitlabCreationInfo as unknown as GitlabRepository).id, this.getExerciseName(assignment, params.members, suffix), this.getExercisePath(req.boundParams.assignment!, exerciseId), Config.exercise.default.description.replace('{{ASSIGNMENT_NAME}}', assignment.name), Config.exercise.default.visibility, Config.gitlab.group.exercises);
await GitlabManager.protectBranch(repository.id, '*', false, GitlabAccessLevel.DEVELOPER, GitlabAccessLevel.DEVELOPER, GitlabAccessLevel.OWNER);
await GitlabManager.addRepositoryVariable(repository.id, 'DOJO_EXERCISE_ID', exerciseId, false, true);
await GitlabManager.addRepositoryVariable(repository.id, 'DOJO_SECRET', secret, false, true);
await GitlabManager.addRepositoryVariable(repository.id, 'DOJO_RESULTS_FOLDER', Config.exercise.pipelineResultsFolder, false, false);
await GitlabManager.addRepositoryBadge(repository.id, Config.gitlab.badges.pipeline.link, Config.gitlab.badges.pipeline.imageUrl, 'Pipeline Status');
break; break;
} catch ( error ) { } catch ( error ) {
logger.error('Repo creation error');
logger.error(error);
if ( error instanceof AxiosError ) { if ( error instanceof AxiosError ) {
if ( error.response?.data.message.name && error.response.data.message.name == 'has already been taken' ) { if ( error.response?.data.message.name && error.response.data.message.name == 'has already been taken' ) {
suffix++; suffix++;
} else { } else {
return res.status(error.response?.status ?? HttpStatusCode.InternalServerError).send(); return req.session.sendResponse(res, StatusCodes.INTERNAL_SERVER_ERROR, {}, 'Unknown gitlab error while forking repository', DojoStatusCode.EXERCISE_CREATION_GITLAB_ERROR);
} }
} else { } else {
return res.status(StatusCodes.INTERNAL_SERVER_ERROR).send(); return req.session.sendResponse(res, StatusCodes.INTERNAL_SERVER_ERROR, {}, 'Unknown error while forking repository', DojoStatusCode.EXERCISE_CREATION_INTERNAL_ERROR);
} }
} }
} while ( suffix < Config.exercise.maxSameName ); } while ( suffix < Config.exercise.maxSameName );
if ( suffix >= Config.exercise.maxSameName ) { if ( suffix >= Config.exercise.maxSameName ) {
logger.error('Max exercise with same name reached');
return res.status(StatusCodes.INSUFFICIENT_SPACE_ON_RESOURCE).send(); return res.status(StatusCodes.INSUFFICIENT_SPACE_ON_RESOURCE).send();
} }
await new Promise(resolve => setTimeout(resolve, Config.gitlab.repository.timeoutAfterCreation));
try { try {
await GitlabManager.createFile(repository.id, '.gitlab-ci.yml', fs.readFileSync(path.join(__dirname, '../../assets/exercise_gitlab_ci.yml'), 'base64'), 'Add .gitlab-ci.yml (DO NOT MODIFY THIS FILE)'); await GitlabManager.protectBranch(repository.id, '*', false, GitlabAccessLevel.DEVELOPER, GitlabAccessLevel.DEVELOPER, GitlabAccessLevel.OWNER);
} catch ( error ) {
logger.error(error);
if ( error instanceof AxiosError ) { await GitlabManager.addRepositoryVariable(repository.id, 'DOJO_EXERCISE_ID', exerciseId, false, true);
return res.status(error.response?.status ?? HttpStatusCode.InternalServerError).send(); await GitlabManager.addRepositoryVariable(repository.id, 'DOJO_SECRET', secret, false, true);
await GitlabManager.addRepositoryVariable(repository.id, 'DOJO_RESULTS_FOLDER', Config.exercise.pipelineResultsFolder, false, false);
await GitlabManager.addRepositoryBadge(repository.id, Config.gitlab.badges.pipeline.link, Config.gitlab.badges.pipeline.imageUrl, 'Pipeline Status');
} catch ( error ) {
return GlobalHelper.repositoryCreationError('Repo params error', error, req, res, DojoStatusCode.EXERCISE_CREATION_GITLAB_ERROR, DojoStatusCode.EXERCISE_CREATION_INTERNAL_ERROR, repository);
} }
return res.status(StatusCodes.INTERNAL_SERVER_ERROR).send(); try {
await GitlabManager.updateFile(repository.id, '.gitlab-ci.yml', fs.readFileSync(path.join(__dirname, '../../assets/exercise_gitlab_ci.yml'), 'base64'), 'Add .gitlab-ci.yml (DO NOT MODIFY THIS FILE)');
} catch ( error ) {
return GlobalHelper.repositoryCreationError('CI file update error', error, req, res, DojoStatusCode.EXERCISE_CREATION_GITLAB_ERROR, DojoStatusCode.EXERCISE_CREATION_INTERNAL_ERROR, repository);
} }
try { try {
await Promise.all([ ...new Set([ ...assignment.staff.map(user => user.id), ...params.members.map(member => member.id) ]) ].map(async (memberId: number): Promise<GitlabMember | false> => { await Promise.all([ ...new Set([ ...assignment.staff.map(user => user.id), ...params.members.map(member => member.id) ]) ].map(async (memberId: number): Promise<GitlabMember | false> => {
try { try {
return await GitlabManager.addRepositoryMember(repository.id, memberId, GitlabAccessLevel.DEVELOPER); return await GitlabManager.addRepositoryMember(repository.id, memberId, GitlabAccessLevel.DEVELOPER);
} catch ( e ) { } catch ( error ) {
logger.error('Add member error');
logger.error(error);
return false; return false;
} }
})); }));
...@@ -172,13 +179,7 @@ class ExerciseRoutes implements RoutesManager { ...@@ -172,13 +179,7 @@ class ExerciseRoutes implements RoutesManager {
return req.session.sendResponse(res, StatusCodes.OK, exercise); return req.session.sendResponse(res, StatusCodes.OK, exercise);
} catch ( error ) { } catch ( error ) {
logger.error(error); return GlobalHelper.repositoryCreationError('DB error', error, req, res, DojoStatusCode.EXERCISE_CREATION_GITLAB_ERROR, DojoStatusCode.EXERCISE_CREATION_INTERNAL_ERROR, repository);
if ( error instanceof AxiosError ) {
return res.status(error.response?.status ?? HttpStatusCode.InternalServerError).send();
}
return res.status(StatusCodes.INTERNAL_SERVER_ERROR).send();
} }
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment