Skip to content

Commit c50c21f

Browse files
committed
Fix #35011: use uid of data directory for containers
1 parent fe3aeae commit c50c21f

9 files changed

Lines changed: 43 additions & 13 deletions

File tree

.github/workflows/workflows.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,5 +46,6 @@ jobs:
4646
- name: Run Tests
4747
run: |
4848
docker network create sp-shared-network
49+
docker plugin install "grafana/loki-docker-driver:3.2.1" --alias loki --grant-all-permissions
4950
export SPO_DOCKER_GID=$(getent group docker | cut -d: -f3)
5051
mvn -B test

src/main/kotlin/eu/openanalytics/shinyproxyoperator/impl/docker/CraneConfig.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import eu.openanalytics.shinyproxyoperator.sha1
3636
import io.github.oshai.kotlinlogging.KotlinLogging
3737
import kotlinx.coroutines.CoroutineScope
3838
import kotlinx.coroutines.Dispatchers
39+
import kotlinx.coroutines.IO
3940
import kotlinx.coroutines.delay
4041
import kotlinx.coroutines.launch
4142
import kotlinx.coroutines.withContext
@@ -56,7 +57,8 @@ class CraneConfig(private val dockerClient: DockerClient,
5657
private val inputDir: Path,
5758
private val redisConfig: RedisConfig,
5859
private val caddyConfig: CaddyConfig,
59-
private val persistentState: PersistentState) {
60+
private val persistentState: PersistentState,
61+
private val dataDirUid: Int) {
6062

6163
private val yamlMapper = ObjectMapper(YAMLFactory())
6264
private val fileManager = FileManager()
@@ -145,6 +147,7 @@ class CraneConfig(private val dockerClient: DockerClient,
145147
.hostConfig(hostConfig)
146148
.labels(dockerActions.labelsForCrane(shinyProxy.realmId, hash))
147149
.env("SPRING_CONFIG_IMPORT=/opt/crane/generated.yml")
150+
.user(dataDirUid.toString())
148151
.build()
149152

150153
logger.info { "${logPrefix(shinyProxyInstance)} [Crane] Creating new container" }

src/main/kotlin/eu/openanalytics/shinyproxyoperator/impl/docker/DockerOrchestrator.kt

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ import org.mandas.docker.client.messages.HostConfig
5353
import org.mandas.docker.client.messages.LogConfig
5454
import java.io.FileWriter
5555
import java.nio.file.Files
56+
import java.nio.file.LinkOption
5657
import java.nio.file.Path
5758
import java.time.OffsetDateTime
5859
import java.time.ZoneOffset
@@ -69,6 +70,7 @@ class DockerOrchestrator(channel: Channel<ShinyProxyEvent>,
6970
private val dockerGID: Int = config.readConfigValue(null, "SPO_DOCKER_GID") { it.toInt() }
7071
private val dockerSocket: String = config.readConfigValue("/var/run/docker.sock", "SPO_DOCKER_SOCKET") { it }
7172
private val disableICC: Boolean = config.readConfigValue(false, "SPO_DISABLE_ICC") { it.toBoolean() }
73+
private var dataDirUid: Int
7274
private val state = mutableMapOf<String, ShinyProxyStatus>()
7375

7476
private val logger = KotlinLogging.logger { }
@@ -98,12 +100,13 @@ class DockerOrchestrator(channel: Channel<ShinyProxyEvent>,
98100
.uri("unix://" + dockerSocket)
99101
.readTimeoutMillis(0) // no timeout, needed for startContainer and logs, #32606
100102
.build()
103+
dataDirUid = getDatadirUId()
101104
caddyConfig = CaddyConfig(dockerClient, dataDir, config)
102105
dockerActions = DockerActions(dockerClient)
103106
shinyProxyReadyChecker = ShinyProxyReadyChecker(channel, dockerActions, dockerClient, dataDir)
104-
redisConfig = RedisConfig(dockerClient, dockerActions, persistentState, dataDir, config)
105-
craneConfig = CraneConfig(dockerClient, dockerActions, dataDir, inputDir, redisConfig, caddyConfig, persistentState)
106-
monitoringConfig = MonitoringConfig(dockerClient, dockerActions, dataDir, caddyConfig, config, dockerSocket)
107+
redisConfig = RedisConfig(dockerClient, dockerActions, persistentState, dataDir, dataDirUid, config)
108+
craneConfig = CraneConfig(dockerClient, dockerActions, dataDir, inputDir, redisConfig, caddyConfig, persistentState, dataDirUid)
109+
monitoringConfig = MonitoringConfig(dockerClient, dockerActions, dataDir, dataDirUid, caddyConfig, config, dockerSocket)
107110
logFilesCleaner = LogFilesCleaner(dataDir.resolve("logs"), fileManager, dockerActions)
108111
fileManager.createDirectories(dataDir)
109112
eventWriter = FileWriter(dataDir.resolve("events.json").toFile())
@@ -278,6 +281,7 @@ class DockerOrchestrator(channel: Channel<ShinyProxyEvent>,
278281
.hostConfig(hostConfigBuilder.build())
279282
.labels(shinyProxy.labels + LabelFactory.labelsForShinyProxyInstance(shinyProxyInstance, version))
280283
.env("PROXY_VERSION=${version}", "PROXY_REALM_ID=${shinyProxy.realmId}", "SPRING_CONFIG_IMPORT=/opt/shinyproxy/generated.yml")
284+
.user(dataDirUid.toString())
281285
.build()
282286

283287
logger.info { "${logPrefix(shinyProxyInstance)} [Docker] Creating new container" }
@@ -515,4 +519,15 @@ class DockerOrchestrator(channel: Channel<ShinyProxyEvent>,
515519
return (cpuPeriod.toDouble() * converted).toLong()
516520
}
517521

522+
private fun getDatadirUId(): Int {
523+
try {
524+
val owner = Integer.parseInt(Files.getAttribute(dataDir, "unix:uid", LinkOption.NOFOLLOW_LINKS).toString())
525+
logger.info { "Owner of data dir is '$owner'" }
526+
return owner
527+
} catch (e: Exception) {
528+
logger.warn(e) { "Failed to determine owner of data dir - failling back to user 1000" }
529+
return 1000
530+
}
531+
}
532+
518533
}

src/main/kotlin/eu/openanalytics/shinyproxyoperator/impl/docker/RedisConfig.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ class RedisConfig(private val dockerClient: DockerClient,
3737
private val dockerActions: DockerActions,
3838
private val persistentState: PersistentState,
3939
mainDataDir: Path,
40+
private val dataDirUid: Int,
4041
config: Config) {
4142

4243
private val containerName = "sp-redis"
@@ -104,7 +105,7 @@ class RedisConfig(private val dockerClient: DockerClient,
104105
.hostConfig(hostConfig)
105106
.labels(mapOf("app" to "redis"))
106107
.cmd(listOf("redis-server", "/etc/redis.conf"))
107-
.user("1000")
108+
.user(dataDirUid.toString())
108109
.build()
109110

110111
logger.info { "[Redis] Creating new container" }

src/main/kotlin/eu/openanalytics/shinyproxyoperator/impl/docker/monitoring/GrafanaLokiConfig.kt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,11 @@ import org.mandas.docker.client.messages.HostConfig
3131
import org.mandas.docker.client.messages.PortBinding
3232
import java.nio.file.Path
3333

34-
class GrafanaLokiConfig(private val dockerClient: DockerClient, private val dockerActions: DockerActions, mainDataDir: Path, config: Config) {
34+
class GrafanaLokiConfig(private val dockerClient: DockerClient,
35+
private val dockerActions: DockerActions,
36+
mainDataDir: Path,
37+
private val dataDirUid: Int,
38+
config: Config) {
3539

3640
private val logger = KotlinLogging.logger {}
3741
private val lokiImage: String = config.readConfigValue("docker.io/grafana/loki:3.2.2", "SPO_GRAFANA_GRAFANA_IMAGE") { it }
@@ -75,7 +79,7 @@ class GrafanaLokiConfig(private val dockerClient: DockerClient, private val dock
7579
.image(lokiImage)
7680
.hostConfig(hostConfig)
7781
.exposedPorts("3100")
78-
.user("1000")
82+
.user(dataDirUid.toString())
7983
.labels(mapOf("app" to "grafana-loki"))
8084
.build()
8185

src/main/kotlin/eu/openanalytics/shinyproxyoperator/impl/docker/monitoring/MonitoringConfig.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,12 @@ import io.github.oshai.kotlinlogging.KotlinLogging
2828
import org.mandas.docker.client.DockerClient
2929
import java.nio.file.Path
3030

31-
class MonitoringConfig(dockerClient: DockerClient, dockerActions: DockerActions, mainDataDir: Path, caddyConfig: CaddyConfig, config: Config, dockerSocket: String) {
31+
class MonitoringConfig(dockerClient: DockerClient, dockerActions: DockerActions, mainDataDir: Path, dataDirUid: Int, caddyConfig: CaddyConfig, config: Config, dockerSocket: String) {
3232

3333
private val logger = KotlinLogging.logger { }
3434
private val enableMonitoring: Boolean
35-
internal val grafanaLokiConfig = GrafanaLokiConfig(dockerClient, dockerActions, mainDataDir, config)
36-
private val prometheusConfig = PrometheusConfig(dockerClient, dockerActions, mainDataDir, config, dockerSocket)
35+
internal val grafanaLokiConfig = GrafanaLokiConfig(dockerClient, dockerActions, mainDataDir, dataDirUid, config)
36+
private val prometheusConfig = PrometheusConfig(dockerClient, dockerActions, mainDataDir, dataDirUid, config, dockerSocket)
3737
private val cAdvisorConfig = CAdvisorConfig(dockerClient, dockerActions, config, dockerSocket)
3838
internal val grafanaConfig = GrafanaConfig(dockerClient, dockerActions, mainDataDir, caddyConfig, config)
3939

src/main/kotlin/eu/openanalytics/shinyproxyoperator/impl/docker/monitoring/PrometheusConfig.kt

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,12 @@ import org.mandas.docker.client.messages.ContainerConfig
3030
import org.mandas.docker.client.messages.HostConfig
3131
import java.nio.file.Path
3232

33-
class PrometheusConfig(private val dockerClient: DockerClient, private val dockerActions: DockerActions, mainDataDir: Path, config: Config, private val dockerSocket: String) {
33+
class PrometheusConfig(private val dockerClient: DockerClient,
34+
private val dockerActions: DockerActions,
35+
mainDataDir: Path,
36+
private val dataDirUid: Int,
37+
config: Config,
38+
private val dockerSocket: String) {
3439

3540
private val logger = KotlinLogging.logger {}
3641
private val dockerGID = config.readConfigValue(null, "SPO_DOCKER_GID") { it.toInt() }
@@ -80,7 +85,7 @@ class PrometheusConfig(private val dockerClient: DockerClient, private val docke
8085
.image(prometheusImage)
8186
.hostConfig(hostConfig)
8287
.labels(mapOf("app" to "prometheus"))
83-
.user("1000")
88+
.user(dataDirUid.toString())
8489
.build()
8590

8691
logger.info { "[Prometheus] Creating new container" }

src/test/kotlin/eu/openanalytics/shinyproxyoperator/impl/docker/MainIntegrationTest.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,14 @@ import kotlinx.coroutines.delay
2828
import kotlinx.coroutines.launch
2929
import kotlinx.coroutines.withTimeout
3030
import org.junit.jupiter.api.Assertions.assertNull
31+
import org.junit.jupiter.api.Disabled
3132
import org.junit.jupiter.api.Test
3233
import org.junit.jupiter.params.ParameterizedTest
3334
import org.junit.jupiter.params.provider.ValueSource
3435
import kotlin.io.path.deleteIfExists
3536
import kotlin.io.path.readText
3637
import kotlin.io.path.writeText
38+
import kotlin.test.Ignore
3739
import kotlin.test.assertEquals
3840
import kotlin.test.assertNotNull
3941

src/test/kotlin/eu/openanalytics/shinyproxyoperator/impl/docker/helpers/DockerAssertions.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ class DockerAssertions(private val base: IntegrationTestBase,
5353
assertEquals("always", redisContainer.hostConfig().restartPolicy().name())
5454
assertEquals(listOf("redis-server", "/etc/redis.conf"), redisContainer.config().cmd())
5555
assertEquals("redis", redisContainer.config().labels()["app"])
56-
assertEquals("1000", redisContainer.config().user())
5756

5857
// remove generated password from file
5958
val redisConfig = dataDir.resolve("sp-redis").resolve("redis.conf").readText().dropLast(33)

0 commit comments

Comments
 (0)