Skip to content

Commit

Permalink
Namespace as suffix implementation and namespace length validation
Browse files Browse the repository at this point in the history
LMCROSSITXSADEPLOY-3002
LMCROSSITXSADEPLOY-2988
  • Loading branch information
Yavor16 authored and Yavor16 committed Sep 20, 2024
1 parent a1879cd commit 1b04b7e
Show file tree
Hide file tree
Showing 43 changed files with 962 additions and 339 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,14 @@ public List<ParameterValidator> getValidatorsList() {
return List.of(new HostValidator(), new DomainValidator(),
new RoutesValidator(context.getNamespace(),
context.applyNamespaceAppRoutesGlobalLevel(),
context.applyNamespaceAppRoutesProcessVariable()),
context.applyNamespaceAppRoutesProcessVariable(),
context.applyNamespaceAsSuffixGlobalLevel(),
context.applyNamespaceAsSuffixProcessVariable()),
new IdleRoutesValidator(context.getNamespace(),
context.applyNamespaceAppRoutesGlobalLevel(),
context.applyNamespaceAppRoutesProcessVariable()),
context.applyNamespaceAppRoutesProcessVariable(),
context.applyNamespaceAsSuffixGlobalLevel(),
context.applyNamespaceAsSuffixProcessVariable()),
new TasksValidator(), new VisibilityValidator(), new RestartOnEnvChangeValidator());
}

