Skip to content

Commit b2f780e

Browse files
committed
Add killswitch for Log4j properties
Adds a `kubernetes.log4j.useProperties` Java system property to disable the usage of Log4j properties. Increases test coverage.
1 parent 316e960 commit b2f780e

File tree

13 files changed

+340
-151
lines changed

13 files changed

+340
-151
lines changed

log4j/pom.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@
4747
<groupId>org.apache.logging.log4j</groupId>
4848
<artifactId>log4j-core</artifactId>
4949
</dependency>
50+
<dependency>
51+
<groupId>org.assertj</groupId>
52+
<artifactId>assertj-core</artifactId>
53+
<scope>test</scope>
54+
</dependency>
5055
<dependency>
5156
<groupId>org.junit.jupiter</groupId>
5257
<artifactId>junit-jupiter-api</artifactId>
@@ -57,6 +62,11 @@
5762
<artifactId>junit-jupiter-params</artifactId>
5863
<scope>test</scope>
5964
</dependency>
65+
<dependency>
66+
<groupId>org.mockito</groupId>
67+
<artifactId>mockito-core</artifactId>
68+
<scope>test</scope>
69+
</dependency>
6070
</dependencies>
6171

6272
<build>
Lines changed: 59 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,82 @@
11
/**
22
* Copyright (C) 2015 Red Hat, Inc.
3-
*
4-
* Licensed under the Apache License, Version 2.0 (the "License");
5-
* you may not use this file except in compliance with the License.
6-
* You may obtain a copy of the License at
7-
*
8-
* http://www.apache.org/licenses/LICENSE-2.0
9-
*
10-
* Unless required by applicable law or agreed to in writing, software
11-
* distributed under the License is distributed on an "AS IS" BASIS,
12-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13-
* See the License for the specific language governing permissions and
14-
* limitations under the License.
3+
* <p>
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
5+
* the License. You may obtain a copy of the License at
6+
* <p>
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
* <p>
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
10+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11+
* specific language governing permissions and limitations under the License.
1512
*/
1613
package io.fabric8.kubernetes.log4j.lookup;
1714

1815
import io.fabric8.kubernetes.client.Config;
1916
import io.fabric8.kubernetes.client.ConfigBuilder;
2017
import io.fabric8.kubernetes.client.KubernetesClient;
2118
import io.fabric8.kubernetes.client.KubernetesClientBuilder;
19+
import org.apache.logging.log4j.status.StatusLogger;
20+
import org.apache.logging.log4j.util.PropertiesUtil;
21+
22+
import static io.fabric8.kubernetes.client.utils.Utils.getSystemPropertyOrEnvVar;
2223

2324
/**
2425
* Builds a Kubernetes Client.
2526
*/
26-
class ClientBuilder {
27+
final class ClientBuilder {
28+
29+
/**
30+
* If this system property is set to {@code true}, the client configuration is retrieved from Log4j Properties.
31+
*/
32+
public static final String KUBERNETES_LOG4J_USE_PROPERTIES = "kubernetes.log4j.useProperties";
33+
34+
private ClientBuilder() {
35+
}
2736

28-
public KubernetesClient createClient() {
29-
final Config config = kubernetesClientConfig();
37+
public static KubernetesClient createClient() {
38+
final Config config = kubernetesClientConfig(PropertiesUtil.getProperties());
3039
return config != null ? new KubernetesClientBuilder()
3140
.withConfig(config).build() : null;
3241
}
3342

34-
private Config kubernetesClientConfig() {
35-
Config base = null;
43+
static Config kubernetesClientConfig(final PropertiesUtil props) {
3644
try {
37-
base = Config.autoConfigure(null);
38-
} catch (Exception ex) {
39-
if (ex instanceof NullPointerException) {
40-
return null;
45+
final Config base = Config.autoConfigure(null);
46+
if (getSystemPropertyOrEnvVar(KUBERNETES_LOG4J_USE_PROPERTIES, false)) {
47+
final Log4jConfig log4jConfig = new Log4jConfig(props, base);
48+
return new ConfigBuilder()
49+
.withApiVersion(log4jConfig.getApiVersion())
50+
.withCaCertData(log4jConfig.getCaCertData())
51+
.withCaCertFile(log4jConfig.getCaCertFile())
52+
.withClientCertData(log4jConfig.getClientCertData())
53+
.withClientCertFile(log4jConfig.getClientCertFile())
54+
.withClientKeyAlgo(log4jConfig.getClientKeyAlgo())
55+
.withClientKeyData(log4jConfig.getClientKeyData())
56+
.withClientKeyFile(log4jConfig.getClientKeyFile())
57+
.withClientKeyPassphrase(log4jConfig.getClientKeyPassphrase())
58+
.withConnectionTimeout(log4jConfig.getConnectionTimeout())
59+
.withHttpProxy(log4jConfig.getHttpProxy())
60+
.withHttpsProxy(log4jConfig.getHttpsProxy())
61+
.withLoggingInterval(log4jConfig.getLoggingInterval())
62+
.withMasterUrl(log4jConfig.getMasterUrl())
63+
.withNamespace(log4jConfig.getNamespace())
64+
.withNoProxy(log4jConfig.getNoProxy())
65+
.withPassword(log4jConfig.getPassword())
66+
.withProxyPassword(log4jConfig.getProxyPassword())
67+
.withProxyUsername(log4jConfig.getProxyUsername())
68+
.withRequestTimeout(log4jConfig.getRequestTimeout())
69+
.withTrustCerts(log4jConfig.isTrustCerts())
70+
.withUsername(log4jConfig.getUsername())
71+
.withWatchReconnectInterval(log4jConfig.getWatchReconnectInterval())
72+
.withWatchReconnectLimit(log4jConfig.getWatchReconnectLimit())
73+
.build();
4174
}
75+
return base;
76+
} catch (final Throwable t) {
77+
StatusLogger.getLogger().warn("An error occurred while retrieving Kubernetes Client configuration: {}.",
78+
t.getMessage(), t);
4279
}
43-
final ClientProperties props = new ClientProperties(base);
44-
final Config properties = new ConfigBuilder(base)
45-
.withApiVersion(props.getApiVersion())
46-
.withCaCertData(props.getCaCertData())
47-
.withCaCertFile(props.getCaCertFile())
48-
.withClientCertData(props.getClientCertData())
49-
.withClientCertFile(props.getClientCertFile())
50-
.withClientKeyAlgo(props.getClientKeyAlgo())
51-
.withClientKeyData(props.getClientKeyData())
52-
.withClientKeyFile(props.getClientKeyFile())
53-
.withClientKeyPassphrase(props.getClientKeyPassphrase())
54-
.withConnectionTimeout(props.getConnectionTimeout())
55-
.withHttpProxy(props.getHttpProxy())
56-
.withHttpsProxy(props.getHttpsProxy())
57-
.withMasterUrl(props.getMasterUrl())
58-
.withNamespace(props.getNamespace())
59-
.withNoProxy(props.getNoProxy())
60-
.withPassword(props.getPassword())
61-
.withProxyPassword(props.getProxyPassword())
62-
.withProxyUsername(props.getProxyUsername())
63-
.withRequestTimeout(props.getRequestTimeout())
64-
.withTrustCerts(props.isTrustCerts())
65-
.withUsername(props.getUsername())
66-
.build();
67-
return properties;
80+
return null;
6881
}
6982
}

log4j/src/main/java/io/fabric8/kubernetes/log4j/lookup/ContainerUtil.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ final class ContainerUtil {
3232
private static final Logger LOGGER = StatusLogger.getLogger();
3333
private static final int MAXLENGTH = 65;
3434

35+
private ContainerUtil() {
36+
}
37+
3538
/**
3639
* Returns the container id when running in a Docker container.
3740
*

log4j/src/main/java/io/fabric8/kubernetes/log4j/lookup/KubernetesLookup.java

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
11
/**
22
* Copyright (C) 2015 Red Hat, Inc.
3-
*
4-
* Licensed under the Apache License, Version 2.0 (the "License");
5-
* you may not use this file except in compliance with the License.
6-
* You may obtain a copy of the License at
7-
*
8-
* http://www.apache.org/licenses/LICENSE-2.0
9-
*
10-
* Unless required by applicable law or agreed to in writing, software
11-
* distributed under the License is distributed on an "AS IS" BASIS,
12-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13-
* See the License for the specific language governing permissions and
14-
* limitations under the License.
3+
* <p>
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
5+
* the License. You may obtain a copy of the License at
6+
* <p>
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
* <p>
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
10+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11+
* specific language governing permissions and limitations under the License.
1512
*/
1613
package io.fabric8.kubernetes.log4j.lookup;
1714

@@ -172,7 +169,7 @@ public KubernetesLookup() {
172169
initialize();
173170
}
174171

175-
private boolean initialize() {
172+
private void initialize() {
176173
if (kubernetesInfo == null || (isSpringIncluded && !kubernetesInfo.isSpringActive)) {
177174
initLock.lock();
178175
try {
@@ -182,14 +179,13 @@ private boolean initialize() {
182179
KubernetesClient client = null;
183180
info.isSpringActive = isSpringActive;
184181
if (pod == null) {
185-
client = new ClientBuilder().createClient();
182+
client = ClientBuilder.createClient();
186183
if (client != null) {
187184
pod = getCurrentPod(client);
188185
info.masterUrl = client.getMasterUrl();
189186
if (pod != null) {
190-
info.namespace = pod.getMetadata().getNamespace();
191187
namespace = client.namespaces()
192-
.withName(info.namespace)
188+
.withName(pod.getMetadata().getNamespace())
193189
.get();
194190
}
195191
} else {
@@ -199,6 +195,7 @@ private boolean initialize() {
199195
info.masterUrl = masterUrl;
200196
}
201197
if (pod != null) {
198+
info.namespace = pod.getMetadata().getNamespace();
202199
if (namespace != null) {
203200
info.namespaceId = namespace.getMetadata().getUid();
204201
info.namespaceAnnotations = namespace.getMetadata().getAnnotations();
@@ -255,7 +252,6 @@ private boolean initialize() {
255252
initLock.unlock();
256253
}
257254
}
258-
return kubernetesInfo != null;
259255
}
260256

261257
@Override

log4j/src/main/java/io/fabric8/kubernetes/log4j/lookup/ClientProperties.java renamed to log4j/src/main/java/io/fabric8/kubernetes/log4j/lookup/Log4jConfig.java

Lines changed: 21 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
11
/**
22
* Copyright (C) 2015 Red Hat, Inc.
3-
*
4-
* Licensed under the Apache License, Version 2.0 (the "License");
5-
* you may not use this file except in compliance with the License.
6-
* You may obtain a copy of the License at
7-
*
8-
* http://www.apache.org/licenses/LICENSE-2.0
9-
*
10-
* Unless required by applicable law or agreed to in writing, software
11-
* distributed under the License is distributed on an "AS IS" BASIS,
12-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13-
* See the License for the specific language governing permissions and
14-
* limitations under the License.
3+
* <p>
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
5+
* the License. You may obtain a copy of the License at
6+
* <p>
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
* <p>
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
10+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11+
* specific language governing permissions and limitations under the License.
1512
*/
1613
package io.fabric8.kubernetes.log4j.lookup;
1714

@@ -23,9 +20,11 @@
2320
/**
2421
* Obtains properties used to configure the Kubernetes client.
2522
*/
26-
class ClientProperties {
23+
final class Log4jConfig {
2724

25+
// Prefixes used in Log4j properties
2826
private static final String[] PREFIXES = { "log4j2.kubernetes.client.", "spring.cloud.kubernetes.client." };
27+
// Recognized Log4j properties
2928
private static final String API_VERSION = "apiVersion";
3029
private static final String CA_CERT_FILE = "caCertFile";
3130
private static final String CA_CERT_DATA = "caCertData";
@@ -51,10 +50,11 @@ class ClientProperties {
5150
private static final String WATCH_RECONNECT_INTERVAL = "watchReconnectInterval";
5251
private static final String WATCH_RECONNECT_LIMIT = "watchReconnectLimit";
5352

54-
private final PropertiesUtil props = PropertiesUtil.getProperties();
53+
private final PropertiesUtil props;
5554
private final Config base;
5655

57-
public ClientProperties(final Config base) {
56+
public Log4jConfig(final PropertiesUtil props, final Config base) {
57+
this.props = props;
5858
this.base = base;
5959
}
6060

@@ -96,10 +96,7 @@ public String getClientKeyPassphrase() {
9696

9797
public int getConnectionTimeout() {
9898
final Duration timeout = props.getDurationProperty(PREFIXES, CONNECTION_TIMEOUT, null);
99-
if (timeout != null) {
100-
return (int) timeout.toMillis();
101-
}
102-
return base.getConnectionTimeout();
99+
return timeout != null ? (int) timeout.toMillis() : base.getConnectionTimeout();
103100
}
104101

105102
public String getHttpProxy() {
@@ -112,10 +109,7 @@ public String getHttpsProxy() {
112109

113110
public int getLoggingInterval() {
114111
final Duration interval = props.getDurationProperty(PREFIXES, LOGGING_INTERVAL, null);
115-
if (interval != null) {
116-
return (int) interval.toMillis();
117-
}
118-
return base.getLoggingInterval();
112+
return interval != null ? (int) interval.toMillis() : base.getLoggingInterval();
119113
}
120114

121115
public String getMasterUrl() {
@@ -128,10 +122,7 @@ public String getNamespace() {
128122

129123
public String[] getNoProxy() {
130124
final String result = props.getStringProperty(PREFIXES, NO_PROXY, null);
131-
if (result != null) {
132-
return result.replace("\\s", "").split(",");
133-
}
134-
return base.getNoProxy();
125+
return result != null ? result.replace("\\s", "").split(",") : base.getNoProxy();
135126
}
136127

137128
public String getPassword() {
@@ -148,10 +139,7 @@ public String getProxyPassword() {
148139

149140
public int getRequestTimeout() {
150141
final Duration interval = props.getDurationProperty(PREFIXES, REQUEST_TIMEOUT, null);
151-
if (interval != null) {
152-
return (int) interval.toMillis();
153-
}
154-
return base.getRequestTimeout();
142+
return interval != null ? (int) interval.toMillis() : base.getRequestTimeout();
155143
}
156144

157145
public Boolean isTrustCerts() {
@@ -164,17 +152,11 @@ public String getUsername() {
164152

165153
public int getWatchReconnectInterval() {
166154
final Duration interval = props.getDurationProperty(PREFIXES, WATCH_RECONNECT_INTERVAL, null);
167-
if (interval != null) {
168-
return (int) interval.toMillis();
169-
}
170-
return base.getWatchReconnectInterval();
155+
return interval != null ? (int) interval.toMillis() : base.getWatchReconnectInterval();
171156
}
172157

173158
public int getWatchReconnectLimit() {
174159
final Duration interval = props.getDurationProperty(PREFIXES, WATCH_RECONNECT_LIMIT, null);
175-
if (interval != null) {
176-
return (int) interval.toMillis();
177-
}
178-
return base.getWatchReconnectLimit();
160+
return interval != null ? (int) interval.toMillis() : base.getWatchReconnectLimit();
179161
}
180162
}

log4j/src/main/java/io/fabric8/kubernetes/log4j/lookup/package-info.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* you may not use this file except in compliance with the License.
66
* You may obtain a copy of the License at
77
*
8-
* http://www.apache.org/licenses/LICENSE-2.0
8+
* http://www.apache.org/licenses/LICENSE-2.0
99
*
1010
* Unless required by applicable law or agreed to in writing, software
1111
* distributed under the License is distributed on an "AS IS" BASIS,

0 commit comments

Comments
 (0)