Skip to content

Commit

Permalink
Print messages about ports that can't change at runtime for K8s
Browse files Browse the repository at this point in the history
Related to quarkusio#33307, task 3.
Fix quarkusio#32882
  • Loading branch information
Sgitario authored and iocanel committed Jul 12, 2023
1 parent cc5514c commit 1da5a0b
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@
import java.util.Set;
import java.util.stream.Collectors;

import org.eclipse.microprofile.config.ConfigProvider;

import io.dekorate.kubernetes.config.Annotation;
import io.dekorate.kubernetes.config.ConfigMapVolumeBuilder;
import io.dekorate.kubernetes.config.EnvBuilder;
Expand Down Expand Up @@ -103,7 +101,6 @@
import io.quarkus.kubernetes.spi.Subject;

public class KubernetesCommonHelper {

private static final String ANY = null;
private static final String OUTPUT_ARTIFACT_FORMAT = "%s%s.jar";
private static final String[] PROMETHEUS_ANNOTATION_TARGETS = { "Service",
Expand Down Expand Up @@ -187,20 +184,32 @@ public static Map<String, Port> combinePorts(List<KubernetesPortBuildItem> ports
: buildItemPort.getPath())
.build();

// Special handling for ports with name "https". We look up the container port from the Quarkus configuration.
if ("https".equals(name) && combinedPort.getContainerPort() == null) {
int containerPort = ConfigProvider.getConfig()
.getOptionalValue("quarkus.http.ssl-port", Integer.class)
.orElse(8443);

combinedPort = new PortBuilder(combinedPort).withContainerPort(containerPort).build();
// Special handling for ports with mapped configuration. We look up the container port from the Quarkus configuration.
if (combinedPort.getContainerPort() == null) {
Integer containerPort = RuntimePropertiesUtil.getPortNumberFromRuntime(name);
if (containerPort != null) {
combinedPort = new PortBuilder(combinedPort)
.withContainerPort(containerPort)
.build();
}
}

allPorts.put(name, combinedPort);
});
return allPorts;
}

/**
* Creates the configurator build items.
*/
public static void printMessageAboutPortsThatCantChange(String target, List<KubernetesPortBuildItem> ports,
PlatformConfiguration config) {
Collection<Port> allPorts = combinePorts(ports, config).values();
for (Port port : allPorts) {
RuntimePropertiesUtil.printTraceIfRuntimePropertyIsSet(target, port);
}
}

