Support additional metadata for services.
This commit is contained in:
parent
477db06f8d
commit
0e3bb88497
7 changed files with 117 additions and 7 deletions
|
|
@ -923,6 +923,38 @@ spec:
|
|||
type: string
|
||||
update:
|
||||
type: boolean
|
||||
additionalServiceMetadata:
|
||||
description: >-
|
||||
Data to be merged with the additionalServiceMetadata
|
||||
defined in the manager's configuration. Values
|
||||
specified here override values from the manager's
|
||||
configuration. If the value of a label or an annotation
|
||||
is null, the property with the corresponding key is
|
||||
deleted from the properties defined in the manager's
|
||||
configuration.
|
||||
type: object
|
||||
properties:
|
||||
labels:
|
||||
description: >-
|
||||
Map of string keys and values that can be
|
||||
used to organize and categorize (scope and select) objects.
|
||||
May match selectors of replication controllers and services.
|
||||
More info: http://kubernetes.io/docs/user-guide/labels
|
||||
type: object
|
||||
additionalProperties:
|
||||
type: string
|
||||
nullable: true
|
||||
annotations:
|
||||
description: >-
|
||||
Annotations is an unstructured key value
|
||||
map stored with a resource that may be set by external
|
||||
tools to store and retrieve arbitrary metadata. They
|
||||
are not queryable and should be preserved when modifying
|
||||
objects. More info: http://kubernetes.io/docs/user-guide/annotations
|
||||
type: object
|
||||
additionalProperties:
|
||||
type: string
|
||||
nullable: true
|
||||
vm:
|
||||
type: object
|
||||
description: Defines the VM.
|
||||
|
|
|
|||
|
|
@ -5,3 +5,7 @@
|
|||
namespace: vmop-dev
|
||||
runnerData:
|
||||
storageClassName: null
|
||||
additionalServiceMetadata:
|
||||
labels:
|
||||
test1: remains
|
||||
test2: deleted
|
||||
|
|
|
|||
|
|
@ -11,6 +11,11 @@ spec:
|
|||
|
||||
runnerTemplate:
|
||||
update: true
|
||||
|
||||
additionalServiceMetadata:
|
||||
labels:
|
||||
test2: null
|
||||
test3: added
|
||||
|
||||
vm:
|
||||
state: Running
|
||||
|
|
|
|||
|
|
@ -5,12 +5,20 @@
|
|||
# Values used when creating the PVC for the runner's data
|
||||
runnerData:
|
||||
storageClassName: null
|
||||
|
||||
# Amount by which the current cpu count is devided when generating
|
||||
# the resource properties.
|
||||
cpuOvercommit: 2
|
||||
|
||||
# Amount by which the current ram size is devided when generating
|
||||
# the resource properties.
|
||||
ramOvercommit: 1.5
|
||||
|
||||
|
||||
# Additional metadata (labels and annotations) to be merged
|
||||
# into the service
|
||||
# additionalServiceMetdata:
|
||||
# labels: {}
|
||||
# annotations: {}
|
||||
|
||||
# Only for development:
|
||||
# namespace: vmop-dev
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ public class GsonPtr {
|
|||
/**
|
||||
* Create a new instance pointing to the {@link JsonElement}
|
||||
* selected by the given selectors. If a selector of type
|
||||
* {@link String} denoted a non-existant member of a
|
||||
* {@link String} denotes a non-existant member of a
|
||||
* {@link JsonObject}, a new member (of type {@link JsonObject}
|
||||
* is added.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -96,9 +96,7 @@ public class Reconciler extends Component {
|
|||
public void onConfigurationUpdate(ConfigurationUpdate event) {
|
||||
event.structured(Components.manager(parent()).componentPath())
|
||||
.ifPresent(c -> {
|
||||
if (c.containsKey("runnerData")) {
|
||||
config.put("runnerData", c.get("runnerData"));
|
||||
}
|
||||
config.putAll(c);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,14 +18,20 @@
|
|||
|
||||
package org.jdrupes.vmoperator.manager;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import freemarker.template.Configuration;
|
||||
import freemarker.template.TemplateException;
|
||||
import io.kubernetes.client.openapi.ApiException;
|
||||
import io.kubernetes.client.openapi.models.V1APIService;
|
||||
import io.kubernetes.client.openapi.models.V1ObjectMeta;
|
||||
import io.kubernetes.client.util.generic.dynamic.DynamicKubernetesApi;
|
||||
import io.kubernetes.client.util.generic.dynamic.DynamicKubernetesObject;
|
||||
import io.kubernetes.client.util.generic.dynamic.Dynamics;
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.logging.Logger;
|
||||
import org.yaml.snakeyaml.LoaderOptions;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
|
|
@ -37,6 +43,11 @@ import org.yaml.snakeyaml.constructor.SafeConstructor;
|
|||
@SuppressWarnings("PMD.DataflowAnomalyAnalysis")
|
||||
/* default */ class ServiceReconciler {
|
||||
|
||||
private static final String METADATA
|
||||
= V1APIService.SERIALIZED_NAME_METADATA;
|
||||
private static final String LABELS = V1ObjectMeta.SERIALIZED_NAME_LABELS;
|
||||
private static final String ANNOTATIONS
|
||||
= V1ObjectMeta.SERIALIZED_NAME_ANNOTATIONS;
|
||||
protected final Logger logger = Logger.getLogger(getClass().getName());
|
||||
private final Configuration fmConfig;
|
||||
|
||||
|
|
@ -72,11 +83,63 @@ import org.yaml.snakeyaml.constructor.SafeConstructor;
|
|||
fmTemplate.process(model, out);
|
||||
// Avoid Yaml.load due to
|
||||
// https://github.com/kubernetes-client/java/issues/2741
|
||||
var mapDef = Dynamics.newFromYaml(
|
||||
var svcDef = Dynamics.newFromYaml(
|
||||
new Yaml(new SafeConstructor(new LoaderOptions())), out.toString());
|
||||
mergeMetadata(svcDef, model, channel);
|
||||
|
||||
// Apply
|
||||
K8s.apply(svcApi, mapDef, out.toString());
|
||||
K8s.apply(svcApi, svcDef, svcDef.getRaw().toString());
|
||||
}
|
||||
|
||||
private void mergeMetadata(DynamicKubernetesObject svcDef,
|
||||
Map<String, Object> model, VmChannel channel) {
|
||||
// Get metadata from config
|
||||
@SuppressWarnings("unchecked")
|
||||
var asmData = Optional.of(model)
|
||||
.map(m -> (Map<String, Object>) m.get("config"))
|
||||
.map(c -> (Map<String, Object>) c.get("additionalServiceMetadata"))
|
||||
.orElseGet(() -> new HashMap<>());
|
||||
var json = channel.client().getJSON();
|
||||
JsonObject cfgMeta
|
||||
= json.deserialize(json.serialize(asmData), JsonObject.class);
|
||||
|
||||
// Get metadata from VM definition
|
||||
var vmMeta = GsonPtr.to(channel.vmDefinition()).to("spec")
|
||||
.get(JsonObject.class, "additionalServiceMetadata")
|
||||
.map(JsonObject::deepCopy).orElseGet(() -> new JsonObject());
|
||||
|
||||
// Merge Data from VM definition into config data
|
||||
mergeReplace(GsonPtr.to(cfgMeta).to(LABELS).get(JsonObject.class),
|
||||
GsonPtr.to(vmMeta).to(LABELS).get(JsonObject.class));
|
||||
mergeReplace(
|
||||
GsonPtr.to(cfgMeta).to(ANNOTATIONS).get(JsonObject.class),
|
||||
GsonPtr.to(vmMeta).to(ANNOTATIONS).get(JsonObject.class));
|
||||
|
||||
// Merge additional data into service definition
|
||||
var svcMeta = GsonPtr.to(svcDef.getRaw()).to(METADATA);
|
||||
mergeIfAbsent(svcMeta.to(LABELS).get(JsonObject.class),
|
||||
GsonPtr.to(cfgMeta).to(LABELS).get(JsonObject.class));
|
||||
mergeIfAbsent(svcMeta.to(ANNOTATIONS).get(JsonObject.class),
|
||||
GsonPtr.to(cfgMeta).to(ANNOTATIONS).get(JsonObject.class));
|
||||
}
|
||||
|
||||
private void mergeReplace(JsonObject dest, JsonObject src) {
|
||||
for (var e : src.entrySet()) {
|
||||
if (e.getValue().isJsonNull()) {
|
||||
dest.remove(e.getKey());
|
||||
continue;
|
||||
}
|
||||
dest.add(e.getKey(), e.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private void mergeIfAbsent(JsonObject dest, JsonObject src) {
|
||||
for (var e : src.entrySet()) {
|
||||
if (dest.has(e.getKey())) {
|
||||
continue;
|
||||
}
|
||||
dest.add(e.getKey(), e.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue