From 414ed42e3920dc08e8ca10f486111fb7ff35e02e Mon Sep 17 00:00:00 2001 From: Marty Pitt Date: Mon, 22 Jun 2026 17:00:43 +0100 Subject: [PATCH 01/11] Emit container coordinates based on consumer connectivity mode Containers' host + port are now resolved by an explicit connectivity mode rather than always emitting host-mapped ports and patching the host after the fact via the HTTP Host header. - Add ConsumerConnectivity (HOST | NETWORK) to NebulaConfig, plus a --connectivity CLI flag (NEBULA_CONNECTIVITY), defaulting to host. - Add NebulaConfig.endpointFor(...) resolver: - HOST -> container.host + host-mapped port - NETWORK -> network alias (componentName) + internal port - Emit a discrete host + port on every *ContainerConfig, and rebuild the embedded connection strings (jdbcUrl, mongo connectionString, localstack endpoint, kafka bootstrapServers) from the same resolved endpoint so they can't drift. - Kafka: drop the external-listener/Host-header machinery; emit the host-mapped PLAINTEXT listener in host mode and the in-network BROKER listener (alias:9092) in network mode. - Remove updateHostReferences / HostNameAwareContainerConfig and the server-side Host-header rewrite entirely. Nebula's own internal clients (Hikari, Kafka admin, S3) keep using the TestContainers host-mapped route, unchanged. Refs #61 Co-Authored-By: Claude Opus 4.8 (1M context) --- .../com/orbitalhq/nebula/core/Events.kt | 65 +------------- .../com/orbitalhq/nebula/cli/NebulaCli.kt | 18 +++- .../nebula/InfrastructureComponent.kt | 28 ++++++- .../com/orbitalhq/nebula/StackRunner.kt | 24 +++++- .../nebula/hazelcast/HazelcastExecutor.kt | 13 ++- .../orbitalhq/nebula/kafka/KafkaExecutor.kt | 84 +++++++------------ .../orbitalhq/nebula/mongo/MongoExecutor.kt | 31 ++++--- .../com/orbitalhq/nebula/s3/S3Executor.kt | 27 ++++-- .../orbitalhq/nebula/sql/DatabaseExecutor.kt | 27 +++--- .../com/orbitalhq/nebula/utils/Strings.kt | 5 -- .../nebula/runtime/server/NebulaServer.kt | 9 +- 11 files changed, 163 insertions(+), 168 deletions(-) delete mode 100644 nebula-dsl/src/main/kotlin/com/orbitalhq/nebula/utils/Strings.kt diff --git a/nebula-api/src/main/kotlin/com/orbitalhq/nebula/core/Events.kt b/nebula-api/src/main/kotlin/com/orbitalhq/nebula/core/Events.kt index 1f42da2..4de8e17 100644 --- a/nebula-api/src/main/kotlin/com/orbitalhq/nebula/core/Events.kt +++ b/nebula-api/src/main/kotlin/com/orbitalhq/nebula/core/Events.kt @@ -13,23 +13,7 @@ data class ComponentInfoWithState( val id: String, val state: ComponentLifecycleEvent, val componentInfo: ComponentInfo<*>? -) { - /** - * Returns an updated StackStateEvent where references to the container's host - * are replaced with the provided host. - * - * This is intended for usecases where Nebula is on a different server from - * the consumers. This was references to things like "localhost" get replaced - * with the host that the consumer uses to reach nebula. - */ - fun updateHostReferences(host: String): ComponentInfoWithState { - return if (componentInfo != null) { - copy(componentInfo = componentInfo.updateHostReferences(host)) - } else { - this - } - } -} +) typealias NebulaEnvVariablesMap = Map>> typealias StackName = String typealias ComponentType = String @@ -37,17 +21,6 @@ typealias ComponentName = String typealias EnvVarKey = String typealias EnvVarValue = String -/** - * An optional interface for ContainerConfig classes, - * which are exposing host details. - * - * Allows us to update host names to the host name known to consumers - */ -interface HostNameAwareContainerConfig { - fun updateHostReferences(containerHost: String, publicHost: String): T -} - - data class ComponentInfo( val container: ContainerInfo?, @@ -57,23 +30,6 @@ data class ComponentInfo( val name: ComponentName, val id: String ) { - /** - * Returns an updated StackStateEvent where references to the container's host - * are replaced with the provided host. - * - * This is intended for usecases where Nebula is on a different server from - * the consumers. This was references to things like "localhost" get replaced - * with the host that the consumer uses to reach nebula. - */ - fun updateHostReferences(host: String): ComponentInfo { - return if (container != null && componentConfig is HostNameAwareContainerConfig<*>) { - val containerHost = container.host - copy(componentConfig = componentConfig.updateHostReferences(containerHost, host) as T) - } else { - this - } - } - @get:JsonIgnore val componentConfigMap: Map get() { @@ -94,24 +50,7 @@ data class StackStateEvent( val stackName: String, val stateCounts: Map, val stackState: NebulaStackState -) { - /** - * Returns an updated StackStateEvent where references to the container's host - * are replaced with the provided host. - * - * This is intended for usecases where Nebula is on a different server from - * the consumers. This was references to things like "localhost" get replaced - * with the host that the consumer uses to reach nebula. - */ - fun updateHostReferences(host: String): StackStateEvent { - val updatedStackState = stackState.mapValues { (_, componentInfoList) -> - componentInfoList.map { componentInfoWithState -> - componentInfoWithState.updateHostReferences(host) - } - } - return copy(stackState = updatedStackState) - } -} +) @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "@type") diff --git a/nebula-cli/src/main/kotlin/com/orbitalhq/nebula/cli/NebulaCli.kt b/nebula-cli/src/main/kotlin/com/orbitalhq/nebula/cli/NebulaCli.kt index ff5f7b3..5fafc41 100644 --- a/nebula-cli/src/main/kotlin/com/orbitalhq/nebula/cli/NebulaCli.kt +++ b/nebula-cli/src/main/kotlin/com/orbitalhq/nebula/cli/NebulaCli.kt @@ -1,6 +1,7 @@ package com.orbitalhq.nebula.cli import arrow.core.getOrElse +import com.orbitalhq.nebula.ConsumerConnectivity import com.orbitalhq.nebula.HostConfig import com.orbitalhq.nebula.NebulaConfig import com.orbitalhq.nebula.NebulaStackWithSource @@ -51,6 +52,17 @@ class Nebula : Callable { @Option(names = ["--network"], description = ["The name of the docker network created"], defaultValue = "\${NEBULA_NETWORK:-nebula_network}") lateinit var networkName: String + @Option( + names = ["--connectivity"], + description = [ + "How consumers reach the started containers. ", + "host (default): emit localhost + host-mapped ports (developer CLI / Linux host-networking). ", + "network: emit the container's network alias + internal port, for consumers on the same docker network (eg. Orbital in docker-compose)." + ], + defaultValue = "\${NEBULA_CONNECTIVITY:-host}" + ) + lateinit var connectivity: ConsumerConnectivity + private var fileWatcher: FileWatcher? = null private var currentStackRunner: StackRunner? = null @@ -61,7 +73,8 @@ class Nebula : Callable { } val network = networkOrError.getOrThrow() spec.commandLine().out.println("Nebula using network name $networkName maps to ${network.id}") - val nebulaConfig = NebulaConfig(networkName, network) + spec.commandLine().out.println("Nebula emitting container coordinates for $connectivity connectivity") + val nebulaConfig = NebulaConfig(networkName, network, connectivity) when { scriptFile != null -> return executeScript(nebulaConfig) httpPort != null -> return startHttpServer(nebulaConfig) @@ -204,7 +217,8 @@ class Nebula : Callable { } } -fun main(args: Array): Unit = exitProcess(CommandLine(Nebula()).execute(*args)) +fun main(args: Array): Unit = + exitProcess(CommandLine(Nebula()).setCaseInsensitiveEnumValuesAllowed(true).execute(*args)) class ExistingDockerNetwork(private val id: String) : Network { override fun close() { diff --git a/nebula-dsl/src/main/kotlin/com/orbitalhq/nebula/InfrastructureComponent.kt b/nebula-dsl/src/main/kotlin/com/orbitalhq/nebula/InfrastructureComponent.kt index 5d93d42..d19e9bd 100644 --- a/nebula-dsl/src/main/kotlin/com/orbitalhq/nebula/InfrastructureComponent.kt +++ b/nebula-dsl/src/main/kotlin/com/orbitalhq/nebula/InfrastructureComponent.kt @@ -39,11 +39,35 @@ interface InfrastructureComponent { } -fun containerInfoFrom(container: GenericContainer<*>):ContainerInfo { +fun containerInfoFrom(container: GenericContainer<*>, host: String = container.host):ContainerInfo { return ContainerInfo( containerId = container.containerId, imageName = container.dockerImageName, containerName = container.containerName, - host = container.host + host = host ) } + +/** + * The host + port a consumer should use to reach a container, resolved + * according to the configured [ConsumerConnectivity] mode. + */ +data class Endpoint(val host: String, val port: Int) { + val hostAndPort: String get() = "$host:$port" +} + +/** + * Resolves the [Endpoint] a consumer should use for [container], given the + * connectivity mode on this config. + * + * @param alias the container's network alias (conventionally its componentName) + * @param internalPort the port the service listens on inside the container + */ +fun NebulaConfig.endpointFor( + container: GenericContainer<*>, + alias: String, + internalPort: Int +): Endpoint = when (connectivity) { + ConsumerConnectivity.HOST -> Endpoint(container.host, container.getMappedPort(internalPort)) + ConsumerConnectivity.NETWORK -> Endpoint(alias, internalPort) +} diff --git a/nebula-dsl/src/main/kotlin/com/orbitalhq/nebula/StackRunner.kt b/nebula-dsl/src/main/kotlin/com/orbitalhq/nebula/StackRunner.kt index fc26238..dc4750e 100644 --- a/nebula-dsl/src/main/kotlin/com/orbitalhq/nebula/StackRunner.kt +++ b/nebula-dsl/src/main/kotlin/com/orbitalhq/nebula/StackRunner.kt @@ -12,9 +12,31 @@ import java.util.UUID import java.util.concurrent.ConcurrentHashMap import kotlin.concurrent.thread +/** + * Determines the coordinates (host + port) that Nebula emits to consumers + * for the containers it starts. + * + * This is about where the *consumer* sits relative to the containers, not + * where Nebula itself runs: + * + * - [HOST]: the consumer reaches containers from the host machine (e.g. a + * developer running the CLI, or a Linux host-networking compose). Emit + * `localhost` + the host-mapped (external) port. + * - [NETWORK]: the consumer is another container on the shared `nebula_network` + * (e.g. Orbital in a docker-compose deployment). Emit the container's + * network alias + its internal port, so consumers talk to it directly over + * the docker network. + * + * Note this is distinct from how Nebula's *own* internal clients (Hikari, the + * Kafka admin client, etc.) reach the containers - those always use the + * TestContainers host-mapped route regardless of this setting. + */ +enum class ConsumerConnectivity { HOST, NETWORK } + data class NebulaConfig( val networkName: String = "nebula_network", - val network: Network = Network.newNetwork() + val network: Network = Network.newNetwork(), + val connectivity: ConsumerConnectivity = ConsumerConnectivity.HOST ) /** diff --git a/nebula-dsl/src/main/kotlin/com/orbitalhq/nebula/hazelcast/HazelcastExecutor.kt b/nebula-dsl/src/main/kotlin/com/orbitalhq/nebula/hazelcast/HazelcastExecutor.kt index 03cd0c4..430f3d6 100644 --- a/nebula-dsl/src/main/kotlin/com/orbitalhq/nebula/hazelcast/HazelcastExecutor.kt +++ b/nebula-dsl/src/main/kotlin/com/orbitalhq/nebula/hazelcast/HazelcastExecutor.kt @@ -9,6 +9,7 @@ import com.orbitalhq.nebula.core.ComponentInfo import com.orbitalhq.nebula.core.ComponentLifecycleEvent import com.orbitalhq.nebula.core.ComponentName import com.orbitalhq.nebula.core.ComponentType +import com.orbitalhq.nebula.endpointFor import com.orbitalhq.nebula.events.ComponentLifecycleEventSource import com.orbitalhq.nebula.logging.LogStream import com.orbitalhq.nebula.logging.LoggerName @@ -25,8 +26,12 @@ val StackRunner.hazelcast: List data class HazelcastContainerConfig( + val host: String, val port: Int ) + +// The port Hazelcast listens on inside the container. +private const val HAZELCAST_INTERNAL_PORT = 5701 class HazelcastExecutor(private val config: HazelcastConfig, loggers: List) : InfrastructureComponent { companion object { private val logger = KotlinLogging.logger {} @@ -41,16 +46,18 @@ class HazelcastExecutor(private val config: HazelcastConfig, loggers: List { eventSource.starting() container = GenericContainer(DockerImageName.parse(config.imageName)) - .withExposedPorts(5701) + .withExposedPorts(HAZELCAST_INTERNAL_PORT) .withNetwork(nebulaConfig.network) .withNetworkAliases(config.componentName) container.waitingFor(Wait.forListeningPort()) eventSource.startContainerAndEmitEvents(container, name) + val endpoint = nebulaConfig.endpointFor(container, config.componentName, HAZELCAST_INTERNAL_PORT) componentInfo = ComponentInfo( - containerInfoFrom(container), + containerInfoFrom(container, endpoint.host), HazelcastContainerConfig( - container.firstMappedPort + endpoint.host, + endpoint.port ), type = type, name = name, diff --git a/nebula-dsl/src/main/kotlin/com/orbitalhq/nebula/kafka/KafkaExecutor.kt b/nebula-dsl/src/main/kotlin/com/orbitalhq/nebula/kafka/KafkaExecutor.kt index 6eb0df9..c3e99af 100644 --- a/nebula-dsl/src/main/kotlin/com/orbitalhq/nebula/kafka/KafkaExecutor.kt +++ b/nebula-dsl/src/main/kotlin/com/orbitalhq/nebula/kafka/KafkaExecutor.kt @@ -1,5 +1,6 @@ package com.orbitalhq.nebula.kafka +import com.orbitalhq.nebula.ConsumerConnectivity import com.orbitalhq.nebula.HostConfig import com.orbitalhq.nebula.InfrastructureComponent import com.orbitalhq.nebula.NebulaConfig @@ -7,7 +8,6 @@ import com.orbitalhq.nebula.StackRunner import com.orbitalhq.nebula.containerInfoFrom import com.orbitalhq.nebula.core.ComponentInfo import com.orbitalhq.nebula.core.ComponentLifecycleEvent -import com.orbitalhq.nebula.core.HostNameAwareContainerConfig import com.orbitalhq.nebula.events.ComponentLifecycleEventSource import com.orbitalhq.nebula.logging.LogStream import com.orbitalhq.nebula.logging.LoggerName @@ -67,14 +67,12 @@ class KafkaExecutor(private val config: KafkaConfig, loggers: List) override fun start(nebulaConfig: NebulaConfig, hostConfig: HostConfig): ComponentInfo { kafkaContainer = KafkaContainer(DockerImageName.parse(config.imageName)) - .let { container -> - configureExternalListenerAddresses(hostConfig, container) - } .withNetwork(nebulaConfig.network) .withNetworkAliases(config.componentName) eventSource.startContainerAndEmitEvents(kafkaContainer, name) + // Nebula's own admin client + producers connect via the host-mapped listener. val bootstrapServers = kafkaContainer.bootstrapServers logger.info { "Kafka container started - bootstrap servers: $bootstrapServers" } @@ -113,11 +111,29 @@ class KafkaExecutor(private val config: KafkaConfig, loggers: List) producerJobs.add(job) } + // The coordinates consumers should use, resolved by connectivity mode: + // - HOST: the PLAINTEXT listener mapped onto the host (localhost:) + // - NETWORK: the in-network BROKER listener, reachable via the container's + // network alias on nebula_network (alias:9092) + val (emittedHost, emittedPort, emittedBootstrapServers) = when (nebulaConfig.connectivity) { + ConsumerConnectivity.HOST -> Triple( + kafkaContainer.host, + kafkaContainer.getMappedPort(KafkaContainer.KAFKA_PORT), + kafkaContainer.bootstrapServers + ) + ConsumerConnectivity.NETWORK -> Triple( + config.componentName, + KAFKA_INTERNAL_BROKER_PORT, + "PLAINTEXT://${config.componentName}:$KAFKA_INTERNAL_BROKER_PORT" + ) + } + componentInfo = ComponentInfo( - containerInfoFrom(kafkaContainer), + containerInfoFrom(kafkaContainer, emittedHost), KafkaContainerConfig( - kafkaContainer.bootstrapServers, - addressToProtocol + bootstrapServers = emittedBootstrapServers, + host = emittedHost, + port = emittedPort ), type = type, name = name, @@ -128,41 +144,6 @@ class KafkaExecutor(private val config: KafkaConfig, loggers: List) eventSource.running() return componentInfo!! } - private val addressToProtocol = mutableMapOf() - - /** - * Configures listeners for the external addresses that - * we're known by. Otherwise consumers who are connecting from - * an external IP address can't connect to Kafka. - * - * Works by establishing a custom protocol mapping (test containers adds a TC-0 / TC-1 etc.. to the front) - */ - private fun configureExternalListenerAddresses( - hostConfig: HostConfig, - container: KafkaContainer - ): KafkaContainer { - hostConfig.hostAddresses.forEachIndexed { index, externalAddress -> - // each custom address gets a port incrementally higher than 9094 - val port = 9094 + index - - container.addExposedPort(port) - container.withListener { - try { - // If this doesn't throw an error, we're building the KAFKA_ADVERTISED_LISTENER part - val mappedPort = container.getMappedPort(port) - logger.info { "Configuring external Kafka listener for $externalAddress:$port" } - // Test containers maps these as TC-0://0.0.0.0:909X - val protocol = "TC-$index" - addressToProtocol.put(externalAddress, "$protocol://$externalAddress:$mappedPort") - "$externalAddress:$mappedPort" - } catch (e: IllegalStateException) { - // The container isn't ready yet, so we're building the internal KAFKA_LISTENER - "0.0.0.0:$port" - } - } - } - return container - } override fun stop() { eventSource.stopping() @@ -218,14 +199,11 @@ class KafkaExecutor(private val config: KafkaConfig, loggers: List) } } -data class KafkaContainerConfig(val bootstrapServers: String, private val externalAddressToListenerProtocol:Map) : HostNameAwareContainerConfig { - override fun updateHostReferences(containerHost: String, publicHost: String): KafkaContainerConfig { - // If we configured a dedicated bootstrap server protocol for this host, then use that - val dedicatedBootstrapServer = externalAddressToListenerProtocol[publicHost] - return if (dedicatedBootstrapServer != null) { - copy(bootstrapServers = dedicatedBootstrapServer) - } else { - this - } - } -} +data class KafkaContainerConfig( + val bootstrapServers: String, + val host: String, + val port: Int +) + +// The port the in-network (BROKER) Kafka listener advertises on nebula_network. +private const val KAFKA_INTERNAL_BROKER_PORT = 9092 diff --git a/nebula-dsl/src/main/kotlin/com/orbitalhq/nebula/mongo/MongoExecutor.kt b/nebula-dsl/src/main/kotlin/com/orbitalhq/nebula/mongo/MongoExecutor.kt index b12e5a9..87e5f50 100644 --- a/nebula-dsl/src/main/kotlin/com/orbitalhq/nebula/mongo/MongoExecutor.kt +++ b/nebula-dsl/src/main/kotlin/com/orbitalhq/nebula/mongo/MongoExecutor.kt @@ -10,11 +10,10 @@ import com.orbitalhq.nebula.core.ComponentInfo import com.orbitalhq.nebula.core.ComponentLifecycleEvent import com.orbitalhq.nebula.core.ComponentName import com.orbitalhq.nebula.core.ComponentType -import com.orbitalhq.nebula.core.HostNameAwareContainerConfig +import com.orbitalhq.nebula.endpointFor import com.orbitalhq.nebula.events.ComponentLifecycleEventSource import com.orbitalhq.nebula.logging.LogStream import com.orbitalhq.nebula.logging.LoggerName -import com.orbitalhq.nebula.utils.updateHostReferences import io.github.oshai.kotlinlogging.KotlinLogging import org.bson.Document import org.testcontainers.containers.MongoDBContainer @@ -44,17 +43,27 @@ class MongoExecutor(private val config: MongoConfig, loggers: List) .withNetwork(nebulaConfig.network) .withNetworkAliases(config.componentName) eventSource.startContainerAndEmitEvents(mongoContainer, name) { + val internalPort = MONGO_INTERNAL_PORT + val endpoint = nebulaConfig.endpointFor(mongoContainer, config.componentName, internalPort) + // The TestContainers connectionString embeds the host-mapped coordinates; + // swap them for the resolved endpoint so the emitted string matches the mode. + val emittedConnectionString = mongoContainer.connectionString.replace( + "${mongoContainer.host}:${mongoContainer.getMappedPort(internalPort)}", + endpoint.hostAndPort + ) componentInfo = ComponentInfo( - containerInfoFrom(mongoContainer), + containerInfoFrom(mongoContainer, endpoint.host), MongoContainerConfig( - mongoContainer.connectionString, - mongoContainer.firstMappedPort + emittedConnectionString, + endpoint.host, + endpoint.port ), type = type, name = name, id = id ) + // Nebula's own client connects via the host-mapped connection string. val mongoClient = MongoClients.create(mongoContainer.connectionString) // Force creation of the database val mongoDb = mongoClient.getDatabase(config.databaseName) @@ -93,13 +102,9 @@ class MongoExecutor(private val config: MongoConfig, loggers: List) data class MongoContainerConfig( val connectionString: String, + val host: String, val port: Int -) : HostNameAwareContainerConfig { - override fun updateHostReferences(containerHost: String, publicHost: String): MongoContainerConfig { - return MongoContainerConfig( - connectionString.updateHostReferences(containerHost, publicHost), - port - ) - } +) -} \ No newline at end of file +// The port MongoDB listens on inside the container. +private const val MONGO_INTERNAL_PORT = 27017 \ No newline at end of file diff --git a/nebula-dsl/src/main/kotlin/com/orbitalhq/nebula/s3/S3Executor.kt b/nebula-dsl/src/main/kotlin/com/orbitalhq/nebula/s3/S3Executor.kt index f27fc5c..54e4703 100644 --- a/nebula-dsl/src/main/kotlin/com/orbitalhq/nebula/s3/S3Executor.kt +++ b/nebula-dsl/src/main/kotlin/com/orbitalhq/nebula/s3/S3Executor.kt @@ -7,11 +7,10 @@ import com.orbitalhq.nebula.StackRunner import com.orbitalhq.nebula.containerInfoFrom import com.orbitalhq.nebula.core.ComponentInfo import com.orbitalhq.nebula.core.ComponentLifecycleEvent -import com.orbitalhq.nebula.core.HostNameAwareContainerConfig +import com.orbitalhq.nebula.endpointFor import com.orbitalhq.nebula.events.ComponentLifecycleEventSource import com.orbitalhq.nebula.logging.LogStream import com.orbitalhq.nebula.logging.LoggerName -import com.orbitalhq.nebula.utils.updateHostReferences import org.testcontainers.containers.localstack.LocalStackContainer import org.testcontainers.utility.DockerImageName import reactor.core.publisher.Flux @@ -55,6 +54,7 @@ class S3Executor(private val config: S3Config, loggers: List) : Infr .withNetworkAliases(config.componentName) eventSource.startContainerAndEmitEvents(localstack, name) + // Nebula's own client connects via the host-mapped endpoint. val endpointOverride = localstack.getEndpointOverride(LocalStackContainer.Service.S3) s3Client = S3Client.builder() .endpointOverride(endpointOverride) @@ -67,12 +67,21 @@ class S3Executor(private val config: S3Config, loggers: List) : Infr uploadResources(bucketConfig) } + // The emitted endpoint swaps the host-mapped coordinates for the resolved ones. + val endpoint = nebulaConfig.endpointFor(localstack, config.componentName, LOCALSTACK_INTERNAL_PORT) + val emittedEndpointOverride = endpointOverride.toASCIIString().replace( + "${localstack.host}:${localstack.getMappedPort(LOCALSTACK_INTERNAL_PORT)}", + endpoint.hostAndPort + ) + componentInfo = ComponentInfo( - containerInfoFrom(localstack), + containerInfoFrom(localstack, endpoint.host), LocalstackContainerConfig( accessKey = localstack.accessKey, secretKey = localstack.secretKey, - endpointOverride = endpointOverride.toASCIIString() + host = endpoint.host, + port = endpoint.port, + endpointOverride = emittedEndpointOverride ), type = type, name = name, @@ -145,10 +154,10 @@ class S3Executor(private val config: S3Config, loggers: List) : Infr data class LocalstackContainerConfig( val accessKey: String, val secretKey: String, + val host: String, + val port: Int, val endpointOverride: String -) : HostNameAwareContainerConfig { - override fun updateHostReferences(containerHost: String, publicHost: String): LocalstackContainerConfig { - return copy(endpointOverride = endpointOverride.updateHostReferences(containerHost, publicHost)) - } +) -} \ No newline at end of file +// The (edge) port LocalStack listens on inside the container. +private const val LOCALSTACK_INTERNAL_PORT = 4566 \ No newline at end of file diff --git a/nebula-dsl/src/main/kotlin/com/orbitalhq/nebula/sql/DatabaseExecutor.kt b/nebula-dsl/src/main/kotlin/com/orbitalhq/nebula/sql/DatabaseExecutor.kt index e7efa93..4e401fc 100644 --- a/nebula-dsl/src/main/kotlin/com/orbitalhq/nebula/sql/DatabaseExecutor.kt +++ b/nebula-dsl/src/main/kotlin/com/orbitalhq/nebula/sql/DatabaseExecutor.kt @@ -7,11 +7,10 @@ import com.orbitalhq.nebula.StackRunner import com.orbitalhq.nebula.containerInfoFrom import com.orbitalhq.nebula.core.ComponentInfo import com.orbitalhq.nebula.core.ComponentLifecycleEvent -import com.orbitalhq.nebula.core.HostNameAwareContainerConfig +import com.orbitalhq.nebula.endpointFor import com.orbitalhq.nebula.events.ComponentLifecycleEventSource import com.orbitalhq.nebula.logging.LogStream import com.orbitalhq.nebula.logging.LoggerName -import com.orbitalhq.nebula.utils.updateHostReferences import com.zaxxer.hikari.HikariConfig import com.zaxxer.hikari.HikariDataSource import io.github.oshai.kotlinlogging.KotlinLogging @@ -62,14 +61,25 @@ class DatabaseExecutor(private val config: DatabaseConfig, loggers: List { - override fun updateHostReferences(containerHost: String, publicHost: String): DatabaseContainerConfig { - return copy(jdbcUrl = jdbcUrl.updateHostReferences(containerHost, publicHost)) - } -} \ No newline at end of file +) \ No newline at end of file diff --git a/nebula-dsl/src/main/kotlin/com/orbitalhq/nebula/utils/Strings.kt b/nebula-dsl/src/main/kotlin/com/orbitalhq/nebula/utils/Strings.kt deleted file mode 100644 index 283d27c..0000000 --- a/nebula-dsl/src/main/kotlin/com/orbitalhq/nebula/utils/Strings.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.orbitalhq.nebula.utils - -fun String.updateHostReferences(containerHost:String, publicHost: String):String { - return this.replace(containerHost, publicHost) -} \ No newline at end of file diff --git a/nebula-runtime/src/main/kotlin/com/orbitalhq/nebula/runtime/server/NebulaServer.kt b/nebula-runtime/src/main/kotlin/com/orbitalhq/nebula/runtime/server/NebulaServer.kt index 118f46f..011a184 100644 --- a/nebula-runtime/src/main/kotlin/com/orbitalhq/nebula/runtime/server/NebulaServer.kt +++ b/nebula-runtime/src/main/kotlin/com/orbitalhq/nebula/runtime/server/NebulaServer.kt @@ -215,11 +215,10 @@ class NebulaServer( val id = call.parameters["id"] ?: return@webSocket close( CloseReason(CloseReason.Codes.CANNOT_ACCEPT, "Missing id") ) - val host = call.request.host() val disposable = try { stackExecutor.stackEvents(id).subscribe { event -> runBlocking { - send(Frame.Text(objectMapper.writeValueAsString(event.updateHostReferences(host)))) + send(Frame.Text(objectMapper.writeValueAsString(event))) } } } catch (e: Exception) { @@ -235,9 +234,6 @@ class NebulaServer( } webSocket("/stream/stacks") { val call = call - // We capture the host on the request. That's the address that the caller is contacting this server on. - // We can use this later to rewrite references to the docker containers using the correct host names - val host = call.request.host() incoming.consumeEach { frame -> require(frame is Frame.Text) { "Only text frames supported" } val payloadJson = frame.readText() @@ -252,10 +248,9 @@ class NebulaServer( } Flux.merge(eventStreams) .subscribe { event -> - val eventWithHostReferences = event.updateHostReferences(host) logger.info { "Emitting stack status event for stack ${event.stackName}" } runBlocking { - val stackStatusJson = objectMapper.writeValueAsString(eventWithHostReferences) + val stackStatusJson = objectMapper.writeValueAsString(event) send(Frame.Text(stackStatusJson)) } From 070d3195d423250da5c345fb69331b1d98166818 Mon Sep 17 00:00:00 2001 From: Marty Pitt Date: Mon, 22 Jun 2026 18:23:36 +0100 Subject: [PATCH 02/11] docs: document --connectivity flag and connectivity modes Add a concise CLI & networking page covering the nebula CLI options (--http, --network, --connectivity, --verbose) and the host vs network connectivity modes, and register it in the docs nav. Refs #61 Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/pages/_meta.ts | 1 + docs/pages/cli.mdx | 45 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 docs/pages/cli.mdx diff --git a/docs/pages/_meta.ts b/docs/pages/_meta.ts index fa6ccd9..a015bea 100644 --- a/docs/pages/_meta.ts +++ b/docs/pages/_meta.ts @@ -1,6 +1,7 @@ export default { "index": "Getting started", "stacks": "Working with stacks", + "cli": "CLI & networking", "logging" : "Logging", "examples": "Examples", }; diff --git a/docs/pages/cli.mdx b/docs/pages/cli.mdx new file mode 100644 index 0000000..ae0af74 --- /dev/null +++ b/docs/pages/cli.mdx @@ -0,0 +1,45 @@ +--- +title: CLI & networking +--- + +## CLI options + +Nebula either runs a script directly, or starts an HTTP server that accepts stacks over HTTP. + +```bash +# Run a script +nebula my-stack.nebula.kts + +# Start the HTTP server on port 8099 +nebula --http=8099 +``` + +| Option | Env var | Default | Description | +|------------------|----------------------|------------------|-----------------------------------------------------------------------------| +| `--http` | | | Start the HTTP server on the given port instead of running a script | +| `--network` | `NEBULA_NETWORK` | `nebula_network` | The name of the docker network containers are attached to (created if absent) | +| `--connectivity` | `NEBULA_CONNECTIVITY`| `host` | How the host + port of each container is reported to consumers (see below) | +| `-v`, `--verbose`| | `false` | Enable verbose output | + +## Connectivity modes + +For every container it starts, Nebula reports a `host` and `port` (and connection strings +such as `jdbcUrl` or `bootstrapServers`). `--connectivity` controls which coordinates are +reported, depending on where the *consumer* sits relative to the containers: + +| Mode | Host reported | Port reported | Use when | +|-----------|--------------------|-------------------------|--------------------------------------------------------------------------| +| `host` | `localhost` | host-mapped (external) | The consumer reaches containers from the host machine — a developer running the CLI, or a Linux host-networking deployment. **(default)** | +| `network` | container's alias | internal container port | The consumer is another container on the same docker network — e.g. Orbital in a docker-compose deployment. | + +In `network` mode consumers talk to the containers directly over `nebula_network`, so no +host port-mapping is involved. + +```bash +# Reporting in-network coordinates (e.g. running alongside Orbital in docker-compose) +nebula --http=8099 --connectivity=network +``` + +This only affects what Nebula *reports*. Nebula's own internal clients (used to create +tables, topics, buckets, etc.) always reach the containers via the host-mapped route, +regardless of this setting. From 9711463c3bf802ac2cb88ec9c0129b97361bb4cb Mon Sep 17 00:00:00 2001 From: Marty Pitt Date: Mon, 22 Jun 2026 18:39:31 +0100 Subject: [PATCH 03/11] Detect own docker network in network mode In network connectivity mode, attach child containers to the network Nebula itself is running on, rather than guessing by name. Nebula reads its own container id from /etc/hostname, inspects itself, and selects the attached network whose name contains --network (default nebula_network). This fixes startup failures when multiple Orbital/Nebula compose projects run on the same host and several *_nebula_network networks exist - name-based lookup matched all of them and bailed out. Host mode keeps the existing name-lookup / create-isolated behaviour. Network selection is extracted as a pure function with unit coverage. Closes #62 Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/pages/cli.mdx | 8 +- .../com/orbitalhq/nebula/cli/NebulaCli.kt | 90 ++++++++++++++++++- .../nebula/cli/SelectAttachedNetworkTest.kt | 31 +++++++ 3 files changed, 126 insertions(+), 3 deletions(-) create mode 100644 nebula-cli/src/test/kotlin/com/orbitalhq/nebula/cli/SelectAttachedNetworkTest.kt diff --git a/docs/pages/cli.mdx b/docs/pages/cli.mdx index ae0af74..051f334 100644 --- a/docs/pages/cli.mdx +++ b/docs/pages/cli.mdx @@ -32,8 +32,12 @@ reported, depending on where the *consumer* sits relative to the containers: | `host` | `localhost` | host-mapped (external) | The consumer reaches containers from the host machine — a developer running the CLI, or a Linux host-networking deployment. **(default)** | | `network` | container's alias | internal container port | The consumer is another container on the same docker network — e.g. Orbital in a docker-compose deployment. | -In `network` mode consumers talk to the containers directly over `nebula_network`, so no -host port-mapping is involved. +In `network` mode consumers talk to the containers directly over the shared docker network, +so no host port-mapping is involved. Nebula attaches the containers it starts to its **own** +network — it inspects the container it is running in and picks the attached network whose name +contains `--network` (default `nebula_network`). This works even when several compose projects +(`project-a_nebula_network`, `project-b_nebula_network`, …) run on the same host. If Nebula is +attached to more than one matching network, set `--network` to a more specific name. ```bash # Reporting in-network coordinates (e.g. running alongside Orbital in docker-compose) diff --git a/nebula-cli/src/main/kotlin/com/orbitalhq/nebula/cli/NebulaCli.kt b/nebula-cli/src/main/kotlin/com/orbitalhq/nebula/cli/NebulaCli.kt index 5fafc41..8a3a5bf 100644 --- a/nebula-cli/src/main/kotlin/com/orbitalhq/nebula/cli/NebulaCli.kt +++ b/nebula-cli/src/main/kotlin/com/orbitalhq/nebula/cli/NebulaCli.kt @@ -67,7 +67,7 @@ class Nebula : Callable { private var currentStackRunner: StackRunner? = null override fun call(): Int { - val networkOrError = discoverActualNetworkName() + val networkOrError = resolveNetwork() if (networkOrError.isFailure) { return spec.exitCodeOnExecutionException() } @@ -85,6 +85,54 @@ class Nebula : Callable { } } + /** + * Resolves the docker network to attach child containers to. + * + * In `network` connectivity mode Nebula is running inside a container + * alongside its consumers (eg. Orbital in docker-compose), so we attach + * children to *our own* network - this is the only reliable way to pick the + * right one when several `*_$networkName` networks exist on the host (eg. + * multiple compose projects). In `host` mode we fall back to looking up (or + * creating) a network by name. + */ + private fun resolveNetwork(): Result = when (connectivity) { + ConsumerConnectivity.NETWORK -> resolveOwnContainerNetwork() + ConsumerConnectivity.HOST -> discoverActualNetworkName() + } + + /** + * Determines the network by inspecting the container Nebula itself is + * running in, and selecting the attached network whose name matches + * [networkName]. + */ + private fun resolveOwnContainerNetwork(): Result { + val containerId = readOwnContainerId() + ?: return fail( + "Running with --connectivity=network, but Nebula's own container id could not be read from /etc/hostname. " + + "This mode requires Nebula to run inside a container; use --connectivity=host when running on the host directly." + ) + + val dockerClient = DockerClientFactory.lazyClient() + val container = try { + dockerClient.inspectContainerCmd(containerId).exec() + } catch (e: Exception) { + return fail( + "Running with --connectivity=network, but Nebula could not inspect its own container ('$containerId') " + + "to determine its docker network: ${e.message}. " + + "If a custom hostname is set on the container, /etc/hostname no longer matches the container id." + ) + } + + val attachedNetworks = container.networkSettings.networks.keys + return selectAttachedNetwork(attachedNetworks, networkName).fold( + onSuccess = { name -> + spec.commandLine().out.println("Nebula detected it is running on docker network '$name' - child containers will be attached to it") + Result.success(ExistingDockerNetwork(name)) + }, + onFailure = { fail(it.message ?: "Could not determine Nebula's docker network") } + ) + } + private fun discoverActualNetworkName():Result { val dockerClient = DockerClientFactory.lazyClient() val networks = dockerClient.listNetworksCmd().withNameFilter(networkName).exec() @@ -105,6 +153,21 @@ class Nebula : Callable { } } + private fun fail(message: String): Result { + spec.commandLine().err.println(message) + return Result.failure(IllegalStateException(message)) + } + + /** + * The container id Nebula is running as. Inside a container `/etc/hostname` + * holds the short container id (unless a custom hostname was set), which + * docker can resolve for an inspect call. + */ + private fun readOwnContainerId(): String? = + runCatching { File("/etc/hostname").readText().trim() } + .getOrNull() + ?.takeIf { it.isNotBlank() } + private fun executeScript(nebulaConfig: NebulaConfig): Int { val file = scriptFile ?: throw ParameterException(spec.commandLine(), "Script file is required") if (!file.exists() || !file.isFile || !file.canRead()) { @@ -220,6 +283,31 @@ class Nebula : Callable { fun main(args: Array): Unit = exitProcess(CommandLine(Nebula()).setCaseInsensitiveEnumValuesAllowed(true).execute(*args)) +/** + * From the set of networks a container is attached to, selects the single one + * whose name contains [identifier]. Returns a failure (rather than guessing) + * when zero or more than one network matches, so callers can surface a clear + * diagnostic. + */ +fun selectAttachedNetwork(attachedNetworks: Set, identifier: String): Result { + val matches = attachedNetworks.filter { it.contains(identifier) } + return when (matches.size) { + 1 -> Result.success(matches.single()) + 0 -> Result.failure( + IllegalStateException( + "Running with --connectivity=network, but none of the networks Nebula is attached to ($attachedNetworks) " + + "contain '$identifier'. Set --network (or NEBULA_NETWORK) to match your network name." + ) + ) + else -> Result.failure( + IllegalStateException( + "Running with --connectivity=network, but Nebula is attached to multiple networks matching '$identifier': $matches. " + + "Set --network (or NEBULA_NETWORK) to a more specific name." + ) + ) + } +} + class ExistingDockerNetwork(private val id: String) : Network { override fun close() { } diff --git a/nebula-cli/src/test/kotlin/com/orbitalhq/nebula/cli/SelectAttachedNetworkTest.kt b/nebula-cli/src/test/kotlin/com/orbitalhq/nebula/cli/SelectAttachedNetworkTest.kt new file mode 100644 index 0000000..111d033 --- /dev/null +++ b/nebula-cli/src/test/kotlin/com/orbitalhq/nebula/cli/SelectAttachedNetworkTest.kt @@ -0,0 +1,31 @@ +package com.orbitalhq.nebula.cli + +import io.kotest.core.spec.style.DescribeSpec +import io.kotest.matchers.shouldBe + +class SelectAttachedNetworkTest : DescribeSpec({ + describe("selectAttachedNetwork") { + it("selects the single network whose name contains the identifier") { + selectAttachedNetwork(setOf("bridge", "project-a_nebula_network"), "nebula_network") + .getOrNull() shouldBe "project-a_nebula_network" + } + + it("matches a compose-prefixed network name") { + selectAttachedNetwork(setOf("project-b_nebula_network"), "nebula_network") + .getOrNull() shouldBe "project-b_nebula_network" + } + + it("fails when no attached network matches") { + selectAttachedNetwork(setOf("bridge", "host"), "nebula_network") + .isFailure shouldBe true + } + + it("fails when more than one attached network matches") { + val result = selectAttachedNetwork( + setOf("project-a_nebula_network", "project-b_nebula_network"), + "nebula_network" + ) + result.isFailure shouldBe true + } + } +}) From eba24e0e4440b8b092596ed6c1c431a2d9d20b15 Mon Sep 17 00:00:00 2001 From: Marty Pitt Date: Mon, 22 Jun 2026 19:03:55 +0100 Subject: [PATCH 04/11] docs: add docker-compose example for network mode Show how to enable network connectivity mode via NEBULA_CONNECTIVITY (or a command: override) in docker-compose, the primary deployment for that mode. Refs #61 #62 Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/pages/cli.mdx | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/docs/pages/cli.mdx b/docs/pages/cli.mdx index 051f334..50e83f5 100644 --- a/docs/pages/cli.mdx +++ b/docs/pages/cli.mdx @@ -47,3 +47,34 @@ nebula --http=8099 --connectivity=network This only affects what Nebula *reports*. Nebula's own internal clients (used to create tables, topics, buckets, etc.) always reach the containers via the host-mapped route, regardless of this setting. + +### Enabling network mode in docker-compose + +When Nebula runs alongside Orbital in docker-compose, set `network` mode via the +`NEBULA_CONNECTIVITY` environment variable: + +```yaml + nebula: + image: orbitalhq/nebula:latest + networks: + - nebula_network + ports: + - "8099:8099" + volumes: + - /var/run/docker.sock:/var/run/docker.sock # let Nebula control Docker + environment: + - DOCKER_HOST=unix:///var/run/docker.sock + - NEBULA_CONNECTIVITY=network +``` + +Nebula attaches the containers it starts to the same network it is on (here +`nebula_network`, which compose names `_nebula_network`), so Orbital and the +started containers can talk to each other directly — no `host.docker.internal` or +host-networking workarounds required. + +Alternatively, pass the flag as a `command:` (appended to the image's entrypoint, which +already includes `--http=8099`): + +```yaml + command: ["--connectivity=network"] +``` From 2e86e38bb9aba050320b5265cd6f57ca99521d51 Mon Sep 17 00:00:00 2001 From: Marty Pitt Date: Tue, 23 Jun 2026 05:42:05 +0100 Subject: [PATCH 05/11] Use an isolated network in host mode; stop discovering by name Host mode reached containers via host port-mapping, so the network they sit on is irrelevant - yet it still called discoverActualNetworkName(), which queried docker and failed when multiple *_nebula_network networks existed (the same failure as #62, just on the host path). Host mode now always creates an isolated network (enough for intra-stack DNS aliases), removing that docker round-trip entirely. discoverActualNetworkName() is deleted. Network mode additionally fails fast when Nebula isn't running inside a container (detected via /.dockerenv, /run/.containerenv, or /proc/1/cgroup), giving a clear "use --connectivity=host" message instead of an inspect error. Refs #62 Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/pages/cli.mdx | 2 +- .../com/orbitalhq/nebula/cli/NebulaCli.kt | 73 +++++++++++------- .../META-INF/nebula-runtime.kotlin_module | Bin 0 -> 94 bytes 3 files changed, 45 insertions(+), 30 deletions(-) create mode 100644 nebula-runtime/${project.build.directory}/classes/META-INF/nebula-runtime.kotlin_module diff --git a/docs/pages/cli.mdx b/docs/pages/cli.mdx index 50e83f5..6cf32f1 100644 --- a/docs/pages/cli.mdx +++ b/docs/pages/cli.mdx @@ -17,7 +17,7 @@ nebula --http=8099 | Option | Env var | Default | Description | |------------------|----------------------|------------------|-----------------------------------------------------------------------------| | `--http` | | | Start the HTTP server on the given port instead of running a script | -| `--network` | `NEBULA_NETWORK` | `nebula_network` | The name of the docker network containers are attached to (created if absent) | +| `--network` | `NEBULA_NETWORK` | `nebula_network` | Identifies the docker network to attach started containers to. Only used in `network` mode (see below); in `host` mode an isolated network is always created | | `--connectivity` | `NEBULA_CONNECTIVITY`| `host` | How the host + port of each container is reported to consumers (see below) | | `-v`, `--verbose`| | `false` | Enable verbose output | diff --git a/nebula-cli/src/main/kotlin/com/orbitalhq/nebula/cli/NebulaCli.kt b/nebula-cli/src/main/kotlin/com/orbitalhq/nebula/cli/NebulaCli.kt index 8a3a5bf..fe62507 100644 --- a/nebula-cli/src/main/kotlin/com/orbitalhq/nebula/cli/NebulaCli.kt +++ b/nebula-cli/src/main/kotlin/com/orbitalhq/nebula/cli/NebulaCli.kt @@ -67,13 +67,12 @@ class Nebula : Callable { private var currentStackRunner: StackRunner? = null override fun call(): Int { + spec.commandLine().out.println("Nebula emitting container coordinates for $connectivity connectivity") val networkOrError = resolveNetwork() if (networkOrError.isFailure) { return spec.exitCodeOnExecutionException() } val network = networkOrError.getOrThrow() - spec.commandLine().out.println("Nebula using network name $networkName maps to ${network.id}") - spec.commandLine().out.println("Nebula emitting container coordinates for $connectivity connectivity") val nebulaConfig = NebulaConfig(networkName, network, connectivity) when { scriptFile != null -> return executeScript(nebulaConfig) @@ -88,16 +87,25 @@ class Nebula : Callable { /** * Resolves the docker network to attach child containers to. * - * In `network` connectivity mode Nebula is running inside a container - * alongside its consumers (eg. Orbital in docker-compose), so we attach - * children to *our own* network - this is the only reliable way to pick the - * right one when several `*_$networkName` networks exist on the host (eg. - * multiple compose projects). In `host` mode we fall back to looking up (or - * creating) a network by name. + * In `network` connectivity mode Nebula runs inside a container alongside + * its consumers (eg. Orbital in docker-compose), so we attach children to + * *our own* network - this is the only reliable way to pick the right one + * when several `*_$networkName` networks exist on the host (eg. multiple + * compose projects). + * + * In `host` mode consumers reach containers via host port-mapping, so the + * network identity is irrelevant - we always create an isolated network + * (enough for intra-stack DNS aliases to resolve) and avoid any docker + * network discovery that could fail. */ private fun resolveNetwork(): Result = when (connectivity) { ConsumerConnectivity.NETWORK -> resolveOwnContainerNetwork() - ConsumerConnectivity.HOST -> discoverActualNetworkName() + ConsumerConnectivity.HOST -> { + spec.commandLine().out.println( + "Nebula running in host connectivity mode - started containers will be placed on an isolated docker network and reached via mapped ports" + ) + Result.success(Network.newNetwork()) + } } /** @@ -106,6 +114,14 @@ class Nebula : Callable { * [networkName]. */ private fun resolveOwnContainerNetwork(): Result { + if (!isRunningInContainer()) { + return fail( + "Running with --connectivity=network, but Nebula does not appear to be running inside a container. " + + "This mode is for running alongside consumers on a shared docker network (eg. docker-compose). " + + "Use --connectivity=host (the default) when running on the host directly." + ) + } + val containerId = readOwnContainerId() ?: return fail( "Running with --connectivity=network, but Nebula's own container id could not be read from /etc/hostname. " + @@ -133,26 +149,6 @@ class Nebula : Callable { ) } - private fun discoverActualNetworkName():Result { - val dockerClient = DockerClientFactory.lazyClient() - val networks = dockerClient.listNetworksCmd().withNameFilter(networkName).exec() - return when (networks.size) { - 0 -> { - spec.commandLine().out.println("A network named $networkName does not exist - will create a temporary, isolated network") - Result.success(Network.newNetwork()) - } - 1 -> { - val network = networks.single() - return Result.success(ExistingDockerNetwork(network.name)) - } - else -> { - spec.commandLine().err.println("Multiple networks were found matching the provided name $networkName - provide a more specific name, or remove the other networks") - networks.forEach { spec.commandLine().err.println(it.name) } - Result.failure(IllegalArgumentException("Multiple networks were found")) - } - } - } - private fun fail(message: String): Result { spec.commandLine().err.println(message) return Result.failure(IllegalStateException(message)) @@ -168,6 +164,25 @@ class Nebula : Callable { .getOrNull() ?.takeIf { it.isNotBlank() } + /** + * Best-effort detection of whether Nebula is running inside a container. + * + * Docker writes `/.dockerenv` at the container root; podman uses + * `/run/.containerenv`. As a fallback we scan `/proc/1/cgroup` for a known + * container runtime - this is unreliable under cgroup v2, hence only a + * fallback. + */ + private fun isRunningInContainer(): Boolean { + if (File("/.dockerenv").exists() || File("/run/.containerenv").exists()) { + return true + } + return runCatching { + File("/proc/1/cgroup").readText().lineSequence().any { line -> + line.contains("docker") || line.contains("containerd") || line.contains("kubepods") + } + }.getOrDefault(false) + } + private fun executeScript(nebulaConfig: NebulaConfig): Int { val file = scriptFile ?: throw ParameterException(spec.commandLine(), "Script file is required") if (!file.exists() || !file.isFile || !file.canRead()) { diff --git a/nebula-runtime/${project.build.directory}/classes/META-INF/nebula-runtime.kotlin_module b/nebula-runtime/${project.build.directory}/classes/META-INF/nebula-runtime.kotlin_module new file mode 100644 index 0000000000000000000000000000000000000000..542785f5d087e3738ad447e8f7e8303e4791f18e GIT binary patch literal 94 zcmZQzU|?ooU|@n`AjQDI<-(<$oS&zI<8ndh6IlA2TOT_VKi2UZmfmh>)BV$fm$0L>a1b^rhX literal 0 HcmV?d00001 From a1d01fc0580930b19709111a40c2f087733da73e Mon Sep 17 00:00:00 2001 From: Marty Pitt Date: Tue, 23 Jun 2026 05:49:28 +0100 Subject: [PATCH 06/11] Only require --network to disambiguate multiple networks A container can be attached to several docker networks, so --network is a disambiguator, not a required exact name. selectAttachedNetwork now uses the single attached network when there is only one (even if it doesn't match the identifier), and only needs --network when the container is on multiple networks. Refs #62 Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/pages/cli.mdx | 14 ++++++---- .../com/orbitalhq/nebula/cli/NebulaCli.kt | 27 ++++++++++++------- .../nebula/cli/SelectAttachedNetworkTest.kt | 7 ++++- 3 files changed, 33 insertions(+), 15 deletions(-) diff --git a/docs/pages/cli.mdx b/docs/pages/cli.mdx index 6cf32f1..d4ca084 100644 --- a/docs/pages/cli.mdx +++ b/docs/pages/cli.mdx @@ -17,7 +17,7 @@ nebula --http=8099 | Option | Env var | Default | Description | |------------------|----------------------|------------------|-----------------------------------------------------------------------------| | `--http` | | | Start the HTTP server on the given port instead of running a script | -| `--network` | `NEBULA_NETWORK` | `nebula_network` | Identifies the docker network to attach started containers to. Only used in `network` mode (see below); in `host` mode an isolated network is always created | +| `--network` | `NEBULA_NETWORK` | `nebula_network` | Disambiguates which docker network to attach started containers to, when Nebula is attached to more than one. Only used in `network` mode (see below); in `host` mode an isolated network is always created | | `--connectivity` | `NEBULA_CONNECTIVITY`| `host` | How the host + port of each container is reported to consumers (see below) | | `-v`, `--verbose`| | `false` | Enable verbose output | @@ -34,10 +34,14 @@ reported, depending on where the *consumer* sits relative to the containers: In `network` mode consumers talk to the containers directly over the shared docker network, so no host port-mapping is involved. Nebula attaches the containers it starts to its **own** -network — it inspects the container it is running in and picks the attached network whose name -contains `--network` (default `nebula_network`). This works even when several compose projects -(`project-a_nebula_network`, `project-b_nebula_network`, …) run on the same host. If Nebula is -attached to more than one matching network, set `--network` to a more specific name. +network — it inspects the container it is running in to find which network(s) it is on. + +A container can be attached to more than one network, so when there are several, `--network` +(default `nebula_network`) selects which one to use — Nebula picks the attached network whose +name contains that value. This works even when several compose projects +(`project-a_nebula_network`, `project-b_nebula_network`, …) run on the same host, since each +Nebula only sees its own. If Nebula is on a single network, `--network` is not needed; if it +matches more than one, set `--network` to a more specific name. ```bash # Reporting in-network coordinates (e.g. running alongside Orbital in docker-compose) diff --git a/nebula-cli/src/main/kotlin/com/orbitalhq/nebula/cli/NebulaCli.kt b/nebula-cli/src/main/kotlin/com/orbitalhq/nebula/cli/NebulaCli.kt index fe62507..ab6578d 100644 --- a/nebula-cli/src/main/kotlin/com/orbitalhq/nebula/cli/NebulaCli.kt +++ b/nebula-cli/src/main/kotlin/com/orbitalhq/nebula/cli/NebulaCli.kt @@ -299,19 +299,28 @@ fun main(args: Array): Unit = exitProcess(CommandLine(Nebula()).setCaseInsensitiveEnumValuesAllowed(true).execute(*args)) /** - * From the set of networks a container is attached to, selects the single one - * whose name contains [identifier]. Returns a failure (rather than guessing) - * when zero or more than one network matches, so callers can surface a clear - * diagnostic. + * From the set of networks a container is attached to, selects the one its + * child containers should join. + * + * A container can be attached to several networks at once, so [identifier] + * (the `--network` value) is used to disambiguate. It is only *needed* when + * there is more than one network: + * + * - exactly one network matches [identifier] -> use it; + * - nothing matches but the container is on a single network -> use it + * (the choice is unambiguous, so the filter is irrelevant); + * - otherwise (several match, or several attached and none match) -> fail, + * rather than guess, so the caller can ask for a more specific `--network`. */ fun selectAttachedNetwork(attachedNetworks: Set, identifier: String): Result { val matches = attachedNetworks.filter { it.contains(identifier) } - return when (matches.size) { - 1 -> Result.success(matches.single()) - 0 -> Result.failure( + return when { + matches.size == 1 -> Result.success(matches.single()) + matches.isEmpty() && attachedNetworks.size == 1 -> Result.success(attachedNetworks.single()) + matches.isEmpty() -> Result.failure( IllegalStateException( - "Running with --connectivity=network, but none of the networks Nebula is attached to ($attachedNetworks) " + - "contain '$identifier'. Set --network (or NEBULA_NETWORK) to match your network name." + "Running with --connectivity=network, but Nebula is attached to multiple networks ($attachedNetworks), " + + "none of which contain '$identifier'. Set --network (or NEBULA_NETWORK) to match your network name." ) ) else -> Result.failure( diff --git a/nebula-cli/src/test/kotlin/com/orbitalhq/nebula/cli/SelectAttachedNetworkTest.kt b/nebula-cli/src/test/kotlin/com/orbitalhq/nebula/cli/SelectAttachedNetworkTest.kt index 111d033..413907f 100644 --- a/nebula-cli/src/test/kotlin/com/orbitalhq/nebula/cli/SelectAttachedNetworkTest.kt +++ b/nebula-cli/src/test/kotlin/com/orbitalhq/nebula/cli/SelectAttachedNetworkTest.kt @@ -15,7 +15,12 @@ class SelectAttachedNetworkTest : DescribeSpec({ .getOrNull() shouldBe "project-b_nebula_network" } - it("fails when no attached network matches") { + it("uses the only attached network even when it does not match the identifier") { + selectAttachedNetwork(setOf("some-custom-network"), "nebula_network") + .getOrNull() shouldBe "some-custom-network" + } + + it("fails when attached to several networks and none match") { selectAttachedNetwork(setOf("bridge", "host"), "nebula_network") .isFailure shouldBe true } From ee990a06e8bf9583a02d294e64ade684de5cfdb0 Mon Sep 17 00:00:00 2001 From: Marty Pitt Date: Tue, 23 Jun 2026 05:51:27 +0100 Subject: [PATCH 07/11] Log the name of the isolated network created in host mode When host mode creates an isolated docker network, log its name so it can be identified (eg. docker network inspect). Uses NetworkImpl.getName(), which unlike getId() doesn't force the network to be created early. Refs #62 Co-Authored-By: Claude Opus 4.8 (1M context) --- .../src/main/kotlin/com/orbitalhq/nebula/cli/NebulaCli.kt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/nebula-cli/src/main/kotlin/com/orbitalhq/nebula/cli/NebulaCli.kt b/nebula-cli/src/main/kotlin/com/orbitalhq/nebula/cli/NebulaCli.kt index ab6578d..39a9fe8 100644 --- a/nebula-cli/src/main/kotlin/com/orbitalhq/nebula/cli/NebulaCli.kt +++ b/nebula-cli/src/main/kotlin/com/orbitalhq/nebula/cli/NebulaCli.kt @@ -101,10 +101,14 @@ class Nebula : Callable { private fun resolveNetwork(): Result = when (connectivity) { ConsumerConnectivity.NETWORK -> resolveOwnContainerNetwork() ConsumerConnectivity.HOST -> { + val network = Network.newNetwork() + // getName() is the docker network name testcontainers will create, and + // (unlike getId()) doesn't force the network to be created just to log it. + val networkName = (network as? Network.NetworkImpl)?.name ?: network.id spec.commandLine().out.println( - "Nebula running in host connectivity mode - started containers will be placed on an isolated docker network and reached via mapped ports" + "Nebula running in host connectivity mode - creating an isolated docker network '$networkName' for started containers (reached via mapped ports)" ) - Result.success(Network.newNetwork()) + Result.success(network) } } From 7a010e667658832d220ccd30383b9479069dbfe4 Mon Sep 17 00:00:00 2001 From: Marty Pitt Date: Tue, 23 Jun 2026 05:57:44 +0100 Subject: [PATCH 08/11] Give isolated host-mode networks a readable name Name the isolated network nebula-- (eg. nebula-focused-turing) instead of testcontainers' default UUID, so it's identifiable in `docker network ls`. Adds a Names util (Moby random-name generator, ported from vyne) and sets the docker network name via a createNetworkCmdModifier, since the testcontainers Network builder has no name() setter. Refs #62 Co-Authored-By: Claude Opus 4.8 (1M context) --- .../com/orbitalhq/nebula/cli/NebulaCli.kt | 13 +- .../com/orbitalhq/nebula/utils/Names.kt | 558 ++++++++++++++++++ 2 files changed, 566 insertions(+), 5 deletions(-) create mode 100644 nebula-dsl/src/main/kotlin/com/orbitalhq/nebula/utils/Names.kt diff --git a/nebula-cli/src/main/kotlin/com/orbitalhq/nebula/cli/NebulaCli.kt b/nebula-cli/src/main/kotlin/com/orbitalhq/nebula/cli/NebulaCli.kt index 39a9fe8..b48d235 100644 --- a/nebula-cli/src/main/kotlin/com/orbitalhq/nebula/cli/NebulaCli.kt +++ b/nebula-cli/src/main/kotlin/com/orbitalhq/nebula/cli/NebulaCli.kt @@ -9,6 +9,7 @@ import com.orbitalhq.nebula.StackRunner import com.orbitalhq.nebula.runtime.NebulaCompilationException import com.orbitalhq.nebula.runtime.NebulaScriptExecutor import com.orbitalhq.nebula.runtime.server.NebulaServer +import com.orbitalhq.nebula.utils.Names import io.github.oshai.kotlinlogging.KotlinLogging import org.junit.runner.Description import org.junit.runners.model.Statement @@ -101,12 +102,14 @@ class Nebula : Callable { private fun resolveNetwork(): Result = when (connectivity) { ConsumerConnectivity.NETWORK -> resolveOwnContainerNetwork() ConsumerConnectivity.HOST -> { - val network = Network.newNetwork() - // getName() is the docker network name testcontainers will create, and - // (unlike getId()) doesn't force the network to be created just to log it. - val networkName = (network as? Network.NetworkImpl)?.name ?: network.id + // Give the isolated network a readable, identifiable name (eg. + // nebula-focused-turing) rather than testcontainers' default UUID. + val isolatedNetworkName = "nebula-${Names.randomName()}" + val network = Network.builder() + .createNetworkCmdModifier { cmd -> cmd.withName(isolatedNetworkName) } + .build() spec.commandLine().out.println( - "Nebula running in host connectivity mode - creating an isolated docker network '$networkName' for started containers (reached via mapped ports)" + "Nebula running in host connectivity mode - creating an isolated docker network '$isolatedNetworkName' for started containers (reached via mapped ports)" ) Result.success(network) } diff --git a/nebula-dsl/src/main/kotlin/com/orbitalhq/nebula/utils/Names.kt b/nebula-dsl/src/main/kotlin/com/orbitalhq/nebula/utils/Names.kt new file mode 100644 index 0000000..e855b29 --- /dev/null +++ b/nebula-dsl/src/main/kotlin/com/orbitalhq/nebula/utils/Names.kt @@ -0,0 +1,558 @@ +package com.orbitalhq.nebula.utils + +/* + * Original work Copyright 2019 The Moby Project. + * Modified work Copyright (c) 2008-2021, Hazelcast, Inc. All Rights Reserved. + * + * 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 + * + * http://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. + */ + + + +/** + * Java port of the Moby Project random name generator (https://github.com/moby/moby). + */ +object Names { + private val LEFT = listOf( + "admiring", "adoring", "affectionate", "agitated", "amazing", "angry", "awesome", + "blissful", "boring", "brave", "charming", "clever", "cocky", "cool", "compassionate", + "competent", "condescending", "confident", "cranky", "crazy", "dazzling", "determined", + "distracted", "dreamy", "eager", "ecstatic", "elastic", "elated", "elegant", "eloquent", + "epic", "fervent", "festive", "flamboyant", "focused", "friendly", "frosty", "gallant", + "gifted", "goofy", "gracious", "happy", "hardcore", "heuristic", "hopeful", "hungry", + "infallible", "inspiring", "jolly", "jovial", "keen", "kind", "laughing", "loving", + "lucid", "magical", "mystifying", "modest", "musing", "naughty", "nervous", "nifty", + "nostalgic", "objective", "optimistic", "peaceful", "pedantic", "pensive", "practical", + "priceless", "quirky", "quizzical", "recursing", "relaxed", "reverent", "romantic", + "sad", "serene", "sharp", "silly", "sleepy", "stoic", "stupefied", "suspicious", + "sweet", "tender", "thirsty", "trusting", "unruffled", "upbeat", "vibrant", "vigilant", + "vigorous", "wizardly", "wonderful", "xenodochial", "youthful", "zealous", "zen" + ).shuffled() + + // Docker, starting from 0.7.x, generates names from notable scientists and hackers. + // Please, for any amazing man that you add to the list, consider adding an equally amazing woman to it, and vice versa. + private val RIGHT = listOf( // Muhammad ibn Jābir al-Ḥarrānī al-Battānī was a founding father of astronomy. + // https://en.wikipedia.org/wiki/Mu%E1%B8%A5ammad_ibn_J%C4%81bir_al-%E1%B8%A4arr%C4%81n%C4%AB_al-Batt%C4%81n%C4%AB + "albattani", // Frances E. Allen, became the first female IBM Fellow in 1989. In 2006, she became the first female recipient of + // the ACM's Turing Award. https://en.wikipedia.org/wiki/Frances_E._Allen + "allen", // June Almeida - Scottish virologist who took the first pictures of the rubella virus + // - https://en.wikipedia.org/wiki/June_Almeida + "almeida", // Kathleen Antonelli, American computer programmer and one of the six original programmers of the ENIAC + // - https://en.wikipedia.org/wiki/Kathleen_Antonelli + "antonelli", // Maria Gaetana Agnesi - Italian mathematician, philosopher, theologian and humanitarian. She was the first woman + // to write a mathematics handbook and the first woman appointed as a Mathematics Professor at a University. + // https://en.wikipedia.org/wiki/Maria_Gaetana_Agnesi + "agnesi", // Archimedes was a physicist, engineer and mathematician who invented too many things to list them here. + // https://en.wikipedia.org/wiki/Archimedes + "archimedes", // Maria Ardinghelli - Italian translator, mathematician and physicist + // - https://en.wikipedia.org/wiki/Maria_Ardinghelli + "ardinghelli", // Aryabhata - Ancient Indian mathematician-astronomer during 476-550 CE https://en.wikipedia.org/wiki/Aryabhata + "aryabhata", // Wanda Austin - Wanda Austin is the President and CEO of The Aerospace Corporation, a leading architect for the + // US security space programs. https://en.wikipedia.org/wiki/Wanda_Austin + "austin", // Charles Babbage invented the concept of a programmable computer. https://en.wikipedia.org/wiki/Charles_Babbage. + "babbage", // Stefan Banach - Polish mathematician, was one of the founders of modern functional analysis. + // https://en.wikipedia.org/wiki/Stefan_Banach + "banach", // Buckaroo Banzai and his mentor Dr. Hikita perfectd the "oscillation overthruster", a device that allows one + // to pass through solid matter. + // - https://en.wikipedia.org/wiki/The_Adventures_of_Buckaroo_Banzai_Across_the_8th_Dimension + "banzai", // John Bardeen co-invented the transistor - https://en.wikipedia.org/wiki/John_Bardeen + "bardeen", // Jean Bartik, born Betty Jean Jennings, was one of the original programmers for the ENIAC computer. + // https://en.wikipedia.org/wiki/Jean_Bartik + "bartik", // Laura Bassi, the world's first female professor https://en.wikipedia.org/wiki/Laura_Bassi + "bassi", // Hugh Beaver, British engineer, founder of the Guinness Book of World Records + // https://en.wikipedia.org/wiki/Hugh_Beaver + "beaver", // Alexander Graham Bell - an eminent Scottish-born scientist, inventor, engineer and innovator who is credited with + // inventing the first practical telephone - https://en.wikipedia.org/wiki/Alexander_Graham_Bell + "bell", // Karl Friedrich Benz - a German automobile engineer. Inventor of the first practical motorcar. + // https://en.wikipedia.org/wiki/Karl_Benz + "benz", // Homi J Bhabha - was an Indian nuclear physicist, founding director, and professor of physics at the Tata + // Institute of Fundamental Research. Colloquially known as "father of Indian nuclear programme" + // - https://en.wikipedia.org/wiki/Homi_J._Bhabha + "bhabha", // Bhaskara II - Ancient Indian mathematician-astronomer whose work on calculus predates Newton and Leibniz + // by over half a millennium - https://en.wikipedia.org/wiki/Bh%C4%81skara_II#Calculus + "bhaskara", // Elizabeth Helen Blackburn - Australian-American Nobel laureate; best known for co-discovering telomerase. + // https://en.wikipedia.org/wiki/Elizabeth_Blackburn + "blackburn", // Elizabeth Blackwell - American doctor and first American woman to receive a medical degree + // - https://en.wikipedia.org/wiki/Elizabeth_Blackwell + "blackwell", // Niels Bohr is the father of quantum theory. https://en.wikipedia.org/wiki/Niels_Bohr. + "bohr", // Kathleen Booth, she's credited with writing the first assembly language. + // https://en.wikipedia.org/wiki/Kathleen_Booth + "booth", // Anita Borg - Anita Borg was the founding director of the Institute for Women and Technology (IWT). + // https://en.wikipedia.org/wiki/Anita_Borg + "borg", // Satyendra Nath Bose - He provided the foundation for Bose–Einstein statistics and the theory of the + // Bose–Einstein condensate. - https://en.wikipedia.org/wiki/Satyendra_Nath_Bose + "bose", // Evelyn Boyd Granville - She was one of the first African-American woman to receive a Ph.D. in mathematics; she + // earned it in 1949 from Yale University. https://en.wikipedia.org/wiki/Evelyn_Boyd_Granville + "boyd", // Brahmagupta - Ancient Indian mathematician during 598-670 CE who gave rules to compute with zero + // - https://en.wikipedia.org/wiki/Brahmagupta#Zero + "brahmagupta", // Walter Houser Brattain co-invented the transistor - https://en.wikipedia.org/wiki/Walter_Houser_Brattain + "brattain", // Emmett Brown invented time travel. https://en.wikipedia.org/wiki/Emmett_Brown (thanks Brian Goff) + "brown", // Dame Susan Jocelyn Bell Burnell - discoverer of pulsars while a graduate student, "one of the most significant + // scientific achievements of the 20th Century". - https://en.wikipedia.org/wiki/Jocelyn_Bell_Burnell + "burnell", // Linda Brown Buck - American biologist and Nobel laureate best known for her genetic and molecular analyses of + // the mechanisms of smell. https://en.wikipedia.org/wiki/Linda_B._Buck + "buck", // Annie Jump Cannon - pioneering female astronomer who classified hundreds of thousands of stars and created the + // system we use to understand stars today. https://en.wikipedia.org/wiki/Annie_Jump_Cannon + "cannon", // Rachel Carson - American marine biologist and conservationist, her book Silent Spring and other writings are + // credited with advancing the global environmental movement. https://en.wikipedia.org/wiki/Rachel_Carson + "carson", // Dame Mary Lucy Cartwright - British mathematician who was one of the first to study what is now known as chaos + // theory. Also known for Cartwright's theorem which finds applications in signal processing. + // https://en.wikipedia.org/wiki/Mary_Cartwright + "cartwright", // Subrahmanyan Chandrasekhar - Astrophysicist known for his mathematical theory on different stages and evolution + // in structures of the stars. He has won nobel prize for physics + // - https://en.wikipedia.org/wiki/Subrahmanyan_Chandrasekhar + "chandrasekhar", // Sergey Alexeyevich Chaplygin was a Russian and Soviet physicist, mathematician, and mechanical engineer. + // He is known for mathematical formulas such as Chaplygin's equation and for a hypothetical substance + // in cosmology called Chaplygin gas, named after him. + // https://en.wikipedia.org/wiki/Sergey_Chaplygin + "chaplygin", // Émilie du Châtelet - French natural philosopher, mathematician, physicist, and author during the early 1730s, + // known for her translation of and commentary on Isaac Newton's book Principia containing basic laws of physics. + // https://en.wikipedia.org/wiki/%C3%89milie_du_Ch%C3%A2telet + "chatelet", // Asima Chatterjee was an Indian organic chemist noted for her research on vinca alkaloids, development of drugs + // for treatment of epilepsy and malaria - https://en.wikipedia.org/wiki/Asima_Chatterjee + "chatterjee", // Pafnuty Chebyshev - Russian mathematician. He is known fo his works on probability, statistics, mechanics, + // analytical geometry and number theory https://en.wikipedia.org/wiki/Pafnuty_Chebyshev + "chebyshev", // Clifford Christopher Cocks - British mathematician and cryptographer employed by the GCHQ. Invented in 1973 + // an equivalent of what is now known as the RSA public-key cryptosystem (Rivest, Shamir and Adleman first + // publicly described RSA in 1978). https://en.wikipedia.org/wiki/Clifford_Cocks + "cocks", // Bram Cohen - American computer programmer and author of the BitTorrent peer-to-peer protocol. + // https://en.wikipedia.org/wiki/Bram_Cohen + "cohen", // David Lee Chaum - American computer scientist and cryptographer. Known for his seminal contributions in the + // field of anonymous communication. https://en.wikipedia.org/wiki/David_Chaum + "chaum", // Joan Clarke - Bletchley Park code breaker during the Second World War who pioneered techniques that remained + // top secret for decades. Also an accomplished numismatist https://en.wikipedia.org/wiki/Joan_Clarke + "clarke", // Jane Colden - American botanist widely considered the first female American botanist + // - https://en.wikipedia.org/wiki/Jane_Colden + "colden", // Gerty Theresa Cori - American biochemist who became the third woman—and first American woman—to win a Nobel + // Prize in science, and the first woman to be awarded the Nobel Prize in Physiology or Medicine. Cori was born + // in Prague. https://en.wikipedia.org/wiki/Gerty_Cori + "cori", // Seymour Roger Cray was an American electrical engineer and supercomputer architect who designed a series of + // computers that were the fastest in the world for decades. https://en.wikipedia.org/wiki/Seymour_Cray + "cray", // This entry reflects a husband and wife team who worked together: + // Joan Curran was a Welsh scientist who developed radar and invented chaff, a radar countermeasure. + // https://en.wikipedia.org/wiki/Joan_Curran + // Samuel Curran was an Irish physicist who worked alongside his wife during WWII and invented the proximity fuse. + // https://en.wikipedia.org/wiki/Samuel_Curran + "curran", // Marie Curie discovered radioactivity. https://en.wikipedia.org/wiki/Marie_Curie. + "curie", // Charles Darwin established the principles of natural evolution. https://en.wikipedia.org/wiki/Charles_Darwin. + "darwin", // Leonardo Da Vinci invented too many things to list here. https://en.wikipedia.org/wiki/Leonardo_da_Vinci. + "davinci", // A. K. (Alexander Keewatin) Dewdney, Canadian mathematician, computer scientist, author and filmmaker. Contributor + // to Scientific American's "Computer Recreations" from 1984 to 1991. Author of Core War (program), The Planiverse, + // The Armchair Universe, The Magic Machine, The New Turing Omnibus, and more. + // https://en.wikipedia.org/wiki/Alexander_Dewdney + "dewdney", // Satish Dhawan - Indian mathematician and aerospace engineer, known for leading the successful and indigenous + // development of the Indian space programme. https://en.wikipedia.org/wiki/Satish_Dhawan + "dhawan", // Bailey Whitfield Diffie - American cryptographer and one of the pioneers of public-key cryptography. + // https://en.wikipedia.org/wiki/Whitfield_Diffie + "diffie", // Edsger Wybe Dijkstra was a Dutch computer scientist and mathematical scientist. + // https://en.wikipedia.org/wiki/Edsger_W._Dijkstra. + "dijkstra", // Paul Adrien Maurice Dirac - English theoretical physicist who made fundamental contributions to the early + // development of both quantum mechanics and quantum electrodynamics. https://en.wikipedia.org/wiki/Paul_Dirac + "dirac", // Agnes Meyer Driscoll - American cryptanalyst during World Wars I and II who successfully cryptanalysed a + // number of Japanese ciphers. She was also the co-developer of one of the cipher machines of the US Navy, + // the CM. https://en.wikipedia.org/wiki/Agnes_Meyer_Driscoll + "driscoll", // Donna Dubinsky - played an integral role in the development of personal digital assistants (PDAs) serving + // as CEO of Palm, Inc. and co-founding Handspring. https://en.wikipedia.org/wiki/Donna_Dubinsky + "dubinsky", // Annie Easley - She was a leading member of the team which developed software for the Centaur rocket stage + // and one of the first African-Americans in her field. https://en.wikipedia.org/wiki/Annie_Easley + "easley", // Thomas Alva Edison, prolific inventor https://en.wikipedia.org/wiki/Thomas_Edison + "edison", // Albert Einstein invented the general theory of relativity. https://en.wikipedia.org/wiki/Albert_Einstein + "einstein", // Alexandra Asanovna Elbakyan is a Kazakhstani graduate student, computer programmer, internet pirate in + // hiding, and the creator of the site Sci-Hub. Nature has listed her in 2016 in the top ten people + // that mattered in science, and Ars Technica has compared her to Aaron Swartz. - + // https://en.wikipedia.org/wiki/Alexandra_Elbakyan + "elbakyan", // Taher A. ElGamal - Egyptian cryptographer best known for the ElGamal discrete log cryptosystem and the + // ElGamal digital signature scheme. https://en.wikipedia.org/wiki/Taher_Elgamal + "elgamal", // Gertrude Elion - American biochemist, pharmacologist and the 1988 recipient of the Nobel Prize in Medicine + // - https://en.wikipedia.org/wiki/Gertrude_Elion + "elion", // James Henry Ellis - British engineer and cryptographer employed by the GCHQ. Best known for conceiving + // for the first time, the idea of public-key cryptography. https://en.wikipedia.org/wiki/James_H._Ellis + "ellis", // Douglas Engelbart gave the mother of all demos: https://en.wikipedia.org/wiki/Douglas_Engelbart + "engelbart", // Euclid invented geometry. https://en.wikipedia.org/wiki/Euclid + "euclid", // Leonhard Euler invented large parts of modern mathematics. https://de.wikipedia.org/wiki/Leonhard_Euler + "euler", // Michael Faraday - British scientist who contributed to the study of electromagnetism and electrochemistry. + // https://en.wikipedia.org/wiki/Michael_Faraday + "faraday", // Horst Feistel - German-born American cryptographer who was one of the earliest non-government researchers to + // study the design and theory of block ciphers. Co-developer of DES and Lucifer. Feistel networks, a symmetric + // structure used in the construction of block ciphers are named after him. + // https://en.wikipedia.org/wiki/Horst_Feistel + "feistel", // Pierre de Fermat pioneered several aspects of modern mathematics. https://en.wikipedia.org/wiki/Pierre_de_Fermat + "fermat", // Enrico Fermi invented the first nuclear reactor. https://en.wikipedia.org/wiki/Enrico_Fermi. + "fermi", // Richard Feynman was a key contributor to quantum mechanics and particle physics. + // https://en.wikipedia.org/wiki/Richard_Feynman + "feynman", // Benjamin Franklin is famous for his experiments in electricity and the invention of the lightning rod. + "franklin", // Yuri Alekseyevich Gagarin - Soviet pilot and cosmonaut, best known as the first human to journey into + // outer space. https://en.wikipedia.org/wiki/Yuri_Gagarin + "gagarin", // Galileo was a founding father of modern astronomy, and faced politics and obscurantism to establish scientific + // truth. https://en.wikipedia.org/wiki/Galileo_Galilei + "galileo", // Évariste Galois - French mathematician whose work laid the foundations of Galois theory and group theory, two + // major branches of abstract algebra, and the subfield of Galois connections, all while still in his late teens. + // https://en.wikipedia.org/wiki/%C3%89variste_Galois + "galois", // Kadambini Ganguly - Indian physician, known for being the first South Asian female physician, trained in western + // medicine, to graduate in South Asia. https://en.wikipedia.org/wiki/Kadambini_Ganguly + "ganguly", // William Henry "Bill" Gates III is an American business magnate, philanthropist, investor, computer programmer, + // and inventor. https://en.wikipedia.org/wiki/Bill_Gates + "gates", // Johann Carl Friedrich Gauss - German mathematician who made significant contributions to many fields, including + // number theory, algebra, statistics, analysis, differential geometry, geodesy, geophysics, mechanics, + // electrostatics, magnetic fields, astronomy, matrix theory, and optics. https://en.wikipedia + // .org/wiki/Carl_Friedrich_Gauss + "gauss", // Marie-Sophie Germain - French mathematician, physicist and philosopher. Known for her work on elasticity theory, + // number theory and philosophy. https://en.wikipedia.org/wiki/Sophie_Germain + "germain", // Adele Goldberg, was one of the designers and developers of the Smalltalk language. https://en.wikipedia + // .org/wiki/Adele_Goldberg_(computer_scientist) + "goldberg", // Adele Goldstine, born Adele Katz, wrote the complete technical description for the first electronic digital + // computer, ENIAC. https://en.wikipedia.org/wiki/Adele_Goldstine + "goldstine", // Shafi Goldwasser is a computer scientist known for creating theoretical foundations of modern cryptography. + // Winner of 2012 ACM Turing Award. https://en.wikipedia.org/wiki/Shafi_Goldwasser + "goldwasser", // James Golick, all around gangster. + "golick", // Jane Goodall - British primatologist, ethologist, and anthropologist who is considered to be the world's + // foremost expert on chimpanzees - https://en.wikipedia.org/wiki/Jane_Goodall + "goodall", // Carolyn Widney Greider - American molecular biologist and joint winner of the 2009 Nobel Prize for Physiology or + // Medicine for the discovery of telomerase. https://en.wikipedia.org/wiki/Carol_W._Greider + "greider", // Alexander Grothendieck - German-born French mathematician who became a leading figure in the creation of modern + // algebraic geometry. https://en.wikipedia.org/wiki/Alexander_Grothendieck + "grothendieck", // Lois Haibt - American computer scientist, part of the team at IBM that developed FORTRAN - https://en.wikipedia + // .org/wiki/Lois_Haibt + "haibt", // Margaret Hamilton - Director of the Software Engineering Division of the MIT Instrumentation Laboratory, which + // developed on-board flight software for the Apollo space program. https://en.wikipedia + // .org/wiki/Margaret_Hamilton_(scientist) + "hamilton", // Caroline Harriet Haslett - English electrical engineer, electricity industry administrator and champion of + // women's rights. Co-author of British Standard 1363 that specifies AC power plugs and sockets used across the + // United Kingdom (which is widely considered as one of the safest designs). https://en.wikipedia + // .org/wiki/Caroline_Haslett + "haslett", // Stephen Hawking pioneered the field of cosmology by combining general relativity and quantum mechanics. + // https://en.wikipedia.org/wiki/Stephen_Hawking + "hawking", // Martin Edward Hellman - American cryptologist, best known for his invention of public-key cryptography in + // co-operation with Whitfield Diffie and Ralph Merkle. https://en.wikipedia.org/wiki/Martin_Hellman + "hellman", // Werner Heisenberg was a founding father of quantum mechanics. https://en.wikipedia.org/wiki/Werner_Heisenberg + "heisenberg", // Grete Hermann was a German philosopher noted for her philosophical work on the foundations of quantum mechanics. + // https://en.wikipedia.org/wiki/Grete_Hermann + "hermann", // Caroline Lucretia Herschel - German astronomer and discoverer of several comets. https://en.wikipedia + // .org/wiki/Caroline_Herschel + "herschel", // Heinrich Rudolf Hertz - German physicist who first conclusively proved the existence of the electromagnetic + // waves. https://en.wikipedia.org/wiki/Heinrich_Hertz + "hertz", // Jaroslav Heyrovský was the inventor of the polarographic method, father of the electroanalytical method, and + // recipient of the Nobel Prize in 1959. His main field of work was polarography. https://en.wikipedia + // .org/wiki/Jaroslav_Heyrovsk%C3%BD + "heyrovsky", // Dorothy Hodgkin was a British biochemist, credited with the development of protein crystallography. She was + // awarded the Nobel Prize in Chemistry in 1964. https://en.wikipedia.org/wiki/Dorothy_Hodgkin + "hodgkin", // Douglas R. Hofstadter is an American professor of cognitive science and author of the Pulitzer Prize and + // American Book Award-winning work Goedel, Escher, Bach: An Eternal Golden Braid in 1979. A mind-bending work + // which coined Hofstadter's Law: "It always takes longer than you expect, even when you take into account + // Hofstadter's Law." https://en.wikipedia.org/wiki/Douglas_Hofstadter + "hofstadter", // Erna Schneider Hoover revolutionized modern communication by inventing a computerized telephone switching method + // . https://en.wikipedia.org/wiki/Erna_Schneider_Hoover + "hoover", // Grace Hopper developed the first compiler for a computer programming language and is credited with popularizing + // the term "debugging" for fixing computer glitches. https://en.wikipedia.org/wiki/Grace_Hopper + "hopper", // Frances Hugle, she was an American scientist, engineer, and inventor who contributed to the understanding of + // semiconductors, integrated circuitry, and the unique electrical principles of microscopic materials. https://en + // .wikipedia.org/wiki/Frances_Hugle + "hugle", // Hypatia - Greek Alexandrine Neoplatonist philosopher in Egypt who was one of the earliest mothers of mathematics + // - https://en.wikipedia.org/wiki/Hypatia + "hypatia", // Teruko Ishizaka - Japanese scientist and immunologist who co-discovered the antibody class Immunoglobulin E. + // https://en.wikipedia.org/wiki/Teruko_Ishizaka + "ishizaka", // Mary Jackson, American mathematician and aerospace engineer who earned the highest title within NASA's + // engineering department - https://en.wikipedia.org/wiki/Mary_Jackson_(engineer) + "jackson", // Yeong-Sil Jang was a Korean scientist and astronomer during the Joseon Dynasty; he invented the first metal + // printing press and water gauge. https://en.wikipedia.org/wiki/Jang_Yeong-sil + "jang", // Betty Jennings - one of the original programmers of the ENIAC. https://en.wikipedia.org/wiki/ENIAC - https://en + // .wikipedia.org/wiki/Jean_Bartik + "jennings", // Mary Lou Jepsen, was the founder and chief technology officer of One Laptop Per Child (OLPC), and the founder of + // Pixel Qi. https://en.wikipedia.org/wiki/Mary_Lou_Jepsen + "jepsen", // Katherine Coleman Goble Johnson - American physicist and mathematician contributed to the NASA. https://en + // .wikipedia.org/wiki/Katherine_Johnson + "johnson", // Irène Joliot-Curie - French scientist who was awarded the Nobel Prize for Chemistry in 1935. Daughter of Marie + // and Pierre Curie. https://en.wikipedia.org/wiki/Ir%C3%A8ne_Joliot-Curie + "joliot", // Karen Spärck Jones came up with the concept of inverse document frequency, which is used in most search engines + // today. https://en.wikipedia.org/wiki/Karen_Sp%C3%A4rck_Jones + "jones", // A. P. J. Abdul Kalam - is an Indian scientist aka Missile Man of India for his work on the development of + // ballistic missile and launch vehicle technology - https://en.wikipedia.org/wiki/A._P._J._Abdul_Kalam + "kalam", // Sergey Petrovich Kapitsa (14 February 1928 – 14 August 2012) was a Russian physicist and demographer. + // He was best known as host of the popular and long-running Russian scientific TV show, Evident, but Incredible. + // His father was the Nobel laureate Soviet-era physicist Pyotr Kapitsa, and his brother was the geographer + // and Antarctic explorer Andrey Kapitsa. - https://en.wikipedia.org/wiki/Sergey_Kapitsa + "kapitsa", // Susan Kare, created the icons and many of the interface elements for the original Apple Macintosh in the 1980s, + // and was an original employee of NeXT, working as the Creative Director. https://en.wikipedia.org/wiki/Susan_Kare + "kare", // Mstislav Keldysh - a Soviet scientist in the field of mathematics and mechanics, academician of the USSR Academy + // of Sciences (1946), President of the USSR Academy of Sciences (1961–1975), three times Hero of Socialist Labor + // (1956, 1961, 1971), fellow of the Royal Society of Edinburgh (1968). https://en.wikipedia.org/wiki/Mstislav_Keldysh + "keldysh", // Mary Kenneth Keller, Sister Mary Kenneth Keller became the first American woman to earn a PhD in Computer + // Science in 1965. https://en.wikipedia.org/wiki/Mary_Kenneth_Keller + "keller", // Johannes Kepler, German astronomer known for his three laws of planetary motion - https://en.wikipedia + // .org/wiki/Johannes_Kepler + "kepler", // Omar Khayyam - Persian mathematician, astronomer and poet. Known for his work on the classification and solution + // of cubic equations, for his contribution to the understanding of Euclid's fifth postulate and for computing the + // length of a year very accurately. https://en.wikipedia.org/wiki/Omar_Khayyam + "khayyam", // Har Gobind Khorana - Indian-American biochemist who shared the 1968 Nobel Prize for Physiology - https://en + // .wikipedia.org/wiki/Har_Gobind_Khorana + "khorana", // Jack Kilby invented silicone integrated circuits and gave Silicon Valley its name. - https://en.wikipedia + // .org/wiki/Jack_Kilby + "kilby", // Maria Kirch - German astronomer and first woman to discover a comet - https://en.wikipedia + // .org/wiki/Maria_Margarethe_Kirch + "kirch", // Donald Knuth - American computer scientist, author of "The Art of Computer Programming" and creator of the TeX + // typesetting system. https://en.wikipedia.org/wiki/Donald_Knuth + "knuth", // Sophie Kowalevski - Russian mathematician responsible for important original contributions to analysis, + // differential equations and mechanics - https://en.wikipedia.org/wiki/Sofia_Kovalevskaya + "kowalevski", // Marie-Jeanne de Lalande - French astronomer, mathematician and cataloguer of stars - https://en.wikipedia + // .org/wiki/Marie-Jeanne_de_Lalande + "lalande", // Hedy Lamarr - Actress and inventor. The principles of her work are now incorporated into modern Wi-Fi, CDMA and + // Bluetooth technology. https://en.wikipedia.org/wiki/Hedy_Lamarr + "lamarr", // Leslie B. Lamport - American computer scientist. Lamport is best known for his seminal work in distributed + // systems and was the winner of the 2013 Turing Award. https://en.wikipedia.org/wiki/Leslie_Lamport + "lamport", // Mary Leakey - British paleoanthropologist who discovered the first fossilized Proconsul skull - https://en + // .wikipedia.org/wiki/Mary_Leakey + "leakey", // Henrietta Swan Leavitt - she was an American astronomer who discovered the relation between the luminosity and + // the period of Cepheid variable stars. https://en.wikipedia.org/wiki/Henrietta_Swan_Leavitt + "leavitt", // Esther Miriam Zimmer Lederberg - American microbiologist and a pioneer of bacterial genetics. https://en + // .wikipedia.org/wiki/Esther_Lederberg + "lederberg", // Inge Lehmann - Danish seismologist and geophysicist. Known for discovering in 1936 that the Earth has a solid + // inner core inside a molten outer core. https://en.wikipedia.org/wiki/Inge_Lehmann + "lehmann", // Daniel Lewin - Mathematician, Akamai co-founder, soldier, 9/11 victim-- Developed optimization techniques for + // routing traffic on the internet. Died attempting to stop the 9-11 hijackers. https://en.wikipedia + // .org/wiki/Daniel_Lewin + "lewin", // Ruth Lichterman - one of the original programmers of the ENIAC. https://en.wikipedia.org/wiki/ENIAC - https://en + // .wikipedia.org/wiki/Ruth_Teitelbaum + "lichterman", // Barbara Liskov - co-developed the Liskov substitution principle. Liskov was also the winner of the Turing Prize + // in 2008. - https://en.wikipedia.org/wiki/Barbara_Liskov + "liskov", // Ada Lovelace invented the first algorithm. https://en.wikipedia.org/wiki/Ada_Lovelace (thanks James Turnbull) + "lovelace", // Auguste and Louis Lumière - the first filmmakers in history - https://en.wikipedia + // .org/wiki/Auguste_and_Louis_Lumi%C3%A8re + "lumiere", // Mahavira - Ancient Indian mathematician during 9th century AD who discovered basic algebraic identities - + // https://en.wikipedia.org/wiki/Mah%C4%81v%C4%ABra_(mathematician) + "mahavira", // Lynn Margulis (b. Lynn Petra Alexander) - an American evolutionary theorist and biologist, science author, + // educator, and popularizer, and was the primary modern proponent for the significance of symbiosis in evolution. + // - https://en.wikipedia.org/wiki/Lynn_Margulis + "margulis", // Yukihiro Matsumoto - Japanese computer scientist and software programmer best known as the chief designer of the + // Ruby programming language. https://en.wikipedia.org/wiki/Yukihiro_Matsumoto + "matsumoto", // James Clerk Maxwell - Scottish physicist, best known for his formulation of electromagnetic theory. https://en + // .wikipedia.org/wiki/James_Clerk_Maxwell + "maxwell", // Maria Mayer - American theoretical physicist and Nobel laureate in Physics for proposing the nuclear shell model + // of the atomic nucleus - https://en.wikipedia.org/wiki/Maria_Mayer + "mayer", // John McCarthy invented LISP: https://en.wikipedia.org/wiki/John_McCarthy_(computer_scientist) + "mccarthy", // Barbara McClintock - a distinguished American cytogeneticist, 1983 Nobel Laureate in Physiology or Medicine for + // discovering transposons. https://en.wikipedia.org/wiki/Barbara_McClintock + "mcclintock", // Anne Laura Dorinthea McLaren - British developmental biologist whose work helped lead to human in-vitro + // fertilisation. https://en.wikipedia.org/wiki/Anne_McLaren + "mclaren", // Malcolm McLean invented the modern shipping container: https://en.wikipedia.org/wiki/Malcom_McLean + "mclean", // Kay McNulty - one of the original programmers of the ENIAC. https://en.wikipedia.org/wiki/ENIAC - https://en + // .wikipedia.org/wiki/Kathleen_Antonelli + "mcnulty", // Gregor Johann Mendel - Czech scientist and founder of genetics. https://en.wikipedia.org/wiki/Gregor_Mendel + "mendel", // Dmitri Mendeleev - a chemist and inventor. He formulated the Periodic Law, created a farsighted version of the + // periodic table of elements, and used it to correct the properties of some already discovered elements and also + // to predict the properties of eight elements yet to be discovered. https://en.wikipedia.org/wiki/Dmitri_Mendeleev + "mendeleev", // Lise Meitner - Austrian/Swedish physicist who was involved in the discovery of nuclear fission. The element + // meitnerium is named after her - https://en.wikipedia.org/wiki/Lise_Meitner + "meitner", // Carla Meninsky, was the game designer and programmer for Atari 2600 games Dodge 'Em and Warlords. https://en + // .wikipedia.org/wiki/Carla_Meninsky + "meninsky", // Ralph C. Merkle - American computer scientist, known for devising Merkle's puzzles - one of the very first + // schemes for public-key cryptography. Also, inventor of Merkle trees and co-inventor of the Merkle-Damgård + // construction for building collision-resistant cryptographic hash functions and the Merkle-Hellman knapsack + // cryptosystem. https://en.wikipedia.org/wiki/Ralph_Merkle + "merkle", // Johanna Mestorf - German prehistoric archaeologist and first female museum director in Germany - https://en + // .wikipedia.org/wiki/Johanna_Mestorf + "mestorf", // Marvin Minsky - Pioneer in Artificial Intelligence, co-founder of the MIT's AI Lab, won the Turing Award in 1969 + // . https://en.wikipedia.org/wiki/Marvin_Minsky + "minsky", // Maryam Mirzakhani - an Iranian mathematician and the first woman to win the Fields Medal. https://en.wikipedia + // .org/wiki/Maryam_Mirzakhani + "mirzakhani", // Gordon Earle Moore - American engineer, Silicon Valley founding father, author of Moore's law. https://en + // .wikipedia.org/wiki/Gordon_Moore + "moore", // Samuel Morse - contributed to the invention of a single-wire telegraph system based on European telegraphs and + // was a co-developer of the Morse code - https://en.wikipedia.org/wiki/Samuel_Morse + "morse", // Ian Murdock - founder of the Debian project - https://en.wikipedia.org/wiki/Ian_Murdock + "murdock", // May-Britt Moser - Nobel prize winner neuroscientist who contributed to the discovery of grid cells in the brain. + // https://en.wikipedia.org/wiki/May-Britt_Moser + "moser", // John Napier of Merchiston - Scottish landowner known as an astronomer, mathematician and physicist. Best known + // for his discovery of logarithms. https://en.wikipedia.org/wiki/John_Napier + "napier", // John Forbes Nash, Jr. - American mathematician who made fundamental contributions to game theory, differential + // geometry, and the study of partial differential equations. https://en.wikipedia.org/wiki/John_Forbes_Nash_Jr. + "nash", // John von Neumann - todays computer architectures are based on the von Neumann architecture. https://en.wikipedia + // .org/wiki/Von_Neumann_architecture + "neumann", // Isaac Newton invented classic mechanics and modern optics. https://en.wikipedia.org/wiki/Isaac_Newton + "newton", // Florence Nightingale, more prominently known as a nurse, was also the first female member of the Royal + // Statistical Society and a pioneer in statistical graphics https://en.wikipedia + // .org/wiki/Florence_Nightingale#Statistics_and_sanitary_reform + "nightingale", // Alfred Nobel - a Swedish chemist, engineer, innovator, and armaments manufacturer (inventor of dynamite) - + // https://en.wikipedia.org/wiki/Alfred_Nobel + "nobel", // Emmy Noether, German mathematician. Noether's Theorem is named after her. https://en.wikipedia + // .org/wiki/Emmy_Noether + "noether", // Poppy Northcutt. Poppy Northcutt was the first woman to work as part of NASA’s Mission Control. http://www + // .businessinsider.com/poppy-northcutt-helped-apollo-astronauts-2014-12?op=1 + "northcutt", // Robert Noyce invented silicone integrated circuits and gave Silicon Valley its name. - https://en.wikipedia + // .org/wiki/Robert_Noyce + "noyce", // Panini - Ancient Indian linguist and grammarian from 4th century CE who worked on the world's first formal + // system - https://en.wikipedia.org/wiki/P%C4%81%E1%B9%87ini#Comparison_with_modern_formal_systems + "panini", // Ambroise Pare invented modern surgery. https://en.wikipedia.org/wiki/Ambroise_Par%C3%A9 + "pare", // Blaise Pascal, French mathematician, physicist, and inventor - https://en.wikipedia.org/wiki/Blaise_Pascal + "pascal", // Louis Pasteur discovered vaccination, fermentation and pasteurization. https://en.wikipedia.org/wiki/Louis_Pasteur. + "pasteur", // Cecilia Payne-Gaposchkin was an astronomer and astrophysicist who, in 1925, proposed in her Ph.D. thesis an + // explanation for the composition of stars in terms of the relative abundances of hydrogen and helium. https://en + // .wikipedia.org/wiki/Cecilia_Payne-Gaposchkin + "payne", // Radia Perlman is a software designer and network engineer and most famous for her invention of the spanning-tree + // protocol (STP). https://en.wikipedia.org/wiki/Radia_Perlman + "perlman", // Rob Pike was a key contributor to Unix, Plan 9, the X graphic system, utf-8, and the Go programming language. + // https://en.wikipedia.org/wiki/Rob_Pike + "pike", // Henri Poincaré made fundamental contributions in several fields of mathematics. https://en.wikipedia + // .org/wiki/Henri_Poincar%C3%A9 + "poincare", // Laura Poitras is a director and producer whose work, made possible by open source crypto tools, advances the + // causes of truth and freedom of information by reporting disclosures by whistleblowers such as Edward Snowden. + // https://en.wikipedia.org/wiki/Laura_Poitras + "poitras", // Tat’yana Avenirovna Proskuriakova (January 23 [O.S. January 10] 1909 – August 30, 1985) was a + // Russian-American Mayanist scholar and archaeologist who contributed significantly to the deciphering + // of Maya hieroglyphs, the writing system of the pre-Columbian Maya civilization of Mesoamerica + // . https://en.wikipedia.org/wiki/Tatiana_Proskouriakoff + "proskuriakova", // Claudius Ptolemy - a Greco-Egyptian writer of Alexandria, known as a mathematician, astronomer, geographer, + // astrologer, and poet of a single epigram in the Greek Anthology - https://en.wikipedia.org/wiki/Ptolemy + "ptolemy", // C. V. Raman - Indian physicist who won the Nobel Prize in 1930 for proposing the Raman effect. - https://en + // .wikipedia.org/wiki/C._V._Raman + "raman", // Srinivasa Ramanujan - Indian mathematician and autodidact who made extraordinary contributions to mathematical + // analysis, number theory, infinite series, and continued fractions. - https://en.wikipedia + // .org/wiki/Srinivasa_Ramanujan + "ramanujan", // Sally Kristen Ride was an American physicist and astronaut. She was the first American woman in space, and the + // youngest American astronaut. https://en.wikipedia.org/wiki/Sally_Ride + "ride", // Rita Levi-Montalcini - Won Nobel Prize in Physiology or Medicine jointly with colleague Stanley Cohen for the + // discovery of nerve growth factor (https://en.wikipedia.org/wiki/Rita_Levi-Montalcini) + "montalcini", // Dennis Ritchie - co-creator of UNIX and the C programming language. - https://en.wikipedia.org/wiki/Dennis_Ritchie + "ritchie", // Ida Rhodes - American pioneer in computer programming, designed the first computer used for Social Security. + // https://en.wikipedia.org/wiki/Ida_Rhodes + "rhodes", // Julia Hall Bowman Robinson - American mathematician renowned for her contributions to the fields of + // computability theory and computational complexity theory. https://en.wikipedia.org/wiki/Julia_Robinson + "robinson", // Wilhelm Conrad Röntgen - German physicist who was awarded the first Nobel Prize in Physics in 1901 for the + // discovery of X-rays (Röntgen rays). https://en.wikipedia.org/wiki/Wilhelm_R%C3%B6ntgen + "roentgen", // Rosalind Franklin - British biophysicist and X-ray crystallographer whose research was critical to the + // understanding of DNA - https://en.wikipedia.org/wiki/Rosalind_Franklin + "rosalind", // Vera Rubin - American astronomer who pioneered work on galaxy rotation rates. https://en.wikipedia + // .org/wiki/Vera_Rubin + "rubin", // Meghnad Saha - Indian astrophysicist best known for his development of the Saha equation, used to describe + // chemical and physical conditions in stars - https://en.wikipedia.org/wiki/Meghnad_Saha + "saha", // Jean E. Sammet developed FORMAC, the first widely used computer language for symbolic manipulation of + // mathematical formulas. https://en.wikipedia.org/wiki/Jean_E._Sammet + "sammet", // Mildred Sanderson - American mathematician best known for Sanderson's theorem concerning modular invariants. + // https://en.wikipedia.org/wiki/Mildred_Sanderson + "sanderson", // Claude Shannon - The father of information theory and founder of digital circuit design theory. (https://en + // .wikipedia.org/wiki/Claude_Shannon) + "shannon", // Carol Shaw - Originally an Atari employee, Carol Shaw is said to be the first female video game designer. + // https://en.wikipedia.org/wiki/Carol_Shaw_(video_game_designer) + "shaw", // Dame Stephanie "Steve" Shirley - Founded a software company in 1962 employing women working from home. + // https://en.wikipedia.org/wiki/Steve_Shirley + "shirley", // William Shockley co-invented the transistor - https://en.wikipedia.org/wiki/William_Shockley + "shockley", // Lina Solomonovna Stern (or Shtern; 26 August 1878 – 7 March 1968) was a Soviet biochemist, physiologist and + // humanist whose medical discoveries saved thousands of lives at the fronts of World + // War II. She is best known for her pioneering work on blood–brain barrier, which she described as + // hemato-encephalic barrier in 1921. https://en.wikipedia.org/wiki/Lina_Stern + "shtern", // Françoise Barré-Sinoussi - French virologist and Nobel Prize Laureate in Physiology or Medicine; her work was + // fundamental in identifying HIV as the cause of AIDS. https://en.wikipedia + // .org/wiki/Fran%C3%A7oise_Barr%C3%A9-Sinoussi + "sinoussi", // Betty Snyder - one of the original programmers of the ENIAC. https://en.wikipedia.org/wiki/ENIAC - https://en + // .wikipedia.org/wiki/Betty_Holberton + "snyder", // Cynthia Solomon - Pioneer in the fields of artificial intelligence, computer science and educational computing. + // Known for creation of Logo, an educational programming language. https://en.wikipedia.org/wiki/Cynthia_Solomon + "solomon", // Frances Spence - one of the original programmers of the ENIAC. https://en.wikipedia.org/wiki/ENIAC - https://en + // .wikipedia.org/wiki/Frances_Spence + "spence", // Ivan Edward Sutherland - American computer scientist and Internet pioneer, widely regarded as the father of + // computer graphics. https://en.wikipedia.org/wiki/Ivan_Sutherland + "sutherland", // Richard Matthew Stallman - the founder of the Free Software movement, the GNU project, the Free Software + // Foundation, and the League for Programming Freedom. He also invented the concept of copyleft to protect the + // ideals of this movement, and enshrined this concept in the widely-used GPL (General Public License) for software + // . https://en.wikiquote.org/wiki/Richard_Stallman + "stallman", // Michael Stonebraker is a database research pioneer and architect of Ingres, Postgres, VoltDB and SciDB. Winner + // of 2014 ACM Turing Award. https://en.wikipedia.org/wiki/Michael_Stonebraker + "stonebraker", // Janese Swanson (with others) developed the first of the Carmen Sandiego games. She went on to found Girl Tech. + // https://en.wikipedia.org/wiki/Janese_Swanson + "swanson", // Aaron Swartz was influential in creating RSS, Markdown, Creative Commons, Reddit, and much of the internet as we + // know it today. He was devoted to freedom of information on the web. https://en.wikiquote.org/wiki/Aaron_Swartz + "swartz", // Bertha Swirles was a theoretical physicist who made a number of contributions to early quantum theory. + // https://en.wikipedia.org/wiki/Bertha_Swirles + "swirles", // Helen Brooke Taussig - American cardiologist and founder of the field of paediatric cardiology. https://en + // .wikipedia.org/wiki/Helen_B._Taussig + "taussig", // Valentina Tereshkova is a Russian engineer, cosmonaut and politician. She was the first woman to fly to space in + // 1963. In 2013, at the age of 76, she offered to go on a one-way mission to Mars. https://en.wikipedia + // .org/wiki/Valentina_Tereshkova + "tereshkova", // Nikola Tesla invented the AC electric system and every gadget ever used by a James Bond villain. https://en + // .wikipedia.org/wiki/Nikola_Tesla + "tesla", // Marie Tharp - American geologist and oceanic cartographer who co-created the first scientific map of the + // Atlantic Ocean floor. Her work led to the acceptance of the theories of plate tectonics and continental drift. + // https://en.wikipedia.org/wiki/Marie_Tharp + "tharp", // Ken Thompson - co-creator of UNIX and the C programming language - https://en.wikipedia.org/wiki/Ken_Thompson + "thompson", // Linus Torvalds invented Linux and Git. https://en.wikipedia.org/wiki/Linus_Torvalds + "torvalds", // Youyou Tu - Chinese pharmaceutical chemist and educator known for discovering artemisinin and + // dihydroartemisinin, used to treat malaria, which has saved millions of lives. Joint winner of the 2015 Nobel + // Prize in Physiology or Medicine. https://en.wikipedia.org/wiki/Tu_Youyou + "tu", // Alan Turing was a founding father of computer science. https://en.wikipedia.org/wiki/Alan_Turing. + "turing", // Varahamihira - Ancient Indian mathematician who discovered trigonometric formulae during 505-587 CE - https://en + // .wikipedia.org/wiki/Var%C4%81hamihira#Contributions + "varahamihira", // Dorothy Vaughan was a NASA mathematician and computer programmer on the SCOUT launch vehicle program that put + // America's first satellites into space - https://en.wikipedia.org/wiki/Dorothy_Vaughan + "vaughan", // Sir Mokshagundam Visvesvaraya - is a notable Indian engineer. He is a recipient of the Indian Republic's + // highest honour, the Bharat Ratna, in 1955. On his birthday, 15 September is celebrated as Engineer's Day in + // India in his memory - https://en.wikipedia.org/wiki/Visvesvaraya + "visvesvaraya", // Christiane Nüsslein-Volhard - German biologist, won Nobel Prize in Physiology or Medicine in 1995 for research + // on the genetic control of embryonic development. https://en.wikipedia.org/wiki/Christiane_N%C3%BCsslein-Volhard + "volhard", // Cédric Villani - French mathematician, won Fields Medal, Fermat Prize and Poincaré Price for his work in + // differential geometry and statistical mechanics. https://en.wikipedia.org/wiki/C%C3%A9dric_Villani + "villani", // Marlyn Wescoff - one of the original programmers of the ENIAC. https://en.wikipedia.org/wiki/ENIAC - https://en + // .wikipedia.org/wiki/Marlyn_Meltzer + "wescoff", // Andrew Wiles - Notable British mathematician who proved the enigmatic Fermat's Last Theorem - https://en + // .wikipedia.org/wiki/Andrew_Wiles + "wiles", // Roberta Williams, did pioneering work in graphical adventure games for personal computers, particularly the + // King's Quest series. https://en.wikipedia.org/wiki/Roberta_Williams + "williams", // Malcolm John Williamson - British mathematician and cryptographer employed by the GCHQ. Developed in 1974 what + // is now known as Diffie-Hellman key exchange (Diffie and Hellman first published the scheme in 1976). https://en + // .wikipedia.org/wiki/Malcolm_J._Williamson + "williamson", // Sophie Wilson designed the first Acorn Micro-Computer and the instruction set for ARM processors. https://en + // .wikipedia.org/wiki/Sophie_Wilson + "wilson", // Jeannette Wing - co-developed the Liskov substitution principle. - https://en.wikipedia.org/wiki/Jeannette_Wing + "wing", // Steve Wozniak invented the Apple I and Apple II. https://en.wikipedia.org/wiki/Steve_Wozniak + "wozniak", // The Wright brothers, Orville and Wilbur - credited with inventing and building the world's first successful + // airplane and making the first controlled, powered and sustained heavier-than-air human flight - https://en + // .wikipedia.org/wiki/Wright_brothers + "wright", // Chien-Shiung Wu - Chinese-American experimental physicist who made significant contributions to nuclear physics. + // https://en.wikipedia.org/wiki/Chien-Shiung_Wu + "wu", // Rosalyn Sussman Yalow - Rosalyn Sussman Yalow was an American medical physicist, and a co-winner of the 1977 + // Nobel Prize in Physiology or Medicine for development of the radioimmunoassay technique. https://en.wikipedia + // .org/wiki/Rosalyn_Sussman_Yalow + "yalow", // Ada Yonath - an Israeli crystallographer, the first woman from the Middle East to win a Nobel prize in the + // sciences. https://en.wikipedia.org/wiki/Ada_Yonath + "yonath", // Nikolay Yegorovich Zhukovsky (January 17 1847 – March 17, 1921) was a Russian scientist, mathematician + // and engineer, and a founding father of modern aero- and hydrodynamics. Whereas contemporary scientists + // scoffed at the idea of human flight, Zhukovsky was the first to undertake the study of + // airflow. He is often called the Father of Russian Aviation. https://en.wikipedia + // .org/wiki/Nikolay_Yegorovich_Zhukovsky + "zhukovsky" + ).shuffled() + + + /** + * Returns a name from the list of names formatted as "adjective_surname", + * for example 'focused_turing'. The list is randomized on class + * initialization, but the answers from repeated calls with the same number + * are stable. + * + * @param number index into the sequence of names + * @return a Moby name + */ + fun getRandomName(number: Int): String { + val combinationIdx = number % (LEFT.size * RIGHT.size) + val rightIdx = combinationIdx / LEFT.size + val leftIdx = combinationIdx % LEFT.size + return "${LEFT[leftIdx]}-${RIGHT[rightIdx]}" + } + + fun randomName(suffix: String? = null): String { + val formattedSuffix = if (suffix != null) { + "-${suffix.removePrefix("-")}" + } else { + "" + } + return "${LEFT.random()}-${RIGHT.random()}$formattedSuffix" + } +} From 0272c387e6ae3625450c02009f75755d61593abd Mon Sep 17 00:00:00 2001 From: Marty Pitt Date: Tue, 23 Jun 2026 06:01:32 +0100 Subject: [PATCH 09/11] Append a random suffix to isolated network names Names the isolated host-mode network nebula---<5 random chars> (eg. nebula-focused-turing-a3k9z), so it can't collide with a network left over from an earlier run when ryuk cleanup is disabled. Refs #62 Co-Authored-By: Claude Opus 4.8 (1M context) --- .../kotlin/com/orbitalhq/nebula/cli/NebulaCli.kt | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/nebula-cli/src/main/kotlin/com/orbitalhq/nebula/cli/NebulaCli.kt b/nebula-cli/src/main/kotlin/com/orbitalhq/nebula/cli/NebulaCli.kt index b48d235..e5351c1 100644 --- a/nebula-cli/src/main/kotlin/com/orbitalhq/nebula/cli/NebulaCli.kt +++ b/nebula-cli/src/main/kotlin/com/orbitalhq/nebula/cli/NebulaCli.kt @@ -103,8 +103,10 @@ class Nebula : Callable { ConsumerConnectivity.NETWORK -> resolveOwnContainerNetwork() ConsumerConnectivity.HOST -> { // Give the isolated network a readable, identifiable name (eg. - // nebula-focused-turing) rather than testcontainers' default UUID. - val isolatedNetworkName = "nebula-${Names.randomName()}" + // nebula-focused-turing-a3k9z) rather than testcontainers' default UUID. + // The random suffix avoids name collisions with networks left over from + // earlier runs (which aren't reaped when ryuk is disabled). + val isolatedNetworkName = "nebula-${Names.randomName()}-${randomSuffix(5)}" val network = Network.builder() .createNetworkCmdModifier { cmd -> cmd.withName(isolatedNetworkName) } .build() @@ -305,6 +307,12 @@ class Nebula : Callable { fun main(args: Array): Unit = exitProcess(CommandLine(Nebula()).setCaseInsensitiveEnumValuesAllowed(true).execute(*args)) +/** A random lowercase-alphanumeric string of [length] characters. */ +private fun randomSuffix(length: Int): String { + val pool = ('a'..'z') + ('0'..'9') + return (1..length).map { pool.random() }.joinToString("") +} + /** * From the set of networks a container is attached to, selects the one its * child containers should join. From e7b82edd8fc86d8606b502405cee850571bab3fa Mon Sep 17 00:00:00 2001 From: Marty Pitt Date: Tue, 23 Jun 2026 06:08:45 +0100 Subject: [PATCH 10/11] removed old docs2.0 folder --- docs2.0/.env.example | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 docs2.0/.env.example diff --git a/docs2.0/.env.example b/docs2.0/.env.example deleted file mode 100644 index 78eade7..0000000 --- a/docs2.0/.env.example +++ /dev/null @@ -1,2 +0,0 @@ -# Rename this file to `.env` to use environment variables locally -ZUDOKU_PUBLIC_VAR="my-value" From e19429407c554319831401274e6d62ffd1b0a34a Mon Sep 17 00:00:00 2001 From: Marty Pitt Date: Tue, 23 Jun 2026 06:21:40 +0100 Subject: [PATCH 11/11] Pin LocalStack image to 3.0.2 The s3 DSL defaulted to localstack/localstack:latest - the only component on a floating tag. CI runners pull a fresh :latest (now LocalStack 4.x), which the pinned testcontainers 1.19.0 LocalStackContainer can't drive reliably: the container reports started but the S3 edge isn't serving, so the test fails with "Connection refused" on the mapped port. Locally a cached 3.0.x :latest kept working, hiding it. Pin to 3.0.2 (a stable tag from the 3.0.x line that has been working locally), matching the explicit pinning of every other component's image. Verified by pulling 3.0.2 fresh and running S3ExecutorTest. Co-Authored-By: Claude Opus 4.8 (1M context) --- nebula-dsl/src/main/kotlin/com/orbitalhq/nebula/s3/S3Dsl.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nebula-dsl/src/main/kotlin/com/orbitalhq/nebula/s3/S3Dsl.kt b/nebula-dsl/src/main/kotlin/com/orbitalhq/nebula/s3/S3Dsl.kt index 75b1ddb..61e13e7 100644 --- a/nebula-dsl/src/main/kotlin/com/orbitalhq/nebula/s3/S3Dsl.kt +++ b/nebula-dsl/src/main/kotlin/com/orbitalhq/nebula/s3/S3Dsl.kt @@ -9,7 +9,7 @@ import mu.KotlinLogging private val logger: KLogger = KotlinLogging.logger {} interface S3Dsl : InfraDsl { - fun s3(imageName: String = "localstack/localstack:latest", componentName: String = "s3", dsl: S3Builder.(KLogger) -> Unit): S3Executor { + fun s3(imageName: String = "localstack/localstack:3.0.2", componentName: String = "s3", dsl: S3Builder.(KLogger) -> Unit): S3Executor { val builder = S3Builder(imageName, componentName) builder.dsl(logger) return this.add(S3Executor(builder.build(), loggers = listOf(logger.name)))