diff --git a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/urlfactory/URLFactoryBuilder.java b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/urlfactory/URLFactoryBuilder.java index 02c51aa0f7..498a3e4cfd 100644 --- a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/urlfactory/URLFactoryBuilder.java +++ b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/urlfactory/URLFactoryBuilder.java @@ -12,6 +12,7 @@ package org.eclipse.che.api.factory.server.urlfactory; import static com.google.common.base.Strings.isNullOrEmpty; +import static java.lang.String.format; import static org.eclipse.che.api.factory.server.DevfileToApiExceptionMapper.toApiException; import static org.eclipse.che.api.factory.shared.Constants.CURRENT_VERSION; import static org.eclipse.che.api.workspace.server.devfile.Constants.CURRENT_API_VERSION; @@ -62,6 +63,7 @@ public class URLFactoryBuilder { private final String defaultCheEditor; private final String defaultChePlugins; + private final boolean devWorskspacesEnabled; private final DevfileParser devfileParser; private final DevfileVersionDetector devfileVersionDetector; @@ -69,10 +71,12 @@ public class URLFactoryBuilder { public URLFactoryBuilder( @Named("che.factory.default_editor") String defaultCheEditor, @Nullable @Named("che.factory.default_plugins") String defaultChePlugins, + @Named("che.devworkspaces.enabled") boolean devWorskspacesEnabled, DevfileParser devfileParser, DevfileVersionDetector devfileVersionDetector) { this.defaultCheEditor = defaultCheEditor; this.defaultChePlugins = defaultChePlugins; + this.devWorskspacesEnabled = devWorskspacesEnabled; this.devfileParser = devfileParser; this.devfileVersionDetector = devfileVersionDetector; } @@ -156,11 +160,16 @@ public class URLFactoryBuilder { .withDevfile(DtoConverter.asDto(devfile)) .withSource(location.filename().isPresent() ? location.filename().get() : null); - } else { + } else if (devWorskspacesEnabled) { return newDto(FactoryDevfileV2Dto.class) .withV(CURRENT_VERSION) .withDevfile(devfileParser.convertYamlToMap(devfileJson)) .withSource(location.filename().isPresent() ? location.filename().get() : null); + } else { + throw new DevfileException( + format( + "Devfile of version %s cannot be used in current deployment, because of DevWorkspaces feature is disabled. Only '1.0.0' version devfiles are supported for such installations.", + devfileVersionDetector.devfileVersion(devfileJson))); } } diff --git a/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/DefaultFactoryParameterResolverTest.java b/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/DefaultFactoryParameterResolverTest.java index cdbb4149bf..3585ae5a0e 100644 --- a/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/DefaultFactoryParameterResolverTest.java +++ b/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/DefaultFactoryParameterResolverTest.java @@ -81,7 +81,8 @@ public class DefaultFactoryParameterResolverTest { DevfileParser devfileParser = new DevfileParser(validator, integrityValidator); URLFactoryBuilder factoryBuilder = - new URLFactoryBuilder("editor", "plugin", devfileParser, new DevfileVersionDetector()); + new URLFactoryBuilder( + "editor", "plugin", false, devfileParser, new DevfileVersionDetector()); DefaultFactoryParameterResolver res = new DefaultFactoryParameterResolver(factoryBuilder, urlFetcher); diff --git a/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/urlfactory/URLFactoryBuilderTest.java b/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/urlfactory/URLFactoryBuilderTest.java index fc7fa5dcdd..c0308d78a3 100644 --- a/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/urlfactory/URLFactoryBuilderTest.java +++ b/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/urlfactory/URLFactoryBuilderTest.java @@ -38,6 +38,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; import org.eclipse.che.api.core.ApiException; +import org.eclipse.che.api.core.BadRequestException; import org.eclipse.che.api.core.ServerException; import org.eclipse.che.api.core.UnauthorizedException; import org.eclipse.che.api.core.rest.shared.dto.ExtendedError; @@ -91,7 +92,8 @@ public class URLFactoryBuilderTest { @BeforeMethod public void setUp() { this.urlFactoryBuilder = - new URLFactoryBuilder(defaultEditor, defaultPlugin, devfileParser, devfileVersionDetector); + new URLFactoryBuilder( + defaultEditor, defaultPlugin, true, devfileParser, devfileVersionDetector); } @Test @@ -222,6 +224,33 @@ public class URLFactoryBuilderTest { assertEquals(((FactoryDevfileV2Dto) factory).getDevfile(), devfileAsMap); } + @Test( + expectedExceptions = BadRequestException.class, + expectedExceptionsMessageRegExp = + "Error occurred during creation a workspace from devfile located at `http://foo-location/`. Cause: Devfile of version 2.0.1 cannot be used in current deployment, because of DevWorkspaces feature is disabled. Only '1.0.0' version devfiles are supported for such installations.") + public void testShouldThrowExceptionOnDevfileV2WithDevworkspacesDisabled() + throws ApiException, DevfileException { + String myLocation = "http://foo-location/"; + Map devfileAsMap = Map.of("hello", "there", "how", "are", "you", "?"); + + JsonNode devfile = new ObjectNode(JsonNodeFactory.instance); + when(devfileParser.parseYamlRaw(anyString())).thenReturn(devfile); + when(devfileParser.convertYamlToMap(devfile)).thenReturn(devfileAsMap); + when(devfileVersionDetector.devfileMajorVersion(devfile)).thenReturn(2); + when(devfileVersionDetector.devfileVersion(devfile)).thenReturn("2.0.1"); + + URLFactoryBuilder localUrlFactoryBuilder = + new URLFactoryBuilder( + defaultEditor, defaultPlugin, false, devfileParser, devfileVersionDetector); + + localUrlFactoryBuilder + .createFactoryFromDevfile( + new DefaultFactoryUrl().withDevfileFileLocation(myLocation), + s -> myLocation + ".list", + emptyMap()) + .get(); + } + @DataProvider public Object[][] devfiles() { final String NAME = "name"; diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/devfile/DevfileParser.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/devfile/DevfileParser.java index 8f2527cb60..4d9b6cf02e 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/devfile/DevfileParser.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/devfile/DevfileParser.java @@ -89,7 +89,7 @@ public class DevfileParser { */ public DevfileImpl parseYaml(String devfileContent) throws DevfileFormatException { try { - return parse(parseYamlRaw(devfileContent, false), yamlMapper, emptyMap()); + return parse(parseYamlRaw(devfileContent), yamlMapper, emptyMap()); } catch (OverrideParameterException e) { // should never happen as we send empty overrides map throw new RuntimeException(e.getMessage()); @@ -97,28 +97,18 @@ public class DevfileParser { } /** - * Tries to parse given `yaml` into {@link JsonNode} and validates it with devfile schema. + * Tries to parse given `yaml` into {@link JsonNode}. * * @param yaml to parse * @return parsed yaml - * @throws DevfileFormatException if given yaml is empty or is not valid devfile + * @throws DevfileFormatException if given yaml is empty or invalid */ public JsonNode parseYamlRaw(String yaml) throws DevfileFormatException { - return parseYamlRaw(yaml, true); - } - - private JsonNode parseYamlRaw(String yaml, boolean validate) throws DevfileFormatException { try { - JsonNode devfileJson = - Optional.ofNullable(yamlMapper.readTree(yaml)) - .orElseThrow( - () -> - new DevfileFormatException( - "Unable to parse Devfile - provided source is empty")); - if (validate) { - schemaValidator.validate(devfileJson); - } - return devfileJson; + return Optional.ofNullable(yamlMapper.readTree(yaml)) + .orElseThrow( + () -> + new DevfileFormatException("Unable to parse Devfile - provided source is empty")); } catch (JsonProcessingException jpe) { throw new DevfileFormatException("Can't parse devfile yaml.", jpe); } @@ -130,7 +120,8 @@ public class DevfileParser { * @param devfileJson json with devfile content * @return devfile in simple Map structure */ - public Map convertYamlToMap(JsonNode devfileJson) { + public Map convertYamlToMap(JsonNode devfileJson) throws DevfileFormatException { + schemaValidator.validate(devfileJson); return yamlMapper.convertValue(devfileJson, new TypeReference<>() {}); } diff --git a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/devfile/DevfileParserTest.java b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/devfile/DevfileParserTest.java index ec5811e017..38a71d67a3 100644 --- a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/devfile/DevfileParserTest.java +++ b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/devfile/DevfileParserTest.java @@ -24,6 +24,7 @@ import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; @@ -83,9 +84,7 @@ public class DevfileParserTest { @Test public void testParseRaw() throws DevfileFormatException { JsonNode parsed = devfileParser.parseYamlRaw(DEVFILE_YAML_CONTENT); - assertEquals(parsed, devfileJsonNode); - verify(schemaValidator).validate(eq(devfileJsonNode)); } @Test(expectedExceptions = DevfileFormatException.class) @@ -200,4 +199,14 @@ public class DevfileParserTest { // when devfileParser.parseJson(DEVFILE_YAML_CONTENT); } + + @Test + public void shouldConvertYamlToMapAndValidate() throws Exception { + // when + devfileParser.convertYamlToMap(devfileJsonNode); + + // then + verify(schemaValidator).validate(eq(devfileJsonNode)); + verify(yamlMapper).convertValue(eq(devfileJsonNode), any(TypeReference.class)); + } }