/**
* Creates the common decorator build items.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import static io.quarkus.kubernetes.deployment.Constants.READINESS_PROBE;
import static io.quarkus.kubernetes.deployment.Constants.ROUTE;
import static io.quarkus.kubernetes.deployment.Constants.STARTUP_PROBE;
import static io.quarkus.kubernetes.deployment.KubernetesCommonHelper.printMessageAboutPortsThatCantChange;
import static io.quarkus.kubernetes.deployment.KubernetesConfigUtil.MANAGEMENT_PORT_NAME;
import static io.quarkus.kubernetes.deployment.KubernetesConfigUtil.managementPortIsEnabled;
import static io.quarkus.kubernetes.deployment.OpenshiftConfig.OpenshiftFlavor.v3;
Expand Down Expand Up @@ -375,6 +376,9 @@ public List<DecoratorBuildItem> createDecorators(ApplicationInfoBuildItem applic
|| !config.route.targetPort.equals(MANAGEMENT_PORT_NAME))) {
result.add(new DecoratorBuildItem(OPENSHIFT, new RemovePortFromServiceDecorator(name, MANAGEMENT_PORT_NAME)));
}

printMessageAboutPortsThatCantChange(OPENSHIFT, ports, config);

return result;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package io.quarkus.kubernetes.deployment;

import java.util.Map;
import java.util.Optional;

import org.eclipse.microprofile.config.ConfigProvider;
import org.jboss.logging.Logger;

import io.dekorate.kubernetes.config.Port;

/**
* Utility to handling runtime properties.
*/
public final class RuntimePropertiesUtil {

private static final Logger LOG = Logger.getLogger(KubernetesDeployer.class);

private static final String CONTAINER_PORT = "the container port";
/**
* List of ports that are linked to a runtime property.
*/
private static final Map<String, RuntimeProperty> PORTS = Map.of(
"http", new RuntimeProperty<>("quarkus.http.port", Integer.class, 8080, CONTAINER_PORT),
"https", new RuntimeProperty<>("quarkus.http.ssl-port", Integer.class, 8443, CONTAINER_PORT),
"management", new RuntimeProperty<>("quarkus.management.port", Integer.class, 9000, CONTAINER_PORT));

private RuntimePropertiesUtil() {

}

/**
* This method will return the port number that is configured from the runtime property. If the runtime property does not
* return any value, it will return the default value that is defined in the {@link RuntimePropertiesUtil#PORTS} map.
*/
public static Integer getPortNumberFromRuntime(String name) {
RuntimeProperty runtimeProperty = PORTS.get(name);
if (runtimeProperty != null) {
return (Integer) runtimeProperty.getValue().orElse(runtimeProperty.defaultValue);
}

return null;
}

/**
* This method will trace an informative message to let users know that runtime properties that are used in the generated
* resources by Kubernetes can't change again at runtime.
*
* For example, for users that set a runtime property "quarkus.http.port=9000" at build time, Kubernetes will use this value
* in the generated resources. Then, when running the application in Kubernetes, if users try to modify again the
* runtime property "quarkus.http.port" to a different value, this won't work because the generated resources already took
* the 9000 value.
*
* Note that this message won't be printed if the users didn't provide the runtime property at build time.
*/
public static void printTraceIfRuntimePropertyIsSet(String target, Port port) {
RuntimeProperty runtimeProperty = PORTS.get(port.getName());
if (runtimeProperty != null) {
var runtimePropertyValue = runtimeProperty.getValue();
if (runtimePropertyValue.isPresent()) {
LOG.info(String.format("The '%s' manifests are generated with %s '%s' having value '%d'. "
+ "The app and manifests will get out of sync if the property '%s' is changed at runtime.",
target, runtimeProperty.usage, port.getName(), port.getContainerPort(), runtimeProperty.propertyName));
}
}
}

private static class RuntimeProperty<T> {
private final String propertyName;
private final Class<T> clazzOfValue;
private final T defaultValue;
private final String usage;

public RuntimeProperty(String propertyName, Class<T> clazzOfValue, T defaultValue, String usage) {
this.propertyName = propertyName;
this.clazzOfValue = clazzOfValue;
this.defaultValue = defaultValue;
this.usage = usage;
}

public Optional<T> getValue() {
return ConfigProvider.getConfig().getOptionalValue(propertyName, clazzOfValue);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import static io.quarkus.kubernetes.deployment.Constants.LIVENESS_PROBE;
import static io.quarkus.kubernetes.deployment.Constants.READINESS_PROBE;
import static io.quarkus.kubernetes.deployment.Constants.STARTUP_PROBE;
import static io.quarkus.kubernetes.deployment.KubernetesCommonHelper.printMessageAboutPortsThatCantChange;
import static io.quarkus.kubernetes.deployment.KubernetesConfigUtil.MANAGEMENT_PORT_NAME;
import static io.quarkus.kubernetes.deployment.KubernetesConfigUtil.managementPortIsEnabled;
import static io.quarkus.kubernetes.spi.KubernetesDeploymentTargetBuildItem.VANILLA_KUBERNETES_PRIORITY;
Expand Down Expand Up @@ -298,7 +299,7 @@ public List<DecoratorBuildItem> createDecorators(ApplicationInfoBuildItem applic
.withMaxUnavailable(config.rollingUpdate.maxUnavailable)
.build())));
}

printMessageAboutPortsThatCantChange(KUBERNETES, ports, config);
return result;
}

Expand All @@ -320,4 +321,4 @@ void externalizeInitTasks(
jobs, initContainers, env, roles, roleBindings, decorators);
}
}
}
}

0 comments on commit 1da5a0b

Please sign in to comment.