diff --git a/src/main/java/de/tum/cit/aet/artemis/ArtemisApp.java b/src/main/java/de/tum/cit/aet/artemis/ArtemisApp.java index 11b1e7c67636..b56b0f82990d 100644 --- a/src/main/java/de/tum/cit/aet/artemis/ArtemisApp.java +++ b/src/main/java/de/tum/cit/aet/artemis/ArtemisApp.java @@ -18,13 +18,14 @@ import org.springframework.boot.info.GitProperties; import org.springframework.core.env.Environment; +import de.tum.cit.aet.artemis.core.config.LicenseConfiguration; import de.tum.cit.aet.artemis.core.config.ProgrammingLanguageConfiguration; import de.tum.cit.aet.artemis.core.config.TheiaConfiguration; import tech.jhipster.config.DefaultProfileUtil; import tech.jhipster.config.JHipsterConstants; @SpringBootApplication -@EnableConfigurationProperties({ LiquibaseProperties.class, ProgrammingLanguageConfiguration.class, TheiaConfiguration.class }) +@EnableConfigurationProperties({ LiquibaseProperties.class, ProgrammingLanguageConfiguration.class, TheiaConfiguration.class, LicenseConfiguration.class }) public class ArtemisApp { private static final Logger log = LoggerFactory.getLogger(ArtemisApp.class); diff --git a/src/main/java/de/tum/cit/aet/artemis/core/config/LicenseConfiguration.java b/src/main/java/de/tum/cit/aet/artemis/core/config/LicenseConfiguration.java new file mode 100644 index 000000000000..6ebe6709d2d1 --- /dev/null +++ b/src/main/java/de/tum/cit/aet/artemis/core/config/LicenseConfiguration.java @@ -0,0 +1,30 @@ +package de.tum.cit.aet.artemis.core.config; + +import static de.tum.cit.aet.artemis.core.config.Constants.PROFILE_CORE; + +import jakarta.annotation.Nullable; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Profile; + +@Profile(PROFILE_CORE) +@ConfigurationProperties(prefix = "artemis.licenses") +public class LicenseConfiguration { + + private final MatLabLicense matlab; + + public record MatLabLicense(String licenseServer) { + } + + public LicenseConfiguration(MatLabLicense matlab) { + this.matlab = matlab; + } + + @Nullable + public String getMatlabLicenseServer() { + if (matlab == null) { + return null; + } + return matlab.licenseServer(); + } +} diff --git a/src/main/java/de/tum/cit/aet/artemis/programming/service/LicenseService.java b/src/main/java/de/tum/cit/aet/artemis/programming/service/LicenseService.java new file mode 100644 index 000000000000..53c279aaf690 --- /dev/null +++ b/src/main/java/de/tum/cit/aet/artemis/programming/service/LicenseService.java @@ -0,0 +1,42 @@ +package de.tum.cit.aet.artemis.programming.service; + +import static de.tum.cit.aet.artemis.core.config.Constants.PROFILE_CORE; + +import java.util.Map; +import java.util.Objects; + +import jakarta.annotation.Nullable; + +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Service; + +import de.tum.cit.aet.artemis.core.config.LicenseConfiguration; +import de.tum.cit.aet.artemis.programming.domain.ProgrammingLanguage; +import de.tum.cit.aet.artemis.programming.domain.ProjectType; + +@Profile(PROFILE_CORE) +@Service +public class LicenseService { + + private final LicenseConfiguration licenseConfiguration; + + public LicenseService(LicenseConfiguration licenseConfiguration) { + this.licenseConfiguration = licenseConfiguration; + } + + public boolean isLicensed(ProgrammingLanguage programmingLanguage, @Nullable ProjectType projectType) { + if (programmingLanguage == ProgrammingLanguage.MATLAB && projectType == null) { + return licenseConfiguration.getMatlabLicenseServer() != null; + } + + return true; + } + + public Map getEnvironment(ProgrammingLanguage programmingLanguage, @Nullable ProjectType projectType) { + if (programmingLanguage == ProgrammingLanguage.MATLAB && projectType == null) { + return Map.of("MLM_LICENSE_FILE", Objects.requireNonNull(licenseConfiguration.getMatlabLicenseServer())); + } + + return Map.of(); + } +} diff --git a/src/main/java/de/tum/cit/aet/artemis/programming/service/ProgrammingExerciseBuildConfigService.java b/src/main/java/de/tum/cit/aet/artemis/programming/service/ProgrammingExerciseBuildConfigService.java index 9b243a289afa..b76dad4d4ab3 100644 --- a/src/main/java/de/tum/cit/aet/artemis/programming/service/ProgrammingExerciseBuildConfigService.java +++ b/src/main/java/de/tum/cit/aet/artemis/programming/service/ProgrammingExerciseBuildConfigService.java @@ -11,7 +11,6 @@ import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; -import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Service; @@ -21,6 +20,7 @@ import de.tum.cit.aet.artemis.buildagent.dto.DockerRunConfig; import de.tum.cit.aet.artemis.programming.domain.ProgrammingExerciseBuildConfig; import de.tum.cit.aet.artemis.programming.domain.ProgrammingLanguage; +import de.tum.cit.aet.artemis.programming.domain.ProjectType; @Profile(PROFILE_CORE) @Service @@ -30,8 +30,11 @@ public class ProgrammingExerciseBuildConfigService { private final ObjectMapper objectMapper = new ObjectMapper(); - @Value("${artemis.languages.matlab.license-server}") - private String matlabLicense; + private final LicenseService licenseService; + + public ProgrammingExerciseBuildConfigService(LicenseService licenseService) { + this.licenseService = licenseService; + } /** * Converts a JSON string representing Docker flags (in JSON format) @@ -52,49 +55,55 @@ public class ProgrammingExerciseBuildConfigService { public DockerRunConfig getDockerRunConfig(ProgrammingExerciseBuildConfig buildConfig) { DockerFlagsDTO dockerFlagsDTO = parseDockerFlags(buildConfig); - dockerFlagsDTO = addLanguageSpecificEnvironment(dockerFlagsDTO, buildConfig.getProgrammingExercise().getProgrammingLanguage()); + String network; + Map exerciseEnvironment; + if (dockerFlagsDTO != null) { + network = dockerFlagsDTO.network(); + exerciseEnvironment = dockerFlagsDTO.env(); + } + else { + network = null; + exerciseEnvironment = null; + } + + ProgrammingLanguage programmingLanguage = buildConfig.getProgrammingExercise().getProgrammingLanguage(); + ProjectType projectType = buildConfig.getProgrammingExercise().getProjectType(); + Map environment = addLanguageSpecificEnvironment(exerciseEnvironment, programmingLanguage, projectType); - return getDockerRunConfigFromParsedFlags(dockerFlagsDTO); + return createDockerRunConfig(network, environment); } @Nullable - private DockerFlagsDTO addLanguageSpecificEnvironment(DockerFlagsDTO dockerFlagsDTO, ProgrammingLanguage language) { - if (language == ProgrammingLanguage.MATLAB && matlabLicense != null) { - Map env; - String network; - if (dockerFlagsDTO != null) { - env = new HashMap<>(dockerFlagsDTO.env()); - network = dockerFlagsDTO.network(); - } - else { - env = new HashMap<>(); - network = null; - } - - env.put("MLM_LICENSE_FILE", matlabLicense); + private Map addLanguageSpecificEnvironment(@Nullable Map exerciseEnvironment, ProgrammingLanguage language, ProjectType projectType) { + Map licenseEnvironment = licenseService.getEnvironment(language, projectType); + if (licenseEnvironment.isEmpty()) { + return exerciseEnvironment; + } - dockerFlagsDTO = new DockerFlagsDTO(network, env); + Map env = new HashMap<>(licenseEnvironment); + if (exerciseEnvironment != null) { + env.putAll(exerciseEnvironment); } - return dockerFlagsDTO; + return env; } - DockerRunConfig getDockerRunConfigFromParsedFlags(DockerFlagsDTO dockerFlagsDTO) { - if (dockerFlagsDTO == null) { + DockerRunConfig createDockerRunConfig(String network, Map environmentMap) { + if (network == null && environmentMap == null) { return null; } - List env = new ArrayList<>(); - boolean isNetworkDisabled = dockerFlagsDTO.network() != null && dockerFlagsDTO.network().equals("none"); + List environmentStrings = new ArrayList<>(); + boolean isNetworkDisabled = network != null && network.equals("none"); - if (dockerFlagsDTO.env() != null) { - for (Map.Entry entry : dockerFlagsDTO.env().entrySet()) { + if (environmentMap != null) { + for (Map.Entry entry : environmentMap.entrySet()) { String key = entry.getKey(); String value = entry.getValue(); - env.add(key + "=" + value); + environmentStrings.add(key + "=" + value); } } - return new DockerRunConfig(isNetworkDisabled, env); + return new DockerRunConfig(isNetworkDisabled, environmentStrings); } /** diff --git a/src/main/java/de/tum/cit/aet/artemis/programming/service/ProgrammingExerciseService.java b/src/main/java/de/tum/cit/aet/artemis/programming/service/ProgrammingExerciseService.java index d85af7904c4c..4b948f63d2f1 100644 --- a/src/main/java/de/tum/cit/aet/artemis/programming/service/ProgrammingExerciseService.java +++ b/src/main/java/de/tum/cit/aet/artemis/programming/service/ProgrammingExerciseService.java @@ -1119,7 +1119,7 @@ public void validateDockerFlags(ProgrammingExercise programmingExercise) { } } - DockerRunConfig dockerRunConfig = programmingExerciseBuildConfigService.getDockerRunConfigFromParsedFlags(dockerFlagsDTO); + DockerRunConfig dockerRunConfig = programmingExerciseBuildConfigService.createDockerRunConfig(dockerFlagsDTO.network(), dockerFlagsDTO.env()); if (List.of(ProgrammingLanguage.SWIFT, ProgrammingLanguage.HASKELL).contains(programmingExercise.getProgrammingLanguage()) && dockerRunConfig.isNetworkDisabled()) { throw new BadRequestAlertException("This programming language does not support disabling the network access feature", "Exercise", "networkAccessNotSupported"); diff --git a/src/main/java/de/tum/cit/aet/artemis/programming/service/TemplateUpgradePolicyService.java b/src/main/java/de/tum/cit/aet/artemis/programming/service/TemplateUpgradePolicyService.java index 9e3248f8cf87..b77d5be04835 100644 --- a/src/main/java/de/tum/cit/aet/artemis/programming/service/TemplateUpgradePolicyService.java +++ b/src/main/java/de/tum/cit/aet/artemis/programming/service/TemplateUpgradePolicyService.java @@ -32,7 +32,8 @@ public TemplateUpgradePolicyService(JavaTemplateUpgradeService javaRepositoryUpg public TemplateUpgradeService getUpgradeService(ProgrammingLanguage programmingLanguage) { return switch (programmingLanguage) { case JAVA -> javaRepositoryUpgradeService; - case KOTLIN, PYTHON, C, HASKELL, VHDL, ASSEMBLER, SWIFT, OCAML, EMPTY, RUST, JAVASCRIPT, R, C_PLUS_PLUS, TYPESCRIPT, C_SHARP, GO, MATLAB -> defaultRepositoryUpgradeService; + case KOTLIN, PYTHON, C, HASKELL, VHDL, ASSEMBLER, SWIFT, OCAML, EMPTY, RUST, JAVASCRIPT, R, C_PLUS_PLUS, TYPESCRIPT, C_SHARP, GO, MATLAB -> + defaultRepositoryUpgradeService; case SQL, BASH, RUBY, POWERSHELL, ADA, DART, PHP -> throw new UnsupportedOperationException("Unsupported programming language: " + programmingLanguage); }; }