use of io.kubernetes.client.custom.Quantity in project heron by twitter.
the class V1Controller method configureContainerResources.
/**
* Configures the resources in the <code>container</code> with values in the <code>config</code> taking precedence.
* @param container The <code>container</code> to be configured.
* @param configuration The <code>Config</code> object to check if a resource request needs to be set.
* @param resource User defined resources limits from input.
* @param isExecutor Flag to indicate configuration for an <code>executor</code> or <code>manager</code>.
*/
@VisibleForTesting
protected void configureContainerResources(final V1Container container, final Config configuration, final Resource resource, boolean isExecutor) {
if (container.getResources() == null) {
container.setResources(new V1ResourceRequirements());
}
final V1ResourceRequirements resourceRequirements = container.getResources();
// Collect Limits and Requests from CLI.
final Map<String, Quantity> limitsCLI = createResourcesRequirement(KubernetesContext.getResourceLimits(configuration, isExecutor));
final Map<String, Quantity> requestsCLI = createResourcesRequirement(KubernetesContext.getResourceRequests(configuration, isExecutor));
if (resourceRequirements.getLimits() == null) {
resourceRequirements.setLimits(new HashMap<>());
}
// Set Limits and Resources from CLI <if> available, <else> use Configs. Deduplicate on name
// with precedence [1] CLI, [2] Config.
final Map<String, Quantity> limits = resourceRequirements.getLimits();
final Quantity limitCPU = limitsCLI.getOrDefault(KubernetesConstants.CPU, Quantity.fromString(Double.toString(KubernetesUtils.roundDecimal(resource.getCpu(), 3))));
final Quantity limitMEMORY = limitsCLI.getOrDefault(KubernetesConstants.MEMORY, Quantity.fromString(KubernetesUtils.Megabytes(resource.getRam())));
limits.put(KubernetesConstants.MEMORY, limitMEMORY);
limits.put(KubernetesConstants.CPU, limitCPU);
// Set the Kubernetes container resource request.
// Order: [1] CLI, [2] EQUAL_TO_LIMIT, [3] NOT_SET
KubernetesContext.KubernetesResourceRequestMode requestMode = KubernetesContext.getKubernetesRequestMode(configuration);
if (!requestsCLI.isEmpty()) {
if (resourceRequirements.getRequests() == null) {
resourceRequirements.setRequests(new HashMap<>());
}
final Map<String, Quantity> requests = resourceRequirements.getRequests();
if (requestsCLI.containsKey(KubernetesConstants.MEMORY)) {
requests.put(KubernetesConstants.MEMORY, requestsCLI.get(KubernetesConstants.MEMORY));
}
if (requestsCLI.containsKey(KubernetesConstants.CPU)) {
requests.put(KubernetesConstants.CPU, requestsCLI.get(KubernetesConstants.CPU));
}
} else if (requestMode == KubernetesContext.KubernetesResourceRequestMode.EQUAL_TO_LIMIT) {
LOG.log(Level.CONFIG, "Setting K8s Request equal to Limit");
resourceRequirements.setRequests(limits);
} else {
LOG.log(Level.CONFIG, "Not setting K8s request because config was NOT_SET");
}
container.setResources(resourceRequirements);
}
use of io.kubernetes.client.custom.Quantity in project heron by twitter.
the class V1ControllerTest method testCreateResourcesRequirement.
@Test
public void testCreateResourcesRequirement() {
final String managerCpuLimit = "3000m";
final String managerMemLimit = "256Gi";
final Quantity memory = Quantity.fromString(managerMemLimit);
final Quantity cpu = Quantity.fromString(managerCpuLimit);
final List<TestTuple<Map<String, String>, Map<String, Quantity>>> testCases = new LinkedList<>();
// No input.
Map<String, String> inputEmpty = new HashMap<>();
testCases.add(new TestTuple<>("Empty input.", inputEmpty, new HashMap<>()));
// Only memory.
Map<String, String> inputMemory = new HashMap<String, String>() {
{
put(KubernetesConstants.MEMORY, managerMemLimit);
}
};
Map<String, Quantity> expectedMemory = new HashMap<String, Quantity>() {
{
put(KubernetesConstants.MEMORY, memory);
}
};
testCases.add(new TestTuple<>("Only memory input.", inputMemory, expectedMemory));
// Only CPU.
Map<String, String> inputCPU = new HashMap<String, String>() {
{
put(KubernetesConstants.CPU, managerCpuLimit);
}
};
Map<String, Quantity> expectedCPU = new HashMap<String, Quantity>() {
{
put(KubernetesConstants.CPU, cpu);
}
};
testCases.add(new TestTuple<>("Only CPU input.", inputCPU, expectedCPU));
// CPU and memory.
Map<String, String> inputMemoryCPU = new HashMap<String, String>() {
{
put(KubernetesConstants.MEMORY, managerMemLimit);
put(KubernetesConstants.CPU, managerCpuLimit);
}
};
Map<String, Quantity> expectedMemoryCPU = new HashMap<String, Quantity>() {
{
put(KubernetesConstants.MEMORY, memory);
put(KubernetesConstants.CPU, cpu);
}
};
testCases.add(new TestTuple<>("Memory and CPU input.", inputMemoryCPU, expectedMemoryCPU));
// Invalid.
Map<String, String> inputInvalid = new HashMap<String, String>() {
{
put("invalid input", "will not be ignored");
put(KubernetesConstants.CPU, managerCpuLimit);
}
};
Map<String, Quantity> expectedInvalid = new HashMap<String, Quantity>() {
{
put(KubernetesConstants.CPU, cpu);
}
};
testCases.add(new TestTuple<>("Invalid input.", inputInvalid, expectedInvalid));
// Test loop.
for (TestTuple<Map<String, String>, Map<String, Quantity>> testCase : testCases) {
Map<String, Quantity> actual = v1ControllerPodTemplate.createResourcesRequirement(testCase.input);
Assert.assertEquals(testCase.description, testCase.expected, actual);
}
}
use of io.kubernetes.client.custom.Quantity in project heron by twitter.
the class V1Controller method createPersistentVolumeClaims.
/**
* Generates <code>Persistent Volume Claims Templates</code> from a mapping of <code>Volumes</code>
* to <code>key-value</code> pairs of configuration options and values.
* @param mapOfOpts <code>Volume</code> to configuration <code>key-value</code> mappings.
* @return Fully populated list of only dynamically backed <code>Persistent Volume Claims</code>.
*/
@VisibleForTesting
protected List<V1PersistentVolumeClaim> createPersistentVolumeClaims(final Map<String, Map<KubernetesConstants.VolumeConfigKeys, String>> mapOfOpts) {
List<V1PersistentVolumeClaim> listOfPVCs = new LinkedList<>();
// Iterate over all the PVC Volumes.
for (Map.Entry<String, Map<KubernetesConstants.VolumeConfigKeys, String>> pvc : mapOfOpts.entrySet()) {
// Only create claims for `OnDemand` volumes.
final String claimName = pvc.getValue().get(KubernetesConstants.VolumeConfigKeys.claimName);
if (claimName != null && !KubernetesConstants.LABEL_ON_DEMAND.equalsIgnoreCase(claimName)) {
continue;
}
V1PersistentVolumeClaim claim = new V1PersistentVolumeClaimBuilder().withNewMetadata().withName(pvc.getKey()).withLabels(getPersistentVolumeClaimLabels(getTopologyName())).endMetadata().withNewSpec().withStorageClassName("").endSpec().build();
// Populate PVC options.
for (Map.Entry<KubernetesConstants.VolumeConfigKeys, String> option : pvc.getValue().entrySet()) {
String optionValue = option.getValue();
switch(option.getKey()) {
case storageClassName:
claim.getSpec().setStorageClassName(optionValue);
break;
case sizeLimit:
claim.getSpec().setResources(new V1ResourceRequirements().putRequestsItem("storage", new Quantity(optionValue)));
break;
case accessModes:
claim.getSpec().setAccessModes(Arrays.asList(optionValue.split(",")));
break;
case volumeMode:
claim.getSpec().setVolumeMode(optionValue);
break;
// Valid ignored options not used in a PVC.
default:
break;
}
}
listOfPVCs.add(claim);
}
return listOfPVCs;
}
use of io.kubernetes.client.custom.Quantity in project heron by twitter.
the class V1Controller method createVolumeAndMountsEmptyDirCLI.
/**
* Generates the <code>Volume</code>s and <code>Volume Mounts</code> for <code>emptyDir</code>s to be
* placed in the <code>Executor</code> and <code>Manager</code> from options on the CLI.
* @param mapOfOpts Mapping of <code>Volume</code> option <code>key-value</code> configuration pairs.
* @param volumes A list of <code>Volume</code> to append to.
* @param volumeMounts A list of <code>Volume Mounts</code> to append to.
*/
@VisibleForTesting
protected void createVolumeAndMountsEmptyDirCLI(final Map<String, Map<KubernetesConstants.VolumeConfigKeys, String>> mapOfOpts, final List<V1Volume> volumes, final List<V1VolumeMount> volumeMounts) {
for (Map.Entry<String, Map<KubernetesConstants.VolumeConfigKeys, String>> configs : mapOfOpts.entrySet()) {
final String volumeName = configs.getKey();
final V1Volume volume = new V1VolumeBuilder().withName(volumeName).withNewEmptyDir().endEmptyDir().build();
for (Map.Entry<KubernetesConstants.VolumeConfigKeys, String> config : configs.getValue().entrySet()) {
switch(config.getKey()) {
case medium:
volume.getEmptyDir().medium(config.getValue());
break;
case sizeLimit:
volume.getEmptyDir().sizeLimit(new Quantity(config.getValue()));
break;
default:
break;
}
}
volumes.add(volume);
volumeMounts.add(createVolumeMountsCLI(volumeName, configs.getValue()));
}
}
use of io.kubernetes.client.custom.Quantity in project heron by twitter.
the class V1ControllerTest method testConfigureContainerResources.
@Test
public void testConfigureContainerResources() {
final boolean isExecutor = true;
final Resource resourceDefault = new Resource(9, ByteAmount.fromMegabytes(19000), ByteAmount.fromMegabytes(99000));
final Resource resourceCustom = new Resource(4, ByteAmount.fromMegabytes(34000), ByteAmount.fromMegabytes(400000));
final Quantity defaultRAM = Quantity.fromString(KubernetesUtils.Megabytes(resourceDefault.getRam()));
final Quantity defaultCPU = Quantity.fromString(Double.toString(KubernetesUtils.roundDecimal(resourceDefault.getCpu(), 3)));
final Quantity customRAM = Quantity.fromString(KubernetesUtils.Megabytes(resourceCustom.getRam()));
final Quantity customCPU = Quantity.fromString(Double.toString(KubernetesUtils.roundDecimal(resourceCustom.getCpu(), 3)));
final Quantity customDisk = Quantity.fromString(KubernetesUtils.Megabytes(resourceCustom.getDisk()));
final Config configNoLimit = Config.newBuilder().put(KubernetesContext.KUBERNETES_RESOURCE_REQUEST_MODE, "NOT_SET").build();
final Config configWithLimit = Config.newBuilder().put(KubernetesContext.KUBERNETES_RESOURCE_REQUEST_MODE, "EQUAL_TO_LIMIT").build();
final V1ResourceRequirements expectDefaultRequirements = new V1ResourceRequirements().putLimitsItem(KubernetesConstants.MEMORY, defaultRAM).putLimitsItem(KubernetesConstants.CPU, defaultCPU);
final V1ResourceRequirements expectCustomRequirements = new V1ResourceRequirements().putLimitsItem(KubernetesConstants.MEMORY, defaultRAM).putLimitsItem(KubernetesConstants.CPU, defaultCPU).putLimitsItem("disk", customDisk);
final V1ResourceRequirements customRequirements = new V1ResourceRequirements().putLimitsItem(KubernetesConstants.MEMORY, customRAM).putLimitsItem(KubernetesConstants.CPU, customCPU).putLimitsItem("disk", customDisk);
// Default. Null resources.
V1Container containerNull = new V1ContainerBuilder().build();
v1ControllerWithPodTemplate.configureContainerResources(containerNull, configNoLimit, resourceDefault, isExecutor);
Assert.assertTrue("Default LIMITS should be set in container with null LIMITS", containerNull.getResources().getLimits().entrySet().containsAll(expectDefaultRequirements.getLimits().entrySet()));
// Empty resources.
V1Container containerEmpty = new V1ContainerBuilder().withNewResources().endResources().build();
v1ControllerWithPodTemplate.configureContainerResources(containerEmpty, configNoLimit, resourceDefault, isExecutor);
Assert.assertTrue("Default LIMITS should be set in container with empty LIMITS", containerNull.getResources().getLimits().entrySet().containsAll(expectDefaultRequirements.getLimits().entrySet()));
// Custom resources.
V1Container containerCustom = new V1ContainerBuilder().withResources(customRequirements).build();
v1ControllerWithPodTemplate.configureContainerResources(containerCustom, configNoLimit, resourceDefault, isExecutor);
Assert.assertTrue("Custom LIMITS should be set in container with custom LIMITS", containerCustom.getResources().getLimits().entrySet().containsAll(expectCustomRequirements.getLimits().entrySet()));
// Custom resources with request.
V1Container containerRequests = new V1ContainerBuilder().withResources(customRequirements).build();
v1ControllerWithPodTemplate.configureContainerResources(containerRequests, configWithLimit, resourceDefault, isExecutor);
Assert.assertTrue("Custom LIMITS should be set in container with custom LIMITS and REQUEST", containerRequests.getResources().getLimits().entrySet().containsAll(expectCustomRequirements.getLimits().entrySet()));
Assert.assertTrue("Custom REQUEST should be set in container with custom LIMITS and REQUEST", containerRequests.getResources().getRequests().entrySet().containsAll(expectCustomRequirements.getLimits().entrySet()));
}
Aggregations