Concretize what is a persistent volume component.

Handle two different versions of specifying that a component is a volume storage

Change-Id: I9d3d621388f4a14a8ed9a71515d771c1461242ea
This commit is contained in:
Rudi Schlatte 2024-06-03 15:41:10 +02:00
parent 6a4e06360a
commit 8992468386

View File

@ -10,7 +10,6 @@ import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.ow2.proactive.sal.model.AttributeRequirement; import org.ow2.proactive.sal.model.AttributeRequirement;
import org.ow2.proactive.sal.model.OperatingSystemFamily;
import org.ow2.proactive.sal.model.Requirement; import org.ow2.proactive.sal.model.Requirement;
import org.ow2.proactive.sal.model.RequirementOperator; import org.ow2.proactive.sal.model.RequirementOperator;
import java.util.ArrayList; import java.util.ArrayList;
@ -18,6 +17,9 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.stream.StreamSupport;
/** /**
* A collection of methods to extract node requirements from KubeVela files. * A collection of methods to extract node requirements from KubeVela files.
@ -27,6 +29,54 @@ public class KubevelaAnalyzer {
private static final ObjectMapper yamlMapper = new ObjectMapper(new YAMLFactory()); private static final ObjectMapper yamlMapper = new ObjectMapper(new YAMLFactory());
/**
* Return true if a component is a volume storage node. If true, such a
* node should not be rewritten during deployment, and no virtual machine
* should be created.<p>
*
* We currently look for one of the following structures in a component:
*
* <pre>{@code
* type: raw
* properties:
* apiVersion: v1
* kind: PersistentVolumeClaim
* }</pre>
*
* or
*
* <pre>{@code
* type: k8s-objects
* properties:
* objects:
* - apiVersion: v1
* kind: PersistentVolumeClaim
* }</pre>
*
* Note: In the two samples above, the objects will have other attributes
* as well, which we omit for brevity.<p>
*
* Note: This method should be redesigned once we discover other kinds of
* nodes (currently we have compute nodes and volume storage nodes).<p>
*
* @param component The component; should be a child of the {@code spec:}
* top-level array in the KubeVela YAML.
*
* @return true if component is a volume storage node.
*/
public static final boolean isVolumeStorageComponent(JsonNode component) {
boolean form1 = component.at("/type").asText().equals("raw")
&& component.at("/properties/kind").asText().equals("PersistentVolumeClaim");
boolean form2 = component.at("/type").asText().equals("k8s-objects")
&& StreamSupport.stream(
Spliterators.spliteratorUnknownSize(
component.withArray("/properties/objects")
.elements(), Spliterator.ORDERED), false)
.anyMatch((o) -> o.at("/kind").asText()
.equals("PersistentVolumeClaim"));
return form1 || form2;
}
/** /**
* Given a KubeVela file, extract how many nodes to deploy for each * Given a KubeVela file, extract how many nodes to deploy for each
* component. Note that this can be zero when the component should not be * component. Note that this can be zero when the component should not be
@ -51,8 +101,7 @@ public class KubevelaAnalyzer {
Map<String, Integer> result = new HashMap<>(); Map<String, Integer> result = new HashMap<>();
ArrayNode components = kubevela.withArray("/spec/components"); ArrayNode components = kubevela.withArray("/spec/components");
for (final JsonNode c : components) { for (final JsonNode c : components) {
// Skip components that define a volume if (isVolumeStorageComponent(c)) continue;
if (c.at("/type").asText().equals("raw")) continue;
result.put(c.get("name").asText(), 1); // default value; might get overwritten result.put(c.get("name").asText(), 1); // default value; might get overwritten
for (final JsonNode t : c.withArray("/traits")) { for (final JsonNode t : c.withArray("/traits")) {
if (t.at("/type").asText().equals("scaler") if (t.at("/type").asText().equals("scaler")
@ -183,7 +232,8 @@ public class KubevelaAnalyzer {
* *
* - When asked to, we add the requirement that memory >= 2GB.<p> * - When asked to, we add the requirement that memory >= 2GB.<p>
* *
* - We skip components with `type: raw`, since these define volumes.<p> * - We skip volume storage components, since there is no virtual machine
* created for those.<p>
* *
* - For the first version, we specify all requirements as "greater or * - For the first version, we specify all requirements as "greater or
* equal", i.e., we might not find precisely the node candidates that * equal", i.e., we might not find precisely the node candidates that
@ -204,15 +254,13 @@ public class KubevelaAnalyzer {
* includeNebulousRequirements is true. * includeNebulousRequirements is true.
* @return a map of component name to (potentially empty) list of * @return a map of component name to (potentially empty) list of
* requirements for that component. No requirements mean any node will * requirements for that component. No requirements mean any node will
* suffice. No requirements are generated for components with * suffice. No requirements are generated for volume storage components.
* `type:raw`.
*/ */
public static Map<String, List<Requirement>> getBoundedRequirements(JsonNode kubevela, boolean includeNebulousRequirements, Set<String> cloudIDs) { public static Map<String, List<Requirement>> getBoundedRequirements(JsonNode kubevela, boolean includeNebulousRequirements, Set<String> cloudIDs) {
Map<String, List<Requirement>> result = new HashMap<>(); Map<String, List<Requirement>> result = new HashMap<>();
ArrayNode components = kubevela.withArray("/spec/components"); ArrayNode components = kubevela.withArray("/spec/components");
for (final JsonNode c : components) { for (final JsonNode c : components) {
// Skip components that define a volume if (isVolumeStorageComponent(c)) continue;
if (c.at("/type").asText().equals("raw")) continue;
String componentName = c.get("name").asText(); String componentName = c.get("name").asText();
ArrayList<Requirement> reqs = new ArrayList<>(); ArrayList<Requirement> reqs = new ArrayList<>();
if (includeNebulousRequirements) { if (includeNebulousRequirements) {