Skip to content

Commit 98bda3c

Browse files
Merge branch 'master' into bump-dependencies
# Conflicts: # pom.xml
2 parents 3d5a6bd + ad8971a commit 98bda3c

45 files changed

Lines changed: 639 additions & 209 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

multiapps-controller-api/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
<parent>
1111
<groupId>org.cloudfoundry.multiapps</groupId>
1212
<artifactId>multiapps-controller-parent</artifactId>
13-
<version>1.190.0-SNAPSHOT</version>
13+
<version>1.191.0-SNAPSHOT</version>
1414
</parent>
1515

1616
<dependencies>

multiapps-controller-client/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
<parent>
1010
<groupId>org.cloudfoundry.multiapps</groupId>
1111
<artifactId>multiapps-controller-parent</artifactId>
12-
<version>1.190.0-SNAPSHOT</version>
12+
<version>1.191.0-SNAPSHOT</version>
1313
</parent>
1414

1515
<dependencies>

multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/lib/domain/CloudServiceInstanceExtended.java

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
package org.cloudfoundry.multiapps.controller.client.lib.domain;
22

3-
import org.cloudfoundry.multiapps.common.Nullable;
4-
import org.immutables.value.Value;
5-
63
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
74
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
85
import com.sap.cloudfoundry.client.facade.domain.CloudServiceInstance;
6+
import org.cloudfoundry.multiapps.common.Nullable;
7+
import org.immutables.value.Value;
98

109
@Value.Immutable
1110
@JsonSerialize(as = ImmutableCloudServiceInstanceExtended.class)
@@ -45,4 +44,19 @@ public boolean shouldSkipSyslogUrlUpdate() {
4544
return false;
4645
}
4746

47+
@Value.Default
48+
public boolean shouldFailOnParametersUpdateFailure() {
49+
return false;
50+
}
51+
52+
@Value.Default
53+
public boolean shouldFailOnPlanUpdateFailure() {
54+
return false;
55+
}
56+
57+
@Value.Default
58+
public boolean shouldFailOnTagsUpdateFailure() {
59+
return false;
60+
}
61+
4862
}

multiapps-controller-core-test/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
<parent>
1010
<groupId>org.cloudfoundry.multiapps</groupId>
1111
<artifactId>multiapps-controller-parent</artifactId>
12-
<version>1.190.0-SNAPSHOT</version>
12+
<version>1.191.0-SNAPSHOT</version>
1313
</parent>
1414

1515
<dependencies>

multiapps-controller-core/pom.xml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2-
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
2+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
33
<modelVersion>4.0.0</modelVersion>
44

55
<artifactId>multiapps-controller-core</artifactId>
@@ -9,10 +9,14 @@
99
<parent>
1010
<groupId>org.cloudfoundry.multiapps</groupId>
1111
<artifactId>multiapps-controller-parent</artifactId>
12-
<version>1.190.0-SNAPSHOT</version>
12+
<version>1.191.0-SNAPSHOT</version>
1313
</parent>
1414

1515
<dependencies>
16+
<dependency>
17+
<groupId>org.apache.tika</groupId>
18+
<artifactId>tika-core</artifactId>
19+
</dependency>
1620
<dependency>
1721
<groupId>jakarta.xml.bind</groupId>
1822
<artifactId>jakarta.xml.bind-api</artifactId>

multiapps-controller-core/src/main/java/module-info.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
requires org.apache.commons.lang3;
6262
requires org.apache.httpcomponents.httpclient;
6363
requires org.apache.httpcomponents.httpcore;
64+
requires org.apache.tika.core;
6465
requires org.cloudfoundry.multiapps.common;
6566
requires org.cloudfoundry.multiapps.controller.api;
6667
requires org.slf4j;

multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/Messages.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,9 @@ public final class Messages {
8686
public static final String OBJECT_STORE_FILE_STORAGE_HEALTH_DATABASE_HEALTH = "Object store file storage health: \"{0}\", Database health: \"{1}\"";
8787
public static final String ERROR_OCCURRED_DURING_OBJECT_STORE_HEALTH_CHECKING_FOR_INSTANCE = "Error occurred during object store health checking for instance: \"{0}\"";
8888
public static final String ERROR_OCCURRED_WHILE_CHECKING_DATABASE_INSTANCE_0 = "Error occurred while checking database instance: \"{0}\"";
89+
public static final String THE_PROVIDED_MULTIPART_FILE_CANNOT_BE_EMPTY = "The provided multipart file cannot be empty";
90+
public static final String THE_PROVIDED_0_FILE_IS_INVALID = "The provided {0} file is invalid! The file format must be either yaml or mtaext";
91+
public static final String UNSUPPORTED_FILE_FORMAT = "Unsupported file format! \"{0}\" detected";
8992

9093
// Warning messages
9194
public static final String ENVIRONMENT_VARIABLE_IS_NOT_SET_USING_DEFAULT = "Environment variable \"{0}\" is not set. Using default \"{1}\"...";

multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/v2/ServicesCloudModelBuilder.java

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import java.util.Objects;
88
import java.util.TreeMap;
99
import java.util.stream.Collectors;
10-
1110
import org.cloudfoundry.client.v3.serviceinstances.ServiceInstanceType;
1211
import org.cloudfoundry.multiapps.common.ContentException;
1312
import org.cloudfoundry.multiapps.controller.client.lib.domain.CloudServiceInstanceExtended;
@@ -85,6 +84,10 @@ protected CloudServiceInstanceExtended createManagedService(Resource resource, C
8584
.shouldSkipTagsUpdate(commonServiceParameters.shouldSkipTagsUpdate())
8685
.shouldSkipPlanUpdate(commonServiceParameters.shouldSkipPlanUpdate())
8786
.shouldSkipSyslogUrlUpdate(commonServiceParameters.shouldSkipSyslogUrlUpdate())
87+
.shouldFailOnParametersUpdateFailure(
88+
commonServiceParameters.failOnServiceParametersUpdateFailure())
89+
.shouldFailOnPlanUpdateFailure(commonServiceParameters.failOnServicePlanUpdateFailure())
90+
.shouldFailOnTagsUpdateFailure(commonServiceParameters.failOnServiceTagsUpdateFailure())
8891
.v3Metadata(ServiceMetadataBuilder.build(deploymentDescriptor, namespace, resource))
8992
.build();
9093
}
@@ -113,6 +116,10 @@ protected CloudServiceInstanceExtended createUserProvidedService(Resource resour
113116
.shouldSkipTagsUpdate(commonServiceParameters.shouldSkipTagsUpdate())
114117
.shouldSkipPlanUpdate(commonServiceParameters.shouldSkipPlanUpdate())
115118
.shouldSkipSyslogUrlUpdate(commonServiceParameters.shouldSkipSyslogUrlUpdate())
119+
.shouldFailOnParametersUpdateFailure(
120+
commonServiceParameters.failOnServiceParametersUpdateFailure())
121+
.shouldFailOnPlanUpdateFailure(commonServiceParameters.failOnServicePlanUpdateFailure())
122+
.shouldFailOnTagsUpdateFailure(commonServiceParameters.failOnServiceTagsUpdateFailure())
116123
.v3Metadata(ServiceMetadataBuilder.build(deploymentDescriptor, namespace, resource))
117124
.build();
118125
}
@@ -126,6 +133,10 @@ protected CloudServiceInstanceExtended createExistingService(Resource resource,
126133
.shouldSkipTagsUpdate(commonServiceParameters.shouldSkipTagsUpdate())
127134
.shouldSkipPlanUpdate(commonServiceParameters.shouldSkipPlanUpdate())
128135
.shouldSkipSyslogUrlUpdate(commonServiceParameters.shouldSkipSyslogUrlUpdate())
136+
.shouldFailOnParametersUpdateFailure(
137+
commonServiceParameters.failOnServiceParametersUpdateFailure())
138+
.shouldFailOnPlanUpdateFailure(commonServiceParameters.failOnServicePlanUpdateFailure())
139+
.shouldFailOnTagsUpdateFailure(commonServiceParameters.failOnServiceTagsUpdateFailure())
129140
.v3Metadata(ServiceMetadataBuilder.build(deploymentDescriptor, namespace, resource))
130141
.build();
131142
}
@@ -153,13 +164,17 @@ protected String getInvalidServiceConfigTypeErrorMessage(String serviceName, Obj
153164
protected static class CommonServiceParameters {
154165
protected final Resource resource;
155166
private final Map<String, Boolean> shouldSkipUpdates;
167+
private final Map<String, Boolean> failOnServiceUpdateFailure;
156168

157169
@SuppressWarnings("unchecked")
158170
protected CommonServiceParameters(Resource resource) {
159171
this.resource = resource;
160172
this.shouldSkipUpdates = (Map<String, Boolean>) resource.getParameters()
161173
.getOrDefault(SupportedParameters.SKIP_SERVICE_UPDATES,
162174
Collections.emptyMap());
175+
failOnServiceUpdateFailure = (Map<String, Boolean>) resource.getParameters()
176+
.getOrDefault(SupportedParameters.FAIL_ON_SERVICE_UPDATE,
177+
Collections.emptyMap());
163178
}
164179

165180
private String getServiceName() {
@@ -186,6 +201,18 @@ private boolean shouldSkipSyslogUrlUpdate() {
186201
return shouldSkipUpdates.getOrDefault("syslog-drain-url", false);
187202
}
188203

204+
private boolean failOnServiceParametersUpdateFailure() {
205+
return failOnServiceUpdateFailure.getOrDefault("parameters", false);
206+
}
207+
208+
private boolean failOnServiceTagsUpdateFailure() {
209+
return failOnServiceUpdateFailure.getOrDefault("tags", false);
210+
}
211+
212+
private boolean failOnServicePlanUpdateFailure() {
213+
return failOnServiceUpdateFailure.getOrDefault("plan", false);
214+
}
215+
189216
}
190217

191218
}

multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/model/SupportedParameters.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ public class SupportedParameters {
152152
public static final String DEFAULT_XS_APP_NAME = "default-xsappname";
153153
public static final String TYPE = "type";
154154
public static final String SKIP_SERVICE_UPDATES = "skip-service-updates";
155+
public static final String FAIL_ON_SERVICE_UPDATE = "fail-on-service-update";
155156
public static final String SYSLOG_DRAIN_URL = "syslog-drain-url";
156157
public static final String SERVICE_GUID = "service-guid";
157158

@@ -203,7 +204,8 @@ public class SupportedParameters {
203204
DEFAULT_SERVICE_NAME, DEFAULT_XS_APP_NAME, SERVICE, SERVICE_KEYS,
204205
SERVICE_KEY_NAME, SERVICE_NAME, SERVICE_PLAN, SERVICE_TAGS, SERVICE_BROKER,
205206
SKIP_SERVICE_UPDATES, TYPE, PROVIDER_ID, PROVIDER_NID, TARGET,
206-
SERVICE_CONFIG_PATH, FILTER, MANAGED, VERSION, PATH, MEMORY);
207+
SERVICE_CONFIG_PATH, FILTER, MANAGED, VERSION, PATH, MEMORY,
208+
FAIL_ON_SERVICE_UPDATE);
207209
public static final Set<String> GLOBAL_PARAMETERS = Set.of(KEEP_EXISTING_ROUTES, APPS_UPLOAD_TIMEOUT, APPS_TASK_EXECUTION_TIMEOUT,
208210
APPS_START_TIMEOUT, APPS_STAGE_TIMEOUT, APPLY_NAMESPACE,
209211
ENABLE_PARALLEL_DEPLOYMENTS, DEPLOY_MODE);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package org.cloudfoundry.multiapps.controller.core.validators.parameters;
2+
3+
import java.io.IOException;
4+
import java.io.InputStream;
5+
import java.text.MessageFormat;
6+
7+
import jakarta.inject.Named;
8+
import org.apache.commons.io.FilenameUtils;
9+
import org.apache.tika.Tika;
10+
import org.cloudfoundry.multiapps.common.SLException;
11+
import org.cloudfoundry.multiapps.controller.core.Messages;
12+
import org.springframework.web.multipart.MultipartFile;
13+
import org.yaml.snakeyaml.LoaderOptions;
14+
import org.yaml.snakeyaml.Yaml;
15+
import org.yaml.snakeyaml.constructor.SafeConstructor;
16+
import org.yaml.snakeyaml.error.YAMLException;
17+
18+
@Named
19+
public class FileMimeTypeValidator {
20+
21+
private static final String APPLICATION_ZIP_MIME_TYPE = "application/zip";
22+
private static final String APPLICATION_OCTET_STREAM_MIME_TYPE = "application/octet-stream";
23+
private static final String TEXT_PLAIN_MIME_TYPE = "text/plain";
24+
private static final String YAML_FILE_EXTENSION = "yaml";
25+
private static final String EXTENSION_DESCRIPTOR_FILE_EXTENSION = "mtaext";
26+
private static final Tika tika = new Tika();
27+
28+
public void validateMultipartFileMimeType(MultipartFile multipartFile) {
29+
if (multipartFile == null || multipartFile.isEmpty()) {
30+
throw new IllegalArgumentException(Messages.THE_PROVIDED_MULTIPART_FILE_CANNOT_BE_EMPTY);
31+
}
32+
33+
try {
34+
validateInputStreamMimeType(multipartFile.getInputStream(), multipartFile.getOriginalFilename());
35+
} catch (IOException e) {
36+
throw new SLException(e);
37+
}
38+
}
39+
40+
public void validateInputStreamMimeType(InputStream uploadedFileInputStream, String filename) throws IOException {
41+
String detectedType = getFileMimeType(uploadedFileInputStream);
42+
switch (detectedType) {
43+
case TEXT_PLAIN_MIME_TYPE -> validateYamlFile(uploadedFileInputStream, filename);
44+
case APPLICATION_ZIP_MIME_TYPE, APPLICATION_OCTET_STREAM_MIME_TYPE -> {
45+
}
46+
default -> throw new IllegalArgumentException(MessageFormat.format(Messages.UNSUPPORTED_FILE_FORMAT, detectedType));
47+
}
48+
}
49+
50+
private String getFileMimeType(InputStream uploadedFileInputStream) throws IOException {
51+
return tika.detect(uploadedFileInputStream);
52+
}
53+
54+
private void validateYamlFile(InputStream uploadedFileInputStream, String filename) {
55+
validateTextFileExtension(filename);
56+
Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()));
57+
try {
58+
yaml.load(uploadedFileInputStream);
59+
} catch (YAMLException e) {
60+
throw new IllegalArgumentException(MessageFormat.format(Messages.THE_PROVIDED_0_FILE_IS_INVALID, filename), e);
61+
}
62+
}
63+
64+
private void validateTextFileExtension(String filename) {
65+
String fileExtension = FilenameUtils.getExtension(filename);
66+
67+
if (!(YAML_FILE_EXTENSION.equals(fileExtension) || EXTENSION_DESCRIPTOR_FILE_EXTENSION.equals(fileExtension))) {
68+
throw new IllegalArgumentException(MessageFormat.format(Messages.THE_PROVIDED_0_FILE_IS_INVALID, filename));
69+
}
70+
}
71+
}

0 commit comments

Comments
 (0)