Expand Down Expand Up @@ -120,10 +124,14 @@ private void unescapeEscapedReferences(DeploymentDescriptor descriptor) {
private DeploymentDescriptor correctEntityNames(DeploymentDescriptor descriptor) {
List<ParameterValidator> correctors = Arrays.asList(new ApplicationNameValidator(context.getNamespace(),
context.applyNamespaceAppNamesGlobalLevel(),
context.applyNamespaceAppNamesProcessVariable()),
context.applyNamespaceAppNamesProcessVariable(),
context.applyNamespaceAsSuffixGlobalLevel(),
context.applyNamespaceAsSuffixProcessVariable()),
new ServiceNameValidator(context.getNamespace(),
context.applyNamespaceServiceNamesGlobalLevel(),
context.applyNamespaceServiceNamesProcessVariable()));
context.applyNamespaceServiceNamesProcessVariable(),
context.applyNamespaceAsSuffixGlobalLevel(),
context.applyNamespaceAsSuffixProcessVariable()));
return context.getHandlerFactory()
.getDescriptorParametersValidator(descriptor, correctors)
.validate();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ public class SystemParameters {

public static final int GENERATED_CREDENTIALS_LENGTH = 16;
public static final String IDLE_HOST_SUFFIX = "-idle";
public static final String GREEN_HOST_SUFFIX = "-green";
public static final String BLUE_HOST_SUFFIX = "-blue";
public static final String ROUTE_PATH_PLACEHOLDER = "${route-path}";
public static final String DEFAULT_HOST_BASED_IDLE_URI = "${idle-host}.${idle-domain}";
public static final String DEFAULT_HOST_BASED_URI = "${host}.${domain}";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ public interface MtaDescriptorPropertiesResolverContext {

boolean applyNamespaceAppRoutesGlobalLevel();

boolean applyNamespaceAsSuffixGlobalLevel();

@Nullable
Boolean applyNamespaceAsSuffixProcessVariable();

@Nullable
Boolean applyNamespaceAppNamesProcessVariable();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public class SupportedParameters {
public static final String SPACE_GUID = "space-guid";
public static final String NAMESPACE = "namespace";
public static final String APPLY_NAMESPACE = "apply-namespace";
public static final String APPLY_NAMESPACE_AS_SUFFIX = "as-suffix";
public static final String MTA_VERSION = "mta-version";
public static final String MTA_ID = "mta-id";
public static final String APPLY_NAMESPACE_APPS = "app-names";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,40 +8,26 @@
import org.cloudfoundry.multiapps.common.SLException;
import org.cloudfoundry.multiapps.controller.core.Constants;
import org.cloudfoundry.multiapps.controller.core.Messages;
import org.cloudfoundry.multiapps.controller.core.helpers.SystemParameters;
import org.cloudfoundry.multiapps.controller.core.model.SupportedParameters;
import org.cloudfoundry.multiapps.mta.model.Module;
import org.cloudfoundry.multiapps.mta.model.Resource;

public class NameUtil {

public static class NameRequirements {

private NameRequirements() {
}

public static final String XS_APP_NAME_PATTERN = "(?!sap_system)[a-zA-Z0-9\\._\\-\\\\/]{1,240}";
public static final String CONTAINER_NAME_PATTERN = "[A-Z0-9][_A-Z0-9]{0,63}";

public static final int XS_APP_NAME_MAX_LENGTH = 240;
public static final int APP_NAME_MAX_LENGTH = 1024;
public static final int SERVICE_NAME_MAX_LENGTH = 50; // TODO: Make this configurable.
public static final int CONTAINER_NAME_MAX_LENGTH = 64;

public static final String ENVIRONMENT_NAME_ILLEGAL_CHARACTERS = "[^_a-zA-Z0-9]";
public static final String XS_APP_NAME_ILLEGAL_CHARACTERS = "[^a-zA-Z0-9._\\-\\\\/]";
public static final String CONTAINER_NAME_ILLEGAL_CHARACTERS = "[^_A-Z0-9]";

}

private NameUtil() {
}

public static String computeValidApplicationName(String applicationName, String namespace, boolean applyNamespace) {
return computeNamespacedNameWithLength(applicationName, namespace, applyNamespace, NameRequirements.APP_NAME_MAX_LENGTH);
public static String computeValidApplicationName(String applicationName, String namespace, boolean applyNamespace,
boolean applyNamespaceAsSuffix) {
return computeNamespacedNameWithLength(applicationName, namespace, applyNamespace, applyNamespaceAsSuffix,
NameRequirements.APP_NAME_MAX_LENGTH);
}

public static String computeValidServiceName(String serviceName, String namespace, boolean applyNamespace) {
return computeNamespacedNameWithLength(serviceName, namespace, applyNamespace, NameRequirements.SERVICE_NAME_MAX_LENGTH);
public static String computeValidServiceName(String serviceName, String namespace, boolean applyNamespace,
boolean applyNamespaceAsSuffix) {
return computeNamespacedNameWithLength(serviceName, namespace, applyNamespace, applyNamespaceAsSuffix,
NameRequirements.SERVICE_NAME_MAX_LENGTH);
}

public static String computeValidContainerName(String organization, String space, String serviceName) {
Expand Down Expand Up @@ -73,19 +59,61 @@ public static String getNameWithProperLength(String name, int maxLength) {
return name;
}

public static String computeNamespacedNameWithLength(String name, String namespace, boolean applyNamespace, int maxLength) {
String prefix = "";
public static String computeNamespacedNameWithLength(String name, String namespace, boolean applyNamespace,
boolean applyNamespaceAsSuffix, int maxLength) {
if (StringUtils.isNotEmpty(namespace) && applyNamespace) {
prefix = getNamespacePrefix(namespace);
if (applyNamespaceAsSuffix) {
name = getNameWithNamespaceSuffix(name, namespace, maxLength);
} else {
name = getNamespacePrefix(namespace) + name;
}
}
return getNameWithProperLength(name, maxLength);
}

return getNameWithProperLength(prefix + name, maxLength);
private static String getNameWithNamespaceSuffix(String name, String namespace, int maxLength) {
String namespaceSuffix = getNamespaceSuffix(namespace);
String shortenedName = getNameWithProperLength(name, calculateNameLengthWithoutNamespaceAndBlueGreenSuffix(namespaceSuffix, maxLength));

return correctNameSuffix(shortenedName, name, namespaceSuffix);
}

private static int calculateNameLengthWithoutNamespaceAndBlueGreenSuffix(String namespaceSuffix, int maxLengthWithSuffix) {
//Here we use the "green" suffix because it is the longest out of all
return maxLengthWithSuffix - (namespaceSuffix.length() + SystemParameters.GREEN_HOST_SUFFIX.length());
}

private static String correctNameSuffix(String name, String nameWithoutShortening, String namespaceSuffix) {
if (nameWithoutShortening.endsWith(SystemParameters.IDLE_HOST_SUFFIX)) {
name = placeNamespaceBeforeBlueGreenSuffix(name, namespaceSuffix, SystemParameters.IDLE_HOST_SUFFIX);
} else if (nameWithoutShortening.endsWith(SystemParameters.BLUE_HOST_SUFFIX)) {
name = placeNamespaceBeforeBlueGreenSuffix(name, namespaceSuffix, SystemParameters.BLUE_HOST_SUFFIX);
} else if (nameWithoutShortening.endsWith(SystemParameters.GREEN_HOST_SUFFIX)) {
name = placeNamespaceBeforeBlueGreenSuffix(name, namespaceSuffix, SystemParameters.GREEN_HOST_SUFFIX);
} else {
name += namespaceSuffix;
}

return name;
}

private static String placeNamespaceBeforeBlueGreenSuffix(String name, String namespaceSuffix, String blueGreenSuffix) {
int lastOccurrenceOfBlueGreenSuffix = name.lastIndexOf(blueGreenSuffix);
if (lastOccurrenceOfBlueGreenSuffix > -1) {
name = name.substring(0, lastOccurrenceOfBlueGreenSuffix);
}
name += namespaceSuffix + blueGreenSuffix;
return name;
}

public static String getNamespacePrefix(String namespace) {
return namespace + Constants.NAMESPACE_SEPARATOR;
}

public static String getNamespaceSuffix(String namespace) {
return Constants.NAMESPACE_SEPARATOR + namespace;
}

private static String getShortenedName(String name, int maxLength) {
String nameHashCode = getHashCodeAsHexString(name);
if (maxLength < nameHashCode.length()) {
Expand Down Expand Up @@ -123,4 +151,21 @@ public static String getServiceName(Resource resource) {
.get(SupportedParameters.SERVICE_NAME);
}

public static class NameRequirements {

public static final String XS_APP_NAME_PATTERN = "(?!sap_system)[a-zA-Z0-9\\._\\-\\\\/]{1,240}";
public static final String CONTAINER_NAME_PATTERN = "[A-Z0-9][_A-Z0-9]{0,63}";
public static final int XS_APP_NAME_MAX_LENGTH = 240;
public static final int APP_NAME_MAX_LENGTH = 1024;
public static final int SERVICE_NAME_MAX_LENGTH = 50; // TODO: Make this configurable.
public static final int CONTAINER_NAME_MAX_LENGTH = 64;
public static final String ENVIRONMENT_NAME_ILLEGAL_CHARACTERS = "[^_a-zA-Z0-9]";
public static final String XS_APP_NAME_ILLEGAL_CHARACTERS = "[^a-zA-Z0-9._\\-\\\\/]";
public static final String CONTAINER_NAME_ILLEGAL_CHARACTERS = "[^_A-Z0-9]";

private NameRequirements() {
}

}

}
Original file line number Diff line number Diff line change
@@ -1,35 +1,48 @@
package org.cloudfoundry.multiapps.controller.core.util;

import static java.text.MessageFormat.format;

import java.util.Map;
import java.util.Objects;

import org.cloudfoundry.multiapps.common.util.MapUtil;
import org.cloudfoundry.multiapps.controller.core.Messages;
import org.cloudfoundry.multiapps.controller.core.model.SupportedParameters;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;
import java.util.Objects;

import static java.text.MessageFormat.format;

public class NamespaceValidationUtil {
private static final Logger LOGGER = LoggerFactory.getLogger(NamespaceValidationUtil.class);
private String namespace;
private boolean applyNamespaceGlobalLevel;
private Boolean applyNamespaceProcessVariable;
private boolean applyNamespaceAsSuffixGlobalLevel;
private Boolean applyNamespaceAsSuffixProcessVariable;

public NamespaceValidationUtil() {
}

public NamespaceValidationUtil(String namespace, boolean applyNamespaceGlobalLevel, Boolean applyNamespaceProcessVariable) {
public NamespaceValidationUtil(String namespace, boolean applyNamespaceGlobalLevel, Boolean applyNamespaceProcessVariable,
boolean applyNamespaceAsSuffixGlobalLevel, Boolean applyNamespaceAsSuffixProcessVariable) {
this.namespace = namespace;
this.applyNamespaceGlobalLevel = applyNamespaceGlobalLevel;
this.applyNamespaceProcessVariable = applyNamespaceProcessVariable;
this.applyNamespaceAsSuffixGlobalLevel = applyNamespaceAsSuffixGlobalLevel;
this.applyNamespaceAsSuffixProcessVariable = applyNamespaceAsSuffixProcessVariable;
}

public String getNamespace() {
return namespace;
}

protected boolean shouldApplyNamespaceAsSuffix(final Map<String, Object> relatedParameters) {
if (applyNamespaceAsSuffixProcessVariable != null) {
return applyNamespaceAsSuffixProcessVariable;
}
Boolean applyNamespaceAsSuffixModuleLevel = MapUtil.parseBooleanFlag(relatedParameters, SupportedParameters.APPLY_NAMESPACE_AS_SUFFIX, null);
return Objects.requireNonNullElse(applyNamespaceAsSuffixModuleLevel, applyNamespaceAsSuffixGlobalLevel);
}

public boolean shouldApplyNamespaceResultValue(final Map<String, Object> relatedParameters) {
Boolean applyNamespaceModuleLevel = MapUtil.parseBooleanFlag(relatedParameters, SupportedParameters.APPLY_NAMESPACE, null);
boolean applyNamespaceResult = Objects.requireNonNullElse(applyNamespaceProcessVariable,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,13 @@

public class ApplicationNameValidator extends NamespaceValidationUtil implements ParameterValidator {

public ApplicationNameValidator(String namespace, boolean applyNamespaceGlobalLevel, Boolean applyNamespaceProcessVariable) {
super(namespace, applyNamespaceGlobalLevel, applyNamespaceProcessVariable);
public ApplicationNameValidator(String namespace, boolean applyNamespaceGlobalLevel, Boolean applyNamespaceProcessVariable,
boolean applyNamespaceAsSuffixGlobalLevel, Boolean applyNamespaceAsSuffixProcessVariable) {
super(namespace,
applyNamespaceGlobalLevel,
applyNamespaceProcessVariable,
applyNamespaceAsSuffixGlobalLevel,
applyNamespaceAsSuffixProcessVariable);
}

@Override
Expand Down Expand Up @@ -43,8 +48,11 @@ public Object attemptToCorrect(Object applicationName, final Map<String, Object>
if (!(applicationName instanceof String)) {
throw new ContentException(Messages.COULD_NOT_CREATE_VALID_APPLICATION_NAME_FROM_0, applicationName);
}

boolean applyNamespaceResult = shouldApplyNamespaceResultValue(relatedParameters);
return NameUtil.computeValidApplicationName((String) applicationName, getNamespace(), applyNamespaceResult);

return NameUtil.computeValidApplicationName((String) applicationName, getNamespace(), applyNamespaceResult,
shouldApplyNamespaceAsSuffix(relatedParameters));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,22 @@
import java.util.Set;

import org.cloudfoundry.multiapps.controller.core.Messages;
import org.cloudfoundry.multiapps.controller.core.helpers.SystemParameters;
import org.cloudfoundry.multiapps.controller.core.model.SupportedParameters;
import org.cloudfoundry.multiapps.controller.core.util.NameUtil;

public class HostValidator extends RoutePartValidator {
public HostValidator() {
super(null, false, false);
super(null, false, false, false, false);
}

public HostValidator(String namespace, boolean applyNamespaceGlobalLevel, Boolean applyNamespaceProcessVariable) {
super(namespace, applyNamespaceGlobalLevel, applyNamespaceProcessVariable);
public HostValidator(String namespace, boolean applyNamespaceGlobalLevel, Boolean applyNamespaceProcessVariable,
boolean applyNamespaceAsSuffixGlobalLevel, Boolean applyNamespaceAsSuffixProcessVariable) {
super(namespace,
applyNamespaceGlobalLevel,
applyNamespaceProcessVariable,
applyNamespaceAsSuffixGlobalLevel,
applyNamespaceAsSuffixProcessVariable);
}

@Override
Expand All @@ -23,11 +29,32 @@ public boolean isValid(Object routePart, final Map<String, Object> context) {
return false;
}
if (shouldApplyNamespace(context) && getNamespace() != null) {
if (shouldApplyNamespaceAsSuffix(context)) {
return isHostWithNamespaceAndSuffixValid((String) routePart);
}
return ((String) routePart).startsWith(getNamespace());
}
return true;
}

private boolean isHostWithNamespaceAndSuffixValid(String routePart) {
if (routePart.endsWith(getNamespace())) {
return true;
} else if (routePart.endsWith(SystemParameters.IDLE_HOST_SUFFIX)) {
return containsNamespaceBeforeSuffix(routePart, SystemParameters.IDLE_HOST_SUFFIX);
} else if (routePart.endsWith(SystemParameters.BLUE_HOST_SUFFIX)) {
return containsNamespaceBeforeSuffix(routePart, SystemParameters.BLUE_HOST_SUFFIX);
} else if (routePart.endsWith(SystemParameters.GREEN_HOST_SUFFIX)) {
return containsNamespaceBeforeSuffix(routePart, SystemParameters.GREEN_HOST_SUFFIX);
} else {
return false;
}
}

private boolean containsNamespaceBeforeSuffix(String routePart, String suffix) {
return routePart.substring(0, routePart.lastIndexOf(suffix)).endsWith(getNamespace());
}

@Override
public String getParameterName() {
return SupportedParameters.HOST;
Expand Down Expand Up @@ -55,7 +82,8 @@ protected String getRoutePartPattern() {

@Override
protected String modifyAndShortenRoutePart(String routePart, Map<String, Object> context) {
return NameUtil.computeNamespacedNameWithLength(routePart, getNamespace(), shouldApplyNamespace(context), getRoutePartMaxLength());
return NameUtil.computeNamespacedNameWithLength(routePart, getNamespace(), shouldApplyNamespace(context),
shouldApplyNamespaceAsSuffix(context), getRoutePartMaxLength());
}

private boolean shouldApplyNamespace(Map<String, Object> context) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,13 @@

public class IdleRouteValidator extends RouteValidator {

public IdleRouteValidator(String namespace, boolean applyNamespaceGlobalLevel, Boolean applyNamespaceProcessVariable) {
super(namespace, applyNamespaceGlobalLevel, applyNamespaceProcessVariable);
public IdleRouteValidator(String namespace, boolean applyNamespaceGlobalLevel, Boolean applyNamespaceProcessVariable,
boolean applyNamespaceAsSuffixGlobalLevel, Boolean applyNamespaceAsSuffixProcessVariable) {
super(namespace,
applyNamespaceGlobalLevel,
applyNamespaceProcessVariable,
applyNamespaceAsSuffixGlobalLevel,
applyNamespaceAsSuffixProcessVariable);
}

@Override
Expand Down
Loading

0 comments on commit 1b04b7e

Please sign in to comment.