com.avito.android.runner.devices.internal.kubernetes.KubernetesReservationClaimer.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of impl Show documentation
Show all versions of impl Show documentation
Collection of infrastructure libraries and gradle plugins of Avito Android project
package com.avito.android.runner.devices.internal.kubernetes
import com.avito.android.runner.devices.internal.EmulatorsLogsReporter
import com.avito.android.runner.devices.internal.RemoteDevice
import com.avito.android.runner.devices.model.ReservationData
import com.avito.k8s.KubernetesApi
import com.avito.k8s.model.KubePod
import com.avito.logger.LoggerFactory
import com.avito.logger.create
import com.avito.runner.service.worker.device.DeviceCoordinate
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.channels.ReceiveChannel
import kotlinx.coroutines.channels.consumeEach
import kotlinx.coroutines.channels.distinctBy
import kotlinx.coroutines.channels.filter
import kotlinx.coroutines.channels.map
import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlin.coroutines.coroutineContext
@ExperimentalCoroutinesApi
internal class KubernetesReservationClaimer(
private val reservationDeploymentFactory: ReservationDeploymentFactory,
private val kubernetesApi: KubernetesApi,
private val deploymentPodsListener: DeploymentPodsListener,
private val deviceProvider: RemoteDeviceProvider,
private val emulatorsLogsReporter: EmulatorsLogsReporter,
private val kubernetesReservationListener: KubernetesReservationListener,
private val lock: Mutex,
loggerFactory: LoggerFactory
) {
private val logger = loggerFactory.create()
suspend fun claim(
reservations: Collection,
serialsChannel: Channel,
podsChannel: Channel,
deploymentsChannel: Channel
) = with(CoroutineScope(coroutineContext)) {
reservations.forEach { reservation ->
launch(CoroutineName("create-deployment")) {
createDeployment(
reservation,
deploymentsChannel,
podsChannel,
serialsChannel
)
}
}
initializeDevices(podsChannel, serialsChannel)
}
private suspend fun createDeployment(
reservation: ReservationData,
deploymentsChannel: Channel,
podsChannel: Channel,
serialsChannel: Channel
) {
logger.info("Create deployment $reservation")
val deployment = reservationDeploymentFactory.createDeployment(
namespace = kubernetesApi.namespace,
reservation = reservation
)
val deploymentName = lock.withLock {
val deploymentName = deployment.metadata.name
deploymentsChannel.send(deploymentName)
kubernetesApi.createDeployment(deployment)
deploymentName
}
deploymentPodsListener.start(
deploymentName, podsChannel
).onFailure {
podsChannel.cancel()
serialsChannel.close()
}
}
private suspend fun initializeDevices(
podsChannel: ReceiveChannel,
serialsChannel: Channel
) {
with(CoroutineScope(coroutineContext + CoroutineName("waiting-pods"))) {
launch(CoroutineName("waiting-pods")) {
@Suppress("DEPRECATION")
podsChannel
.map {
if (serialsChannel.isClosedForSend) {
logger.info("cancel waiting-pods")
podsChannel.cancel()
}
it
}
.filter { it.phase is KubePod.PodPhase.Running }
.distinctBy { it.name }
.consumeEach { pod ->
kubernetesReservationListener.onPodAcquired()
launch(CoroutineName("boot-pod-${pod.name}")) {
deviceProvider.create(pod)
.onSuccess { device ->
device.sendTo(
pod.name,
serialsChannel
)
}
}
}
logger.info("initializeDevices finished")
}
}
}
private suspend fun RemoteDevice.sendTo(
podName: String,
serials: Channel,
) {
if (serials.isClosedForSend) {
logger.info("Pod $podName boot device but serials channel closed")
return
}
emulatorsLogsReporter.redirectLogcat(
emulatorName = serial,
device = this
)
serials.send(
DeviceCoordinate.Kubernetes(
serial = serial,
podName = podName
)
)
logger.info("Pod $podName sent outside for further usage")
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy