package de.is24.infrastructure.gridfs.http.web.controller; import de.is24.infrastructure.gridfs.http.domain.yum.YumPackageReducedView; import de.is24.infrastructure.gridfs.http.maintenance.MaintenanceService; import de.is24.infrastructure.gridfs.http.repos.RepoService; import de.is24.infrastructure.gridfs.http.storage.FileStorageItem; import de.is24.infrastructure.gridfs.http.storage.FileStorageService; import de.is24.util.monitoring.spring.TimeMeasurement; import org.bson.types.ObjectId; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.servlet.ModelAndView; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import static org.springframework.http.HttpStatus.ACCEPTED; import static org.springframework.http.HttpStatus.NO_CONTENT; import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; import static org.springframework.http.MediaType.TEXT_HTML_VALUE; import static org.springframework.web.bind.annotation.RequestMethod.DELETE; import static org.springframework.web.bind.annotation.RequestMethod.GET; @Controller @RequestMapping("/maintenance") @TimeMeasurement public class MaintenanceController { private final MaintenanceService maintenanceService; private final RepoService repoService; private final FileStorageService fileStorageService; /* for AOP autoproxying */ protected MaintenanceController() { maintenanceService = null; repoService = null; fileStorageService = null; } @Autowired public MaintenanceController(MaintenanceService maintenanceService, RepoService repoService, FileStorageService fileStorageService) { this.maintenanceService = maintenanceService; this.repoService = repoService; this.fileStorageService = fileStorageService; } @RequestMapping(method = GET, produces = TEXT_HTML_VALUE) @TimeMeasurement public ModelAndView showMaintenaceOptions() { Map<String, Object> model = prepareModel(); return new ModelAndView("maintenanceOptions", model); } private Map<String, Object> prepareModel() { Map<String, Object> model = new HashMap<>(); model.put("viewName", "maintenance"); model.put("error", Boolean.FALSE); model.put("propagatableSourceRepoInvalid", Boolean.FALSE); model.put("propagatableTargetRepoInvalid", Boolean.FALSE); model.put("obsoleteSourceRepoInvalid", Boolean.FALSE); model.put("obsoleteTargetRepoInvalid", Boolean.FALSE); return model; } @RequestMapping(value = "/obsolete", method = GET, produces = TEXT_HTML_VALUE) @TimeMeasurement public ModelAndView getObsoleteRPMsAsHtml(@RequestParam(value = "targetRepo", required = true) String targetRepo, @RequestParam(value = "sourceRepo", required = true) String sourceRepo) { Map<String, Object> model = prepareModel(); boolean reposAreVaid = validateRepos(model, "obsolete", sourceRepo, targetRepo); if (reposAreVaid) { model.put("obsoleteRPMs", maintenanceService.getObsoleteRPMs(targetRepo, sourceRepo)); model.put("targetRepo", targetRepo); model.put("sourceRepo", sourceRepo); return new ModelAndView("obsoleteRPMs", model); } else { model.put("error", Boolean.TRUE); model.put("errorMessage", "At least one of the given repos does not exist or is not a static repository"); model.put("obsoleteTargetRepo", targetRepo); model.put("obsoleteSourceRepo", sourceRepo); return new ModelAndView("maintenanceOptions", model); } } @RequestMapping( value = "/obsolete", method = GET, produces = APPLICATION_JSON_VALUE, headers = "Accept=application/json" ) @ResponseBody @TimeMeasurement public Set<YumPackageReducedView> getObsoletePRMsAsJson( @RequestParam(value = "targetRepo", required = true) String targetRepo, @RequestParam(value = "sourceRepo", required = true) String sourceRepo) { return maintenanceService.getObsoleteRPMs(targetRepo, sourceRepo); } @RequestMapping(value = "/obsolete", method = DELETE) @ResponseStatus(ACCEPTED) public void deleteObsoletePRMs(@RequestParam(value = "targetRepo", required = true) String targetRepo, @RequestParam(value = "sourceRepo", required = true) String sourceRepo) { maintenanceService.triggerDeletionOfObsoleteRPMs(targetRepo, sourceRepo); } @RequestMapping(value = "/propagatable", method = GET, produces = TEXT_HTML_VALUE) @TimeMeasurement public ModelAndView getPropagatableRPMsAsHtml( @RequestParam(value = "targetRepo", required = true) String targetRepo, @RequestParam(value = "sourceRepo", required = true) String sourceRepo) { Map<String, Object> model = prepareModel(); boolean reposAreVaid = validateRepos(model, "propagatable", sourceRepo, targetRepo); if (reposAreVaid) { model.put("targetRepo", targetRepo); model.put("sourceRepo", sourceRepo); model.put("propagatableRPMs", maintenanceService.getPropagatableRPMs(targetRepo, sourceRepo)); return new ModelAndView("propagatableRPMs", model); } else { model.put("error", Boolean.TRUE); model.put("errorMessage", "At least one of the given repos does not exist or is not a static repository"); model.put("propagatableTargetRepo", targetRepo); model.put("propagatableSourceRepo", sourceRepo); return new ModelAndView("maintenanceOptions", model); } } @RequestMapping( value = "/propagatable", method = GET, produces = APPLICATION_JSON_VALUE, headers = "Accept=application/json" ) @ResponseBody @TimeMeasurement public Set<YumPackageReducedView> getPropagatablePRMsAsJson( @RequestParam(value = "targetRepo", required = true) String targetRepo, @RequestParam(value = "sourceRepo", required = true) String sourceRepo) { return maintenanceService.getPropagatableRPMs(targetRepo, sourceRepo); } @RequestMapping( value = "/consistency/entries", method = GET, produces = APPLICATION_JSON_VALUE, headers = "Accept=application/json" ) @ResponseBody @TimeMeasurement public Map<ObjectId, YumPackageReducedView> getYumEntriesWithoutGridFsFile() { return maintenanceService.getYumEntriesWithoutAssociatedFiles(); } @RequestMapping( value = "/consistency/entries", method = DELETE, produces = APPLICATION_JSON_VALUE, headers = "Accept=application/json" ) @ResponseBody @TimeMeasurement public Map<ObjectId, YumPackageReducedView> deleteYumEntriesWithoutGridFsFile() { return maintenanceService.deleteYumEntriesWithoutAssociatedFiles(); } @RequestMapping( value = "/consistency/files", method = GET, produces = APPLICATION_JSON_VALUE, headers = "Accept=application/json" ) @ResponseBody @TimeMeasurement public Set<FileStorageItem> getFilesWithoutYumEntries() { return maintenanceService.getFilesWithoutYumEntry(); } @RequestMapping( value = "/corrupt-data/files", method = GET, produces = APPLICATION_JSON_VALUE, headers = "Accept=application/json" ) @ResponseBody @TimeMeasurement public List<FileStorageItem> getCorruptFiles() { return fileStorageService.getCorruptFiles(); } @RequestMapping( value = "/corrupt-data/files", method = DELETE, produces = APPLICATION_JSON_VALUE, headers = "Accept=application/json" ) @ResponseStatus(NO_CONTENT) @TimeMeasurement public void deleteCorruptFiles() { fileStorageService.deleteCorruptFiles(); } private boolean validateRepos(Map<String, Object> model, String prefix, String sourceRepo, String targetRepo) { boolean okay = true; if (!repoService.staticRepoExists(sourceRepo)) { okay = false; model.put(prefix + "SourceRepoInvalid", Boolean.TRUE); } if (!repoService.staticRepoExists(targetRepo)) { okay = false; model.put(prefix + "TargetRepoInvalid", Boolean.TRUE); } return okay; } }