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
|
type: string
|
||||||
update:
|
update:
|
||||||
type: boolean
|
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:
|
vm:
|
||||||
type: object
|
type: object
|
||||||
description: Defines the VM.
|
description: Defines the VM.
|
||||||
|
|
|
||||||
|
|
@ -5,3 +5,7 @@
|
||||||
namespace: vmop-dev
|
namespace: vmop-dev
|
||||||
runnerData:
|
runnerData:
|
||||||
storageClassName: null
|
storageClassName: null
|
||||||
|
additionalServiceMetadata:
|
||||||
|
labels:
|
||||||
|
test1: remains
|
||||||
|
test2: deleted
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,11 @@ spec:
|
||||||
runnerTemplate:
|
runnerTemplate:
|
||||||
update: true
|
update: true
|
||||||
|
|
||||||
|
additionalServiceMetadata:
|
||||||
|
labels:
|
||||||
|
test2: null
|
||||||
|
test3: added
|
||||||
|
|
||||||
vm:
|
vm:
|
||||||
state: Running
|
state: Running
|
||||||
bootMenu: yes
|
bootMenu: yes
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,20 @@
|
||||||
# Values used when creating the PVC for the runner's data
|
# Values used when creating the PVC for the runner's data
|
||||||
runnerData:
|
runnerData:
|
||||||
storageClassName: null
|
storageClassName: null
|
||||||
|
|
||||||
# Amount by which the current cpu count is devided when generating
|
# Amount by which the current cpu count is devided when generating
|
||||||
# the resource properties.
|
# the resource properties.
|
||||||
cpuOvercommit: 2
|
cpuOvercommit: 2
|
||||||
|
|
||||||
# Amount by which the current ram size is devided when generating
|
# Amount by which the current ram size is devided when generating
|
||||||
# the resource properties.
|
# the resource properties.
|
||||||
ramOvercommit: 1.5
|
ramOvercommit: 1.5
|
||||||
|
|
||||||
|
# Additional metadata (labels and annotations) to be merged
|
||||||
|
# into the service
|
||||||
|
# additionalServiceMetdata:
|
||||||
|
# labels: {}
|
||||||
|
# annotations: {}
|
||||||
|
|
||||||
# Only for development:
|
# Only for development:
|
||||||
# namespace: vmop-dev
|
# namespace: vmop-dev
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ public class GsonPtr {
|
||||||
/**
|
/**
|
||||||
* Create a new instance pointing to the {@link JsonElement}
|
* Create a new instance pointing to the {@link JsonElement}
|
||||||
* selected by the given selectors. If a selector of type
|
* 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}
|
* {@link JsonObject}, a new member (of type {@link JsonObject}
|
||||||
* is added.
|
* is added.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -96,9 +96,7 @@ public class Reconciler extends Component {
|
||||||
public void onConfigurationUpdate(ConfigurationUpdate event) {
|
public void onConfigurationUpdate(ConfigurationUpdate event) {
|
||||||
event.structured(Components.manager(parent()).componentPath())
|
event.structured(Components.manager(parent()).componentPath())
|
||||||
.ifPresent(c -> {
|
.ifPresent(c -> {
|
||||||
if (c.containsKey("runnerData")) {
|
config.putAll(c);
|
||||||
config.put("runnerData", c.get("runnerData"));
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,14 +18,20 @@
|
||||||
|
|
||||||
package org.jdrupes.vmoperator.manager;
|
package org.jdrupes.vmoperator.manager;
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
import freemarker.template.Configuration;
|
import freemarker.template.Configuration;
|
||||||
import freemarker.template.TemplateException;
|
import freemarker.template.TemplateException;
|
||||||
import io.kubernetes.client.openapi.ApiException;
|
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.DynamicKubernetesApi;
|
||||||
|
import io.kubernetes.client.util.generic.dynamic.DynamicKubernetesObject;
|
||||||
import io.kubernetes.client.util.generic.dynamic.Dynamics;
|
import io.kubernetes.client.util.generic.dynamic.Dynamics;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import org.yaml.snakeyaml.LoaderOptions;
|
import org.yaml.snakeyaml.LoaderOptions;
|
||||||
import org.yaml.snakeyaml.Yaml;
|
import org.yaml.snakeyaml.Yaml;
|
||||||
|
|
@ -37,6 +43,11 @@ import org.yaml.snakeyaml.constructor.SafeConstructor;
|
||||||
@SuppressWarnings("PMD.DataflowAnomalyAnalysis")
|
@SuppressWarnings("PMD.DataflowAnomalyAnalysis")
|
||||||
/* default */ class ServiceReconciler {
|
/* 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());
|
protected final Logger logger = Logger.getLogger(getClass().getName());
|
||||||
private final Configuration fmConfig;
|
private final Configuration fmConfig;
|
||||||
|
|
||||||
|
|
@ -72,11 +83,63 @@ import org.yaml.snakeyaml.constructor.SafeConstructor;
|
||||||
fmTemplate.process(model, out);
|
fmTemplate.process(model, out);
|
||||||
// Avoid Yaml.load due to
|
// Avoid Yaml.load due to
|
||||||
// https://github.com/kubernetes-client/java/issues/2741
|
// https://github.com/kubernetes-client/java/issues/2741
|
||||||
var mapDef = Dynamics.newFromYaml(
|
var svcDef = Dynamics.newFromYaml(
|
||||||
new Yaml(new SafeConstructor(new LoaderOptions())), out.toString());
|
new Yaml(new SafeConstructor(new LoaderOptions())), out.toString());
|
||||||
|
mergeMetadata(svcDef, model, channel);
|
||||||
|
|
||||||
// Apply
|
// 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