Skip to content

Commit 8fec6c8

Browse files
committed
Add support for SpEL to Kubernetes patches and additional manifests
1 parent f665e57 commit 8fec6c8

2 files changed

Lines changed: 30 additions & 43 deletions

File tree

src/main/java/eu/openanalytics/containerproxy/backend/kubernetes/KubernetesBackend.java

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,17 +39,20 @@
3939
import java.util.UUID;
4040
import java.util.function.BiConsumer;
4141
import java.util.stream.Collectors;
42+
import javax.json.JsonPatch;
4243

4344
import javax.inject.Inject;
4445

4546
import org.apache.commons.io.IOUtils;
4647

4748
import com.fasterxml.jackson.core.JsonParseException;
49+
import com.fasterxml.jackson.core.JsonProcessingException;
4850
import com.fasterxml.jackson.databind.JsonMappingException;
4951
import com.fasterxml.jackson.databind.MapperFeature;
5052
import com.fasterxml.jackson.databind.ObjectMapper;
5153
import com.fasterxml.jackson.databind.SerializationFeature;
5254
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
55+
import com.fasterxml.jackson.datatype.jsr353.JSR353Module;
5356
import com.google.common.base.Charsets;
5457
import com.google.common.base.Splitter;
5558

@@ -59,6 +62,8 @@
5962
import eu.openanalytics.containerproxy.model.runtime.Container;
6063
import eu.openanalytics.containerproxy.model.runtime.Proxy;
6164
import eu.openanalytics.containerproxy.model.spec.ContainerSpec;
65+
import eu.openanalytics.containerproxy.spec.expression.SpecExpressionContext;
66+
import eu.openanalytics.containerproxy.spec.expression.SpecExpressionResolver;
6267
import eu.openanalytics.containerproxy.util.Retrying;
6368
import io.fabric8.kubernetes.api.model.ContainerBuilder;
6469
import io.fabric8.kubernetes.api.model.ContainerPort;
@@ -258,8 +263,10 @@ protected Container startContainer(ContainerSpec spec, Proxy proxy) throws Excep
258263
podSpec.setNodeSelector(Splitter.on(",").withKeyValueSeparator("=").split(nodeSelectorString));
259264
}
260265

266+
JsonPatch patch = readPatchFromSpec(spec, proxy);
267+
261268
Pod startupPod = podBuilder.withSpec(podSpec).build();
262-
Pod patchedPod = podPatcher.patchWithDebug(startupPod, proxy.getSpec().getKubernetesPodPatchAsJsonpatch());
269+
Pod patchedPod = podPatcher.patchWithDebug(startupPod, patch);
263270
final String effectiveKubeNamespace = patchedPod.getMetadata().getNamespace(); // use the namespace of the patched Pod, in case the patch changes the namespace.
264271
container.getParameters().put(PARAM_NAMESPACE, effectiveKubeNamespace);
265272

@@ -322,6 +329,20 @@ protected Container startContainer(ContainerSpec spec, Proxy proxy) throws Excep
322329
return container;
323330
}
324331

332+
private JsonPatch readPatchFromSpec(ContainerSpec containerSpec, Proxy proxy) throws JsonMappingException, JsonProcessingException {
333+
String patchAsString = proxy.getSpec().getKubernetesPodPatch();
334+
if (patchAsString == null) {
335+
return null;
336+
}
337+
338+
// resolve expressions
339+
SpecExpressionContext context = SpecExpressionContext.create(containerSpec, proxy, proxy.getSpec());
340+
String expressionAwarePatch = expressionResolver.evaluateToString(patchAsString, context);
341+
342+
ObjectMapper yamlReader = new ObjectMapper(new YAMLFactory());
343+
yamlReader.registerModule(new JSR353Module());
344+
return yamlReader.readValue(expressionAwarePatch, JsonPatch.class);
345+
}
325346

326347
/**
327348
* Creates the extra manifests/resources defined in the ProxySpec.
@@ -342,11 +363,14 @@ private void createAdditionalManifstes(Proxy proxy, String namespace) {
342363
* parameter will be used.
343364
*/
344365
private List<HasMetadata> getAdditionManifestsAsObjects(Proxy proxy, String namespace) {
366+
SpecExpressionContext context = SpecExpressionContext.create(proxy, proxy.getSpec());
367+
345368
ArrayList<HasMetadata> result = new ArrayList<HasMetadata>();
346369
for (String manifest : proxy.getSpec().getKubernetesAdditionalManifests()) {
347-
HasMetadata object = Serialization.unmarshal(new ByteArrayInputStream(manifest.getBytes())); // used to determine whether the manifest has specified a namespace
370+
String expressionManifest = expressionResolver.evaluateToString(manifest, context);
371+
HasMetadata object = Serialization.unmarshal(new ByteArrayInputStream(expressionManifest.getBytes())); // used to determine whether the manifest has specified a namespace
348372

349-
HasMetadata fullObject = kubeClient.load(new ByteArrayInputStream(manifest.getBytes())).get().get(0);
373+
HasMetadata fullObject = kubeClient.load(new ByteArrayInputStream(expressionManifest.getBytes())).get().get(0);
350374
if (object.getMetadata().getNamespace() == null) {
351375
// the load method (in some cases) automatically sets a namepsace when no namespace is provided
352376
// therefore we overwrite this namespace with the namsepace of the pod.

src/main/java/eu/openanalytics/containerproxy/model/spec/ProxySpec.java

Lines changed: 3 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -20,23 +20,12 @@
2020
*/
2121
package eu.openanalytics.containerproxy.model.spec;
2222

23-
import java.io.IOException;
2423
import java.util.ArrayList;
2524
import java.util.HashMap;
2625
import java.util.List;
2726
import java.util.Map;
2827
import java.util.stream.Collectors;
2928

30-
import javax.json.JsonPatch;
31-
import javax.json.JsonValue;
32-
33-
import com.fasterxml.jackson.annotation.JsonIgnore;
34-
import com.fasterxml.jackson.core.JsonParseException;
35-
import com.fasterxml.jackson.databind.JsonMappingException;
36-
import com.fasterxml.jackson.databind.ObjectMapper;
37-
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
38-
import com.fasterxml.jackson.datatype.jsr353.JSR353Module;
39-
4029
public class ProxySpec {
4130

4231
private String id;
@@ -50,7 +39,7 @@ public class ProxySpec {
5039

5140
private Map<String, String> settings = new HashMap<>();
5241

53-
private JsonPatch kubernetesPodPatches;
42+
private String kubernetesPodPatches;
5443
private List<String> kubernetesAdditionalManifests = new ArrayList<>();
5544

5645
public ProxySpec() {
@@ -124,36 +113,11 @@ public void setSettings(Map<String, String> settings) {
124113
/**
125114
* Returns the Kubernetes Pod Patch as JsonValue (i.e. array) for nice representation in API requests.
126115
*/
127-
public JsonValue getKubernetesPodPatch() {
128-
if (this.kubernetesPodPatches == null) {
129-
return null;
130-
} else {
131-
return kubernetesPodPatches.toJsonArray();
132-
}
133-
}
134-
135-
/**
136-
* Returns the Kubernetes Pod Patch as a JsonPatch, so it can be directly be used to patch the spec.
137-
* Should not be returned by API responses.
138-
*/
139-
@JsonIgnore
140-
public JsonPatch getKubernetesPodPatchAsJsonpatch() {
116+
public String getKubernetesPodPatch() {
141117
return kubernetesPodPatches;
142118
}
143119

144-
public void setKubernetesPodPatches(String kubernetesPodPatches) throws JsonParseException, JsonMappingException, IOException {
145-
try {
146-
// convert the raw YAML string into a JsonPatch
147-
ObjectMapper yamlReader = new ObjectMapper(new YAMLFactory());
148-
yamlReader.registerModule(new JSR353Module());
149-
this.kubernetesPodPatches = yamlReader.readValue(kubernetesPodPatches, JsonPatch.class);
150-
} catch (Exception exception) {
151-
exception.printStackTrace(); // log the exception for easier debugging
152-
throw exception;
153-
}
154-
}
155-
156-
private void setKubernetesPodPatches(JsonPatch kubernetesPodPatches) {
120+
public void setKubernetesPodPatches(String kubernetesPodPatches) {
157121
this.kubernetesPodPatches = kubernetesPodPatches;
158122
}
159123

@@ -201,7 +165,6 @@ public void copy(ProxySpec target) {
201165

202166

203167
if (kubernetesPodPatches != null) {
204-
// JsonPatch is an immutable object
205168
target.setKubernetesPodPatches(kubernetesPodPatches);
206169
}
207170

0 commit comments

Comments
 (0)