Skip to content

Commit d34cb75

Browse files
committed
feat: add configuration options for Kerberos material and container log append mode
- Introduced Kerberos configuration options: `materialDirectory`, `localKrb5ConfPath`, and `localClientKeytabPath` for better control over generated Kerberos files. - Added `append` flag for container log options to toggle between appending or overwriting logs. Updated default behavior to append for backward compatibility. - Updated documentation examples and test configurations to reflect new features. - Minor updates to Gradle Plugin, JUnit5, and Core modules to integrate changes.
1 parent 9415e38 commit d34cb75

13 files changed

Lines changed: 101 additions & 8 deletions

File tree

core/src/main/kotlin/org/openprojectx/bigdata/test/core/BigDataTestKitOptions.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ data class KerberosOptions(
2323
val domain: String = "example.com",
2424
val clientPrincipal: String = "app_user@EXAMPLE.COM",
2525
val clientPassword: String = "app-user-secret",
26+
val materialDirectory: String? = null,
27+
val localKrb5ConfPath: String? = null,
28+
val localClientKeytabPath: String? = null,
2629
val users: List<KerberosUserOptions> = emptyList(),
2730
val startupTimeoutSeconds: Int = 120,
2831
val materialTimeoutSeconds: Int = 30,
@@ -163,6 +166,7 @@ enum class ContainerLogMode {
163166
data class ContainerLogOptions(
164167
val mode: ContainerLogMode = ContainerLogMode.NONE,
165168
val directory: String = "build/bigdata-test-container-logs",
169+
val append: Boolean = true,
166170
)
167171

168172
enum class BigDataHealthCheckMode {

core/src/main/kotlin/org/openprojectx/bigdata/test/core/container/BigDataContainerFactory.kt

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,14 @@ internal class BigDataContainerFactory(
4141
private val network = Network.newNetwork()
4242
private val supportContainers = mutableListOf<Startable>()
4343
private val logConsumers = mutableListOf<Closeable>()
44-
private val kerberosDir: Path? = if (kerberosRequired()) Files.createTempDirectory("bigdata-test-kerberos-") else null
44+
private val kerberosDir: Path? =
45+
if (kerberosRequired()) {
46+
options.kerberos.materialDirectory
47+
?.let { Files.createDirectories(Path.of(it)) }
48+
?: Files.createTempDirectory("bigdata-test-kerberos-")
49+
} else {
50+
null
51+
}
4552
private val tlsMaterial: TlsMaterial by lazy { TlsMaterial(options.tls.copy(enabled = true)) }
4653

4754
fun healthCheck(service: BigDataService, container: GenericContainer<*>, endpoint: BigDataEndpoint) {
@@ -1045,7 +1052,11 @@ internal class BigDataContainerFactory(
10451052
Files.newOutputStream(
10461053
logDir.resolve("${sanitizeLogName(name)}.log"),
10471054
StandardOpenOption.CREATE,
1048-
StandardOpenOption.APPEND,
1055+
if (options.containerLogs.append) {
1056+
StandardOpenOption.APPEND
1057+
} else {
1058+
StandardOpenOption.TRUNCATE_EXISTING
1059+
},
10491060
),
10501061
StandardCharsets.UTF_8,
10511062
)
@@ -1356,9 +1367,14 @@ internal class BigDataContainerFactory(
13561367

13571368
private fun localKerberosPath(containerPath: String): String =
13581369
when {
1359-
containerPath == "/kerby/client/krb5.conf" -> Path.of(kerberosDirectory())
1360-
.resolve("krb5-local.conf")
1361-
.toString()
1370+
containerPath == "/kerby/client/krb5.conf" ->
1371+
options.kerberos.localKrb5ConfPath ?: Path.of(kerberosDirectory())
1372+
.resolve("krb5-local.conf")
1373+
.toString()
1374+
containerPath == "/kerby/keytabs/client.keytab" ->
1375+
options.kerberos.localClientKeytabPath ?: Path.of(kerberosDirectory())
1376+
.resolve(containerPath.removePrefix("/kerby/"))
1377+
.toString()
13621378
containerPath.startsWith("/kerby/") -> Path.of(kerberosDirectory())
13631379
.resolve(containerPath.removePrefix("/kerby/"))
13641380
.toString()

doc/user-guide.adoc

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -887,7 +887,13 @@ Write one file per service:
887887
----
888888
val kit = BigDataTestKit.builder()
889889
.withHiveMetastore()
890-
.withContainerLogsToDirectory("build/container-logs")
890+
.withContainerLogs(
891+
ContainerLogOptions(
892+
mode = ContainerLogMode.FILE,
893+
directory = "build/container-logs",
894+
append = false,
895+
),
896+
)
891897
.build()
892898
----
893899

@@ -911,6 +917,7 @@ val kit = BigDataTestKit.builder()
911917
schemaRegistry = true,
912918
containerLogMode = ContainerLogMode.FILE,
913919
containerLogDirectory = "build/container-logs",
920+
containerLogAppend = false,
914921
)
915922
class MyTroubleshootingTest
916923
----
@@ -933,6 +940,18 @@ localStackS3 = "TRACE"
933940
* `hive-metastore.log`
934941
* `hive-metastore-postgres.log`
935942

943+
File logs append by default for backward compatibility. Set `append = false` in TOML, `containerLogAppend = false` on `@BigDataTest`, or `ContainerLogOptions(append = false)` programmatically to overwrite the files at the start of each kit run.
944+
945+
TOML example:
946+
947+
[source,toml]
948+
----
949+
[containerLogs]
950+
mode = "FILE"
951+
directory = "build/container-logs"
952+
append = false
953+
----
954+
936955
For HDFS troubleshooting, use `DEBUG` or `TRACE`. The framework maps that to Hadoop's container-side log settings and tails the NameNode/DataNode log files so startup failures show the Hadoop process output, not only the Testcontainers wait-strategy error.
937956

938957
[source,kotlin]
@@ -994,14 +1013,17 @@ Kerberos bootstrap timing is configurable from TOML. The defaults are intentiona
9941013
[kerberos]
9951014
clientPrincipal = "app_user@EXAMPLE.COM"
9961015
clientPassword = "app-user-secret"
1016+
materialDirectory = "build/bigdata-test/kerberos"
1017+
localKrb5ConfPath = "build/bigdata-test/kerberos/krb5.conf"
1018+
localClientKeytabPath = "build/bigdata-test/kerberos/app_user.keytab"
9971019
startupTimeoutSeconds = 180
9981020
materialTimeoutSeconds = 120
9991021
adminAttempts = 120
10001022
adminRetryDelaySeconds = 1
10011023
debug = true
10021024
----
10031025

1004-
`clientPrincipal` and `clientPassword` configure the generated app/client user and keytab. `startupTimeoutSeconds` controls how long Testcontainers waits for the KDC image to print its ready log. `materialTimeoutSeconds` controls the post-start wait for generated keytabs and client config to be readable. `adminAttempts` and `adminRetryDelaySeconds` are passed to the Kerby image as `KERBY_KADMIN_ATTEMPTS` and `KERBY_KADMIN_RETRY_DELAY_SECONDS`.
1026+
`clientPrincipal` and `clientPassword` configure the generated app/client user and keytab. `materialDirectory` makes generated Kerberos material land in a stable local directory instead of a temporary directory. `localKrb5ConfPath` and `localClientKeytabPath` optionally pin the exact local files exposed through `bigdata.test.kerberos.krb5-conf` and `bigdata.test.kerberos.client-keytab`. `startupTimeoutSeconds` controls how long Testcontainers waits for the KDC image to print its ready log. `materialTimeoutSeconds` controls the post-start wait for generated keytabs and client config to be readable. `adminAttempts` and `adminRetryDelaySeconds` are passed to the Kerby image as `KERBY_KADMIN_ATTEMPTS` and `KERBY_KADMIN_RETRY_DELAY_SECONDS`.
10051027

10061028
Set `debug = true` when troubleshooting Kerberos startup in CI. It passes `KERBY_DEBUG=true` to the Kerby image, which enables JDK Kerberos debug output, Kerby DEBUG logs on container stdout, and dumps the generated `kdc.conf`, server `krb5.conf`, client `krb5.conf`, backend config, and admin server config into the container log.
10071029

@@ -1013,6 +1035,11 @@ BigDataTestKit.builder()
10131035
.withKerberos(
10141036
KerberosOptions(
10151037
enabled = true,
1038+
clientPrincipal = "app_user@EXAMPLE.COM",
1039+
clientPassword = "app-user-secret",
1040+
materialDirectory = "build/bigdata-test/kerberos",
1041+
localKrb5ConfPath = "build/bigdata-test/kerberos/krb5.conf",
1042+
localClientKeytabPath = "build/bigdata-test/kerberos/app_user.keytab",
10161043
startupTimeoutSeconds = 180,
10171044
materialTimeoutSeconds = 120,
10181045
adminAttempts = 120,
@@ -1538,6 +1565,9 @@ bigDataTest {
15381565
kerberos {
15391566
clientPrincipal.set(providers.gradleProperty("bigdata.test.kerberos.clientPrincipal"))
15401567
clientPassword.set(providers.gradleProperty("bigdata.test.kerberos.clientPassword"))
1568+
materialDirectory.set(layout.buildDirectory.dir("bigdata-test/kerberos").map { it.asFile.absolutePath })
1569+
localKrb5ConfPath.set(layout.buildDirectory.file("bigdata-test/kerberos/krb5.conf").map { it.asFile.absolutePath })
1570+
localClientKeytabPath.set(layout.buildDirectory.file("bigdata-test/kerberos/app_user.keytab").map { it.asFile.absolutePath })
15411571
}
15421572
}
15431573
----

example/spark/src/test/kotlin/org/openprojectx/bigdata/test/example/spark/SparkBigDataTestExample.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import org.openprojectx.bigdata.test.junit5.BigDataTest
99
@BigDataTest(
1010
config = [
1111
"classpath:spark-bigdata-test-common.toml",
12-
"classpath:spark-bigdata-test-cloudera-hms-kerberos.toml",
12+
"classpath:spark-bigdata-test-apache-hms-kerberos.toml",
1313
],
1414
)
1515
class SparkBigDataTestExample : SparkBigDataScenario() {

example/spark/src/test/resources/spark-bigdata-test-apache-hms-kerberos.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ materialTimeoutSeconds = 120
1111
adminAttempts = 120
1212
adminRetryDelaySeconds = 1
1313
debug = true
14+
materialDirectory = "build/bigdata-test/kerberos"
15+
localKrb5ConfPath = "build/bigdata-test/kerberos/krb5.conf"
16+
localClientKeytabPath = "build/bigdata-test/kerberos/app_user.keytab"
1417

1518
[ports]
1619
kafka = 19092

example/spring-gradle-plugin/src/main/resources/spring-bigdata-test.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ localStackS3 = true
66
[kerberos]
77
realm = "EXAMPLE.COM"
88
domain = "example.com"
9+
materialDirectory = "build/bigdata-test/kerberos"
10+
localKrb5ConfPath = "build/bigdata-test/kerberos/krb5.conf"
11+
localClientKeytabPath = "build/bigdata-test/kerberos/app_user.keytab"
912
debug = true
1013

1114
[hdfs]

gradle-plugin/src/main/kotlin/org/openprojectx/bigdata/test/gradle/BigDataTestGradleConfig.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ internal data class BigDataTestGradleConfig(
5151
val domain: String? = null,
5252
val clientPrincipal: String? = null,
5353
val clientPassword: String? = null,
54+
val materialDirectory: String? = null,
55+
val localKrb5ConfPath: String? = null,
56+
val localClientKeytabPath: String? = null,
5457
val startupTimeoutSeconds: Int? = null,
5558
val materialTimeoutSeconds: Int? = null,
5659
val adminAttempts: Int? = null,
@@ -104,6 +107,7 @@ internal data class BigDataTestGradleConfig(
104107
data class ContainerLogs(
105108
val mode: ContainerLogMode? = null,
106109
val directory: String? = null,
110+
val append: Boolean? = null,
107111
)
108112

109113
fun merge(override: BigDataTestGradleConfig): BigDataTestGradleConfig =
@@ -140,6 +144,9 @@ internal data class BigDataTestGradleConfig(
140144
domain = override.kerberos.domain ?: kerberos.domain,
141145
clientPrincipal = override.kerberos.clientPrincipal ?: kerberos.clientPrincipal,
142146
clientPassword = override.kerberos.clientPassword ?: kerberos.clientPassword,
147+
materialDirectory = override.kerberos.materialDirectory ?: kerberos.materialDirectory,
148+
localKrb5ConfPath = override.kerberos.localKrb5ConfPath ?: kerberos.localKrb5ConfPath,
149+
localClientKeytabPath = override.kerberos.localClientKeytabPath ?: kerberos.localClientKeytabPath,
143150
startupTimeoutSeconds = override.kerberos.startupTimeoutSeconds ?: kerberos.startupTimeoutSeconds,
144151
materialTimeoutSeconds = override.kerberos.materialTimeoutSeconds ?: kerberos.materialTimeoutSeconds,
145152
adminAttempts = override.kerberos.adminAttempts ?: kerberos.adminAttempts,
@@ -182,6 +189,7 @@ internal data class BigDataTestGradleConfig(
182189
containerLogs = ContainerLogs(
183190
mode = override.containerLogs.mode ?: containerLogs.mode,
184191
directory = override.containerLogs.directory ?: containerLogs.directory,
192+
append = override.containerLogs.append ?: containerLogs.append,
185193
),
186194
containerLogLevels = containerLogLevels + override.containerLogLevels,
187195
)
@@ -241,6 +249,9 @@ internal class BigDataTestGradleConfigLoader(
241249
domain = kerberos.string("domain"),
242250
clientPrincipal = kerberos.string("clientPrincipal"),
243251
clientPassword = kerberos.string("clientPassword"),
252+
materialDirectory = kerberos.string("materialDirectory"),
253+
localKrb5ConfPath = kerberos.string("localKrb5ConfPath"),
254+
localClientKeytabPath = kerberos.string("localClientKeytabPath"),
244255
startupTimeoutSeconds = kerberos.int("startupTimeoutSeconds"),
245256
materialTimeoutSeconds = kerberos.int("materialTimeoutSeconds"),
246257
adminAttempts = kerberos.int("adminAttempts"),
@@ -285,6 +296,7 @@ internal class BigDataTestGradleConfigLoader(
285296
containerLogs = BigDataTestGradleConfig.ContainerLogs(
286297
mode = containerLogs.string("mode")?.let { ContainerLogMode.valueOf(it.uppercase()) },
287298
directory = containerLogs.string("directory"),
299+
append = containerLogs.boolean("append"),
288300
),
289301
containerLogLevels = containerLogLevels.mapValues { (key, value) ->
290302
value.asString("containerLogLevels.$key")

gradle-plugin/src/main/kotlin/org/openprojectx/bigdata/test/gradle/BigDataTestGradleExtension.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,9 @@ abstract class BigDataTestGradleKerberos @Inject constructor(objects: ObjectFact
132132
val domain: Property<String> = objects.property(String::class.java).convention("example.com")
133133
val clientPrincipal: Property<String> = objects.property(String::class.java).convention("app_user@EXAMPLE.COM")
134134
val clientPassword: Property<String> = objects.property(String::class.java).convention("app-user-secret")
135+
val materialDirectory: Property<String> = objects.property(String::class.java).convention("")
136+
val localKrb5ConfPath: Property<String> = objects.property(String::class.java).convention("")
137+
val localClientKeytabPath: Property<String> = objects.property(String::class.java).convention("")
135138
val startupTimeoutSeconds: Property<Int> = objects.property(Int::class.java).convention(120)
136139
val materialTimeoutSeconds: Property<Int> = objects.property(Int::class.java).convention(30)
137140
val adminAttempts: Property<Int> = objects.property(Int::class.java).convention(30)
@@ -187,4 +190,5 @@ abstract class BigDataTestGradleObjectStore @Inject constructor(objects: ObjectF
187190
abstract class BigDataTestGradleContainerLogs @Inject constructor(objects: ObjectFactory) {
188191
val mode: Property<ContainerLogMode> = objects.property(ContainerLogMode::class.java).convention(ContainerLogMode.NONE)
189192
val directory: Property<String> = objects.property(String::class.java).convention("build/bigdata-test-container-logs")
193+
val append: Property<Boolean> = objects.property(Boolean::class.java).convention(true)
190194
}

gradle-plugin/src/main/kotlin/org/openprojectx/bigdata/test/gradle/BigDataTestGradlePlugin.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ class BigDataTestGradlePlugin : Plugin<Project> {
7171
spec.parameters.kerberosDomain.set(extension.kerberos.domain)
7272
spec.parameters.kerberosClientPrincipal.set(extension.kerberos.clientPrincipal)
7373
spec.parameters.kerberosClientPassword.set(extension.kerberos.clientPassword)
74+
spec.parameters.kerberosMaterialDirectory.set(extension.kerberos.materialDirectory)
75+
spec.parameters.kerberosLocalKrb5ConfPath.set(extension.kerberos.localKrb5ConfPath)
76+
spec.parameters.kerberosLocalClientKeytabPath.set(extension.kerberos.localClientKeytabPath)
7477
spec.parameters.kerberosStartupTimeoutSeconds.set(extension.kerberos.startupTimeoutSeconds)
7578
spec.parameters.kerberosMaterialTimeoutSeconds.set(extension.kerberos.materialTimeoutSeconds)
7679
spec.parameters.kerberosAdminAttempts.set(extension.kerberos.adminAttempts)
@@ -111,6 +114,7 @@ class BigDataTestGradlePlugin : Plugin<Project> {
111114

112115
spec.parameters.containerLogMode.set(extension.containerLogs.mode)
113116
spec.parameters.containerLogDirectory.set(extension.containerLogs.directory)
117+
spec.parameters.containerLogAppend.set(extension.containerLogs.append)
114118
}
115119

116120
val startTask = project.tasks.register("bigDataTestStart", BigDataTestStartTask::class.java) { task ->
@@ -283,6 +287,9 @@ class BigDataTestGradlePlugin : Plugin<Project> {
283287
extension.kerberos.domain.tomlConvention(config.kerberos.domain)
284288
extension.kerberos.clientPrincipal.tomlConvention(config.kerberos.clientPrincipal)
285289
extension.kerberos.clientPassword.tomlConvention(config.kerberos.clientPassword)
290+
extension.kerberos.materialDirectory.tomlConvention(config.kerberos.materialDirectory)
291+
extension.kerberos.localKrb5ConfPath.tomlConvention(config.kerberos.localKrb5ConfPath)
292+
extension.kerberos.localClientKeytabPath.tomlConvention(config.kerberos.localClientKeytabPath)
286293
extension.kerberos.startupTimeoutSeconds.tomlConvention(config.kerberos.startupTimeoutSeconds)
287294
extension.kerberos.materialTimeoutSeconds.tomlConvention(config.kerberos.materialTimeoutSeconds)
288295
extension.kerberos.adminAttempts.tomlConvention(config.kerberos.adminAttempts)
@@ -317,6 +324,7 @@ class BigDataTestGradlePlugin : Plugin<Project> {
317324

318325
extension.containerLogs.mode.tomlConvention(config.containerLogs.mode)
319326
extension.containerLogs.directory.tomlConvention(config.containerLogs.directory)
327+
extension.containerLogs.append.tomlConvention(config.containerLogs.append)
320328
extension.containerLogLevels.tomlConvention(config.containerLogLevels.takeIf { it.isNotEmpty() })
321329
}
322330

gradle-plugin/src/main/kotlin/org/openprojectx/bigdata/test/gradle/BigDataTestGradleService.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ abstract class BigDataTestGradleService : BuildService<BigDataTestGradleService.
6060
val kerberosDomain: Property<String>
6161
val kerberosClientPrincipal: Property<String>
6262
val kerberosClientPassword: Property<String>
63+
val kerberosMaterialDirectory: Property<String>
64+
val kerberosLocalKrb5ConfPath: Property<String>
65+
val kerberosLocalClientKeytabPath: Property<String>
6366
val kerberosStartupTimeoutSeconds: Property<Int>
6467
val kerberosMaterialTimeoutSeconds: Property<Int>
6568
val kerberosAdminAttempts: Property<Int>
@@ -100,6 +103,7 @@ abstract class BigDataTestGradleService : BuildService<BigDataTestGradleService.
100103

101104
val containerLogMode: Property<ContainerLogMode>
102105
val containerLogDirectory: Property<String>
106+
val containerLogAppend: Property<Boolean>
103107
}
104108

105109
private var kit: BigDataTestKit? = null
@@ -170,6 +174,7 @@ abstract class BigDataTestGradleService : BuildService<BigDataTestGradleService.
170174
ContainerLogOptions(
171175
mode = parameters.containerLogMode.get(),
172176
directory = parameters.containerLogDirectory.get(),
177+
append = parameters.containerLogAppend.get(),
173178
),
174179
)
175180

@@ -278,6 +283,9 @@ abstract class BigDataTestGradleService : BuildService<BigDataTestGradleService.
278283
domain = parameters.kerberosDomain.get(),
279284
clientPrincipal = parameters.kerberosClientPrincipal.get(),
280285
clientPassword = parameters.kerberosClientPassword.get(),
286+
materialDirectory = parameters.kerberosMaterialDirectory.get().ifBlank { null },
287+
localKrb5ConfPath = parameters.kerberosLocalKrb5ConfPath.get().ifBlank { null },
288+
localClientKeytabPath = parameters.kerberosLocalClientKeytabPath.get().ifBlank { null },
281289
startupTimeoutSeconds = parameters.kerberosStartupTimeoutSeconds.get(),
282290
materialTimeoutSeconds = parameters.kerberosMaterialTimeoutSeconds.get(),
283291
adminAttempts = parameters.kerberosAdminAttempts.get(),

0 commit comments

Comments
 (0)