Skip to content
14 changes: 14 additions & 0 deletions orchestrator/src/main/resources/application.conf
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ config {
mountSecrets = ${?CONFIG_MOUNT_SECRETS}
mountPvcs = ${?CONFIG_MOUNT_PVCS}
mountEmptyDirs = ${?CONFIG_MOUNT_EMPTY_DIRS}
volumeMounts = ${?CONFIG_VOLUME_MOUNTS}
additionalContainers = ${?CONFIG_ADDITIONAL_CONTAINERS}
labels = ${?CONFIG_LABELS}
annotationVariables = ${?CONFIG_ANNOTATIONS}
serviceAccount = ${?CONFIG_SERVICE_ACCOUNT}
Expand Down Expand Up @@ -99,6 +101,8 @@ analyzer {
mountSecrets = ${?ANALYZER_MOUNT_SECRETS}
mountPvcs = ${?ANALYZER_MOUNT_PVCS}
mountEmptyDirs = ${?ANALYZER_MOUNT_EMPTY_DIRS}
volumeMounts = ${?ANALYZER_VOLUME_MOUNTS}
additionalContainers = ${?ANALYZER_ADDITIONAL_CONTAINERS}
labels = ${?ANALYZER_LABELS}
annotationVariables = ${?ANALYZER_ANNOTATIONS}
serviceAccount = ${?ANALYZER_SERVICE_ACCOUNT}
Expand Down Expand Up @@ -138,6 +142,8 @@ advisor {
mountSecrets = ${?ADVISOR_MOUNT_SECRETS}
mountPvcs = ${?ADVISOR_MOUNT_PVCS}
mountEmptyDirs = ${?ADVISOR_MOUNT_EMPTY_DIRS}
volumeMounts = ${?ADVISOR_VOLUME_MOUNTS}
additionalContainers = ${?ADVISOR_ADDITIONAL_CONTAINERS}
labels = ${?ADVISOR_LABELS}
annotationVariables = ${?ADVISOR_ANNOTATIONS}
serviceAccount = ${?ADVISOR_SERVICE_ACCOUNT}
Expand Down Expand Up @@ -177,6 +183,8 @@ scanner {
mountSecrets = ${?SCANNER_MOUNT_SECRETS}
mountPvcs = ${?SCANNER_MOUNT_PVCS}
mountEmptyDirs = ${?SCANNER_MOUNT_EMPTY_DIRS}
volumeMounts = ${?SCANNER_VOLUME_MOUNTS}
additionalContainers = ${?SCANNER_ADDITIONAL_CONTAINERS}
labels = ${?SCANNER_LABELS}
annotationVariables = ${?SCANNER_ANNOTATIONS}
serviceAccount = ${?SCANNER_SERVICE_ACCOUNT}
Expand Down Expand Up @@ -216,6 +224,8 @@ evaluator {
mountSecrets = ${?EVALUATOR_MOUNT_SECRETS}
mountPvcs = ${?EVALUATOR_MOUNT_PVCS}
mountEmptyDirs = ${?EVALUATOR_MOUNT_EMPTY_DIRS}
volumeMounts = ${?EVALUATOR_VOLUME_MOUNTS}
additionalContainers = ${?EVALUATOR_ADDITIONAL_CONTAINERS}
labels = ${?EVALUATOR_LABELS}
annotationVariables = ${?EVALUATOR_ANNOTATIONS}
serviceAccount = ${?EVALUATOR_SERVICE_ACCOUNT}
Expand Down Expand Up @@ -255,6 +265,8 @@ reporter {
mountSecrets = ${?REPORTER_MOUNT_SECRETS}
mountPvcs = ${?REPORTER_MOUNT_PVCS}
mountEmptyDirs = ${?REPORTER_MOUNT_EMPTY_DIRS}
volumeMounts = ${?REPORTER_VOLUME_MOUNTS}
additionalContainers = ${?REPORTER_ADDITIONAL_CONTAINERS}
labels = ${?REPORTER_LABELS}
annotationVariables = ${?REPORTER_ANNOTATIONS}
serviceAccount = ${?REPORTER_SERVICE_ACCOUNT}
Expand Down Expand Up @@ -294,6 +306,8 @@ notifier {
mountSecrets = ${?NOTIFIER_MOUNT_SECRETS}
mountPvcs = ${?NOTIFIER_MOUNT_PVCS}
mountEmptyDirs = ${?NOTIFIER_MOUNT_EMPTY_DIRS}
volumeMounts = ${?NOTIFIER_VOLUME_MOUNTS}
additionalContainers = ${?NOTIFIER_ADDITIONAL_CONTAINERS}
labels = ${?NOTIFIER_LABELS}
annotationVariables = ${?NOTIFIER_ANNOTATIONS}
serviceAccount = ${?NOTIFIER_SERVICE_ACCOUNT}
Expand Down
3 changes: 2 additions & 1 deletion transport/kubernetes/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,12 @@ group = "org.eclipse.apoapsis.ortserver.transport"
dependencies {
api(projects.transport.transportSpi)

api(libs.kubernetesClientApiFluent)

implementation(projects.utils.config)
implementation(projects.utils.logging)

implementation(libs.kubernetesClient)
implementation(libs.kubernetesClientApiFluent)

testImplementation(projects.model)

Expand Down
98 changes: 98 additions & 0 deletions transport/kubernetes/src/main/kotlin/Container.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*
* Copyright (C) 2026 The ORT Server Authors (See <https://github.com/eclipse-apoapsis/ort-server/blob/main/NOTICE>)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
* License-Filename: LICENSE
*/

package org.eclipse.apoapsis.ortserver.transport.kubernetes

import io.kubernetes.client.custom.Quantity
import io.kubernetes.client.openapi.models.V1ResourceRequirements

import org.eclipse.apoapsis.ortserver.utils.config.substituteVariables

/** The name of the CPU resource. */
private const val CPU_RESOURCE = "cpu"

/** The name of the memory resource. */
private const val MEMORY_RESOURCE = "memory"

/**
* A data class to hold the properties of a container in the pod to be generated by the Kubernetes sender.
*/
data class Container(
/** A name for this container. This is used in the Kubernetes manifest. */
val name: String,

/** The name of the container image for the container (including the tag). */
val imageName: String,

/** The policy when pulling images. */
val imagePullPolicy: String,

/** The commands to be executed when running the container. */
val commands: List<String> = emptyList(),

/** A list with arguments for the container command. */
val args: List<String> = emptyList(),

/** An optional limit for the CPU resource. This may contain variables. */
val cpuLimit: String?,

/** An optional request for the CPU resource. This may contain variables. */
val cpuRequest: String?,

/** An optional limit for the memory resource. This may contain variables. */
val memoryLimit: String?,

/** An optional request for the memory resource. This may contain variables. */
val memoryRequest: String?,

/**
* A list with the names of volume mounts to add to this container. The strings in the list reference the names of
* declared volume mounts. In addition, volume mounts without a name are added to all containers.
*/
val volumeMounts: List<String> = emptyList(),

/**
* A flag whether this container is an init container.
* See https://kubernetes.io/docs/concepts/workloads/pods/init-containers/
*/
val isInitContainer: Boolean = false
) {
/**
* Return an optional [V1ResourceRequirements] object based on the properties related to resource requests and
* limits contained in this object. These properties may contain variables; therefore, apply substitution using
* the provided [variables] map. If no resource requests or limits are specified, return *null*.
*/
fun createResources(variables: Map<String, String>): V1ResourceRequirements? {
val requirements = V1ResourceRequirements()

substituteAndConvert(cpuLimit, variables)?.also { requirements.putLimitsItem(CPU_RESOURCE, it) }
substituteAndConvert(memoryLimit, variables)?.also { requirements.putLimitsItem(MEMORY_RESOURCE, it) }
substituteAndConvert(cpuRequest, variables)?.also { requirements.putRequestsItem(CPU_RESOURCE, it) }
substituteAndConvert(memoryRequest, variables)?.also { requirements.putRequestsItem(MEMORY_RESOURCE, it) }

return requirements.takeUnless { it.limits.isNullOrEmpty() && it.requests.isNullOrEmpty() }
}
}

/**
* Apply variable substitution to the given [value] using the provided [variables] and convert it to a [Quantity]
* object. Return *null* if the value is undefined.
*/
private fun substituteAndConvert(value: String?, variables: Map<String, String>): Quantity? =
value?.let { Quantity(it.substituteVariables(variables)) }
Loading
Loading