Skip to content

Commit 747e93f

Browse files
authored
Merge pull request #145 from oracle/probes-and-scripts
Create shared domain scripts config map and use for liveness and readiness probes
2 parents 838bde2 + 57eac6c commit 747e93f

17 files changed

+958
-365
lines changed

kubernetes/internal/domain-job-template.yaml

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -208,37 +208,6 @@ data:
208208
209209
checkFileExists ${pyFile}
210210
211-
# Create a liveness probe script. It checks a WL server state file maintained by the node manager.
212-
# The script and 'EOF' on the following lines must not be indented!
213-
214-
scriptFile=${nmdir}/livenessProbe.sh
215-
216-
cat << EOF > $scriptFile
217-
#!/bin/bash
218-
219-
# Kubernetes periodically calls this liveness probe script to determine whether
220-
# the pod should be restarted. The script checks a WebLogic Server state file which
221-
# is updated by the node manager.
222-
223-
STATEFILE=${stateFile}
224-
225-
if [ \`jps -l | grep -c " weblogic.NodeManager"\` -eq 0 ]; then
226-
echo "Error: WebLogic NodeManager process not found."
227-
exit 1
228-
fi
229-
230-
if [ -f \${STATEFILE} ] && [ \`grep -c "FAILED_NOT_RESTARTABLE" \${STATEFILE}\` -eq 1 ]; then
231-
echo "Error: WebLogic Server FAILED_NOT_RESTARTABLE."
232-
exit 1
233-
fi
234-
235-
echo "Info: Probe check passed."
236-
exit 0
237-
EOF
238-
239-
checkFileExists ${scriptFile}
240-
chmod +x ${scriptFile}
241-
242211
}
243212
244213
# Function to create script for stopping a server

kubernetes/internal/generate-security-policy.sh

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,8 +181,17 @@ rules:
181181
- apiGroups: [""]
182182
resources: ["secrets", "persistentvolumeclaims"]
183183
verbs: ["get", "list", "watch"]
184+
- apiGroups: ["storage.k8s.io"]
185+
resources: ["storageclasses"]
186+
verbs: ["get", "list", "watch"]
184187
- apiGroups: [""]
185-
resources: ["services", "pods", "networkpolicies"]
188+
resources: ["services", "configmaps", "pods", "jobs", "events"]
189+
verbs: ["get", "list", "watch", "create", "update", "patch", "delete", "deletecollection"]
190+
- apiGroups: ["settings.k8s.io"]
191+
resources: ["podpresets"]
192+
verbs: ["get", "list", "watch", "create", "update", "patch", "delete", "deletecollection"]
193+
- apiGroups: ["extensions"]
194+
resources: ["podsecuritypolicies", "networkpolicies"]
186195
verbs: ["get", "list", "watch", "create", "update", "patch", "delete", "deletecollection"]
187196
---
188197
EOF
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
// Copyright 2018, Oracle Corporation and/or its affiliates. All rights reserved.
2+
// Licensed under the Universal Permissive License v 1.0 as shown at http://oss.oracle.com/licenses/upl.
3+
4+
package oracle.kubernetes.operator;
5+
6+
import io.kubernetes.client.ApiException;
7+
import io.kubernetes.client.models.V1ConfigMap;
8+
import io.kubernetes.client.util.Watch;
9+
import oracle.kubernetes.operator.builders.WatchBuilder;
10+
import oracle.kubernetes.operator.builders.WatchI;
11+
import oracle.kubernetes.operator.helpers.ClientHelper;
12+
import oracle.kubernetes.operator.helpers.ClientHolder;
13+
import oracle.kubernetes.operator.watcher.Watcher;
14+
import oracle.kubernetes.operator.watcher.Watching;
15+
import oracle.kubernetes.operator.watcher.WatchingEventDestination;
16+
17+
import java.util.concurrent.atomic.AtomicBoolean;
18+
19+
/**
20+
* This class handles ConfigMap watching. It receives config map change events and sends
21+
* them into the operator for processing.
22+
*/
23+
public class ConfigMapWatcher implements Runnable {
24+
private final String ns;
25+
private final String initialResourceVersion;
26+
private final WatchingEventDestination<V1ConfigMap> destination;
27+
private final AtomicBoolean isStopping;
28+
29+
public static ConfigMapWatcher create(String ns, String initialResourceVersion, WatchingEventDestination<V1ConfigMap> destination, AtomicBoolean isStopping) {
30+
ConfigMapWatcher dlw = new ConfigMapWatcher(ns, initialResourceVersion, destination, isStopping);
31+
Thread thread = new Thread(dlw);
32+
thread.setName("Thread-ConfigMapWatcher-" + ns);
33+
thread.setDaemon(true);
34+
thread.start();
35+
return dlw;
36+
}
37+
38+
private ConfigMapWatcher(String ns, String initialResourceVersion, WatchingEventDestination<V1ConfigMap> destination, AtomicBoolean isStopping) {
39+
this.ns = ns;
40+
this.initialResourceVersion = initialResourceVersion;
41+
this.destination = destination;
42+
this.isStopping = isStopping;
43+
}
44+
45+
/**
46+
* Polling loop. Get the next ConfigMap object event and process it.
47+
*/
48+
@Override
49+
public void run() {
50+
ClientHelper helper = ClientHelper.getInstance();
51+
ClientHolder client = helper.take();
52+
try {
53+
Watching<V1ConfigMap> w = createWatching(client);
54+
Watcher<V1ConfigMap> watcher = new Watcher<>(w, initialResourceVersion);
55+
56+
// invoke watch on current Thread. Won't return until watch stops
57+
watcher.doWatch();
58+
59+
} finally {
60+
helper.recycle(client);
61+
}
62+
}
63+
64+
protected Watching<V1ConfigMap> createWatching(ClientHolder client) {
65+
return new Watching<V1ConfigMap>() {
66+
67+
/**
68+
* Watcher callback to issue the list ConfigMap changes. It is driven by the
69+
* Watcher wrapper to issue repeated watch requests.
70+
* @param resourceVersion resource version to omit older events
71+
* @return Watch object or null if the operation should end
72+
* @throws ApiException if there is an API error.
73+
*/
74+
@Override
75+
public WatchI<V1ConfigMap> initiateWatch(String resourceVersion) throws ApiException {
76+
return new WatchBuilder(client)
77+
.withResourceVersion(resourceVersion)
78+
.withLabelSelector(LabelConstants.CREATEDBYOPERATOR_LABEL)
79+
.createConfigMapWatch(ns);
80+
}
81+
82+
@Override
83+
public void eventCallback(Watch.Response<V1ConfigMap> item) {
84+
processEventCallback(item);
85+
}
86+
87+
@Override
88+
public boolean isStopping() {
89+
return isStopping.get();
90+
}
91+
};
92+
}
93+
94+
public void processEventCallback(Watch.Response<V1ConfigMap> item) {
95+
destination.eventCallback(item);
96+
}
97+
}

src/main/java/oracle/kubernetes/operator/KubernetesConstants.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,7 @@ public interface KubernetesConstants {
2121
public static final String DOMAIN_PLURAL = "domains";
2222
public static final String DOMAIN_SINGULAR = "domain";
2323
public static final String DOMAIN_SHORT = "dom";
24+
25+
public static final String DOMAIN_CONFIG_MAP_NAME = "weblogic-domain-config-map";
2426

2527
}

src/main/java/oracle/kubernetes/operator/Main.java

Lines changed: 58 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import java.util.concurrent.atomic.AtomicBoolean;
1717

1818
import io.kubernetes.client.ApiException;
19+
import io.kubernetes.client.models.V1ConfigMap;
1920
import io.kubernetes.client.models.V1DeleteOptions;
2021
import io.kubernetes.client.models.V1EnvVar;
2122
import io.kubernetes.client.models.V1ObjectMeta;
@@ -38,6 +39,7 @@
3839
import oracle.kubernetes.operator.helpers.CallBuilder;
3940
import oracle.kubernetes.operator.helpers.ClientHelper;
4041
import oracle.kubernetes.operator.helpers.ClientHolder;
42+
import oracle.kubernetes.operator.helpers.ConfigMapConsumer;
4143
import oracle.kubernetes.operator.helpers.ConfigMapHelper;
4244
import oracle.kubernetes.operator.helpers.DomainPresenceInfo;
4345
import oracle.kubernetes.operator.helpers.DomainPresenceInfo.ServerStartupInfo;
@@ -90,6 +92,7 @@ public class Main {
9092
private static String principal;
9193
private static RestServer restServer = null;
9294
private static Thread livenessThread = null;
95+
private static Map<String, ConfigMapWatcher> configMapWatchers = new HashMap<>();
9396
private static Map<String, DomainWatcher> domainWatchers = new HashMap<>();
9497
private static Map<String, PodWatcher> podWatchers = new HashMap<>();
9598
private static Map<String, ServiceWatcher> serviceWatchers = new HashMap<>();
@@ -117,9 +120,8 @@ public static void main(String[] args) {
117120

118121
Collection<String> targetNamespaces = getTargetNamespaces(namespace);
119122

120-
ConfigMapHelper cmh = new ConfigMapHelper("/operator/config");
121-
122-
String serviceAccountName = cmh.get("serviceaccount");
123+
ConfigMapConsumer cmc = new ConfigMapConsumer("/operator/config");
124+
String serviceAccountName = cmc.get("serviceaccount");
123125
if (serviceAccountName == null) {
124126
serviceAccountName = "default";
125127
}
@@ -206,7 +208,9 @@ public NextAction onSuccess(Packet packet, DomainList result, int statusCode,
206208
}
207209
});
208210

209-
Step initialize = CallBuilder.create().with($ -> {
211+
Step initialize = ConfigMapHelper.createScriptConfigMapStep(ns,
212+
new ConfigMapAfterStep(ns,
213+
CallBuilder.create().with($ -> {
210214
$.labelSelector = LabelConstants.DOMAINUID_LABEL
211215
+ "," + LabelConstants.CREATEDBYOPERATOR_LABEL;
212216
}).listPodAsync(ns, new ResponseStep<V1PodList>(
@@ -318,7 +322,7 @@ public NextAction onSuccess(Packet packet, V1PodList result, int statusCode,
318322
podWatchers.put(ns, createPodWatcher(ns, result != null ? result.getMetadata().getResourceVersion() : ""));
319323
return doNext(packet);
320324
}
321-
});
325+
})));
322326

323327
engine.createFiber().start(initialize, new Packet(), new CompletionCallback() {
324328
@Override
@@ -1420,8 +1424,8 @@ public NextAction onSuccess(Packet packet, V1Status result, int statusCode, Map<
14201424
private static Collection<String> getTargetNamespaces(String namespace) {
14211425
Collection<String> targetNamespaces = new ArrayList<String>();
14221426

1423-
ConfigMapHelper cmh = new ConfigMapHelper("/operator/config");
1424-
String tnValue = cmh.get("targetNamespaces");
1427+
ConfigMapConsumer cmc = new ConfigMapConsumer("/operator/config");
1428+
String tnValue = cmc.get("targetNamespaces");
14251429
if (tnValue != null) {
14261430
StringTokenizer st = new StringTokenizer(tnValue, ",");
14271431
while (st.hasMoreTokens()) {
@@ -1667,6 +1671,53 @@ private static void dispatchIngressWatch(Watch.Response<V1beta1Ingress> item) {
16671671
}
16681672
}
16691673

1674+
private static class ConfigMapAfterStep extends Step {
1675+
private final String ns;
1676+
1677+
public ConfigMapAfterStep(String ns, Step next) {
1678+
super(next);
1679+
this.ns = ns;
1680+
}
1681+
1682+
@Override
1683+
public NextAction apply(Packet packet) {
1684+
V1ConfigMap result = (V1ConfigMap) packet.get(ProcessingConstants.SCRIPT_CONFIG_MAP);
1685+
configMapWatchers.put(ns, createConfigMapWatcher(ns, result != null ? result.getMetadata().getResourceVersion() : ""));
1686+
return doNext(packet);
1687+
}
1688+
}
1689+
1690+
private static ConfigMapWatcher createConfigMapWatcher(String namespace, String initialResourceVersion) {
1691+
return ConfigMapWatcher.create(namespace, initialResourceVersion, Main::dispatchConfigMapWatch, stopping);
1692+
}
1693+
1694+
private static void dispatchConfigMapWatch(Watch.Response<V1ConfigMap> item) {
1695+
V1ConfigMap c = item.object;
1696+
if (c != null) {
1697+
switch (item.type) {
1698+
case "MODIFIED":
1699+
case "DELETED":
1700+
engine.createFiber().start(
1701+
ConfigMapHelper.createScriptConfigMapStep(c.getMetadata().getNamespace(), null),
1702+
new Packet(), new CompletionCallback() {
1703+
@Override
1704+
public void onCompletion(Packet packet) {
1705+
// no-op
1706+
}
1707+
1708+
@Override
1709+
public void onThrowable(Packet packet, Throwable throwable) {
1710+
LOGGER.severe(MessageKeys.EXCEPTION, throwable);
1711+
}
1712+
});
1713+
break;
1714+
1715+
case "ERROR":
1716+
default:
1717+
}
1718+
}
1719+
}
1720+
16701721
/**
16711722
* Dispatch the Domain event to the appropriate handler.
16721723
*

src/main/java/oracle/kubernetes/operator/ProcessingConstants.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,6 @@ public interface ProcessingConstants {
2828
public static final String EXPLICIT_RESTART_SERVERS = "explicitRestartServers";
2929
public static final String EXPLICIT_RESTART_CLUSTERS = "explicitRestartClusters";
3030

31+
public static final String SCRIPT_CONFIG_MAP = "scriptConfigMap";
32+
3133
}

src/main/java/oracle/kubernetes/operator/ServiceWatcher.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
import java.util.concurrent.atomic.AtomicBoolean;
2020

2121
/**
22-
* This class handles Service watching. It service change events and sends
22+
* This class handles Service watching. It receives service change events and sends
2323
* them into the operator for processing.
2424
*/
2525
public class ServiceWatcher implements Runnable {

src/main/java/oracle/kubernetes/operator/builders/WatchBuilder.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import io.kubernetes.client.ApiException;
88
import io.kubernetes.client.ProgressRequestBody;
99
import io.kubernetes.client.ProgressResponseBody;
10+
import io.kubernetes.client.models.V1ConfigMap;
1011
import io.kubernetes.client.models.V1Pod;
1112
import io.kubernetes.client.models.V1Service;
1213
import io.kubernetes.client.models.V1beta1Ingress;
@@ -179,6 +180,36 @@ public Call apply(ClientHolder clientHolder, CallParams callParams) {
179180
}
180181
}
181182

183+
/**
184+
* Creates a web hook object to track config map calls
185+
* @param namespace the namespace
186+
* @return the active web hook
187+
* @throws ApiException if there is an error on the call that sets up the web hook.
188+
*/
189+
public WatchI<V1ConfigMap> createConfigMapWatch(String namespace) throws ApiException {
190+
return FACTORY.createWatch(clientHolder, callParams, V1ConfigMap.class, new ListNamespacedConfigMapCall(namespace));
191+
}
192+
193+
private class ListNamespacedConfigMapCall implements BiFunction<ClientHolder, CallParams, Call> {
194+
private String namespace;
195+
196+
ListNamespacedConfigMapCall(String namespace) {
197+
this.namespace = namespace;
198+
}
199+
200+
@Override
201+
public Call apply(ClientHolder clientHolder, CallParams callParams) {
202+
try {
203+
return clientHolder.getCoreApiClient().listNamespacedConfigMapCall(namespace,
204+
callParams.getPretty(), START_LIST,
205+
callParams.getFieldSelector(), callParams.getIncludeUninitialized(), callParams.getLabelSelector(),
206+
callParams.getLimit(), callParams.getResourceVersion(), callParams.getTimeoutSeconds(), WATCH, null, null);
207+
} catch (ApiException e) {
208+
throw new UncheckedApiException(e);
209+
}
210+
}
211+
}
212+
182213
/**
183214
* Sets a value for the fieldSelector parameter for the call that will set up this watch. Defaults to null.
184215
* @param fieldSelector the desired value

src/main/java/oracle/kubernetes/operator/helpers/AnnotationHelper.java

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,22 @@
66
import java.util.Objects;
77

88
import io.kubernetes.client.models.V1ObjectMeta;
9-
import oracle.kubernetes.weblogic.domain.v1.Domain;
109

1110
/**
1211
* Annotates pods, services with details about the Domain instance and checks these annotations.
1312
*
1413
*/
1514
public class AnnotationHelper {
1615

17-
private static final String DOMAIN_RESOURCE_VERSION = "weblogic.oracle/domain-resourceVersion";
16+
private static final String FORMAT_ANNOTATION = "weblogic.oracle/operator-formatVersion";
17+
private static final String FORMAT_VERSION = "1";
1818

1919
/**
20-
* Marks metadata object with an annotation saying that it was created for this domain and resource version
20+
* Marks metadata object with an annotation saying that it was created for this format version
2121
* @param meta Metadata object that will be included in a newly created resource, e.g. pod or service
22-
* @param domain The domain
2322
*/
24-
public static void annotateWithDomain(V1ObjectMeta meta, Domain domain) {
25-
String domainResourceVersion = domain.getMetadata().getResourceVersion();
26-
if (domainResourceVersion != null) {
27-
meta.putAnnotationsItem(DOMAIN_RESOURCE_VERSION, domainResourceVersion);
28-
}
23+
public static void annotateWithFormat(V1ObjectMeta meta) {
24+
meta.putAnnotationsItem(FORMAT_ANNOTATION, FORMAT_VERSION);
2925
}
3026

3127

@@ -43,14 +39,12 @@ public static void annotateForPrometheus(V1ObjectMeta meta, int httpPort) {
4339
}
4440

4541
/**
46-
* Check the metadata object for the presence of an annotation matching the domain and resource version.l
42+
* Check the metadata object for the presence of an annotation matching the expected format version.
4743
* @param meta The metadata object
48-
* @param domain The domain
49-
* @return true, if the metadata includes an annotation matching this domain
44+
* @return true, if the metadata includes an annotation matching the expected format version
5045
*/
51-
public static boolean checkDomainAnnotation(V1ObjectMeta meta, Domain domain) {
52-
String domainResourceVersion = domain.getMetadata().getResourceVersion();
53-
String metaResourceVersion = meta.getAnnotations().get(DOMAIN_RESOURCE_VERSION);
54-
return Objects.equals(domainResourceVersion, metaResourceVersion);
46+
public static boolean checkFormatAnnotation(V1ObjectMeta meta) {
47+
String metaResourceVersion = meta.getAnnotations().get(FORMAT_ANNOTATION);
48+
return Objects.equals(FORMAT_VERSION, metaResourceVersion);
5549
}
5650
}

0 commit comments

Comments
 (0)