package config import ( "fmt" "os" "path/filepath" "strconv" "sync" "time" "github.com/magiconair/properties" ) const ReaperDefaultImage = "testcontainers/ryuk:0.8.1" var ( tcConfig Config tcConfigOnce *sync.Once = new(sync.Once) ) // testcontainersConfig { // Config represents the configuration for Testcontainers. // User values are read from ~/.testcontainers.properties file which can be overridden // using the specified environment variables. For more information, see [Custom Configuration]. // // The Ryuk prefixed fields controls the [Garbage Collector] feature, which ensures that // resources are cleaned up after the test execution. // // [Garbage Collector]: https://golang.testcontainers.org/features/garbage_collector/ // [Custom Configuration]: https://golang.testcontainers.org/features/configuration/ type Config struct { // Host is the address of the Docker daemon. // // Environment variable: DOCKER_HOST Host string `properties:"docker.host,default="` // TLSVerify is a flag to enable or disable TLS verification when connecting to a Docker daemon. // // Environment variable: DOCKER_TLS_VERIFY TLSVerify int `properties:"docker.tls.verify,default=0"` // CertPath is the path to the directory containing the Docker certificates. // This is used when connecting to a Docker daemon over TLS. // // Environment variable: DOCKER_CERT_PATH CertPath string `properties:"docker.cert.path,default="` // HubImageNamePrefix is the prefix used for the images pulled from the Docker Hub. // This is useful when running tests in environments with restricted internet access. // // Environment variable: TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX HubImageNamePrefix string `properties:"hub.image.name.prefix,default="` // RyukDisabled is a flag to enable or disable the Garbage Collector. // Setting this to true will prevent testcontainers from automatically cleaning up // resources, which is particularly important in tests which timeout as they // don't run test clean up. // // Environment variable: TESTCONTAINERS_RYUK_DISABLED RyukDisabled bool `properties:"ryuk.disabled,default=false"` // RyukPrivileged is a flag to enable or disable the privileged mode for the Garbage Collector container. // Setting this to true will run the Garbage Collector container in privileged mode. // // Environment variable: TESTCONTAINERS_RYUK_CONTAINER_PRIVILEGED RyukPrivileged bool `properties:"ryuk.container.privileged,default=false"` // RyukReconnectionTimeout is the time to wait before attempting to reconnect to the Garbage Collector container. // // Environment variable: TESTCONTAINERS_RYUK_RECONNECTION_TIMEOUT RyukReconnectionTimeout time.Duration `properties:"ryuk.reconnection.timeout,default=10s"` // RyukConnectionTimeout is the time to wait before timing out when connecting to the Garbage Collector container. // // Environment variable: TESTCONTAINERS_RYUK_CONNECTION_TIMEOUT RyukConnectionTimeout time.Duration `properties:"ryuk.connection.timeout,default=1m"` // RyukVerbose is a flag to enable or disable verbose logging for the Garbage Collector. // // Environment variable: TESTCONTAINERS_RYUK_VERBOSE RyukVerbose bool `properties:"ryuk.verbose,default=false"` // TestcontainersHost is the address of the Testcontainers host. // // Environment variable: TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE TestcontainersHost string `properties:"tc.host,default="` } // } // Read reads from testcontainers properties file, if it exists // it is possible that certain values get overridden when set as environment variables func Read() Config { tcConfigOnce.Do(func() { tcConfig = read() }) return tcConfig } // Reset resets the singleton instance of the Config struct, // allowing to read the configuration again. // Handy for testing, so do not use it in production code // This function is not thread-safe func Reset() { tcConfigOnce = new(sync.Once) } func read() Config { config := Config{} applyEnvironmentConfiguration := func(config Config) Config { ryukDisabledEnv := os.Getenv("TESTCONTAINERS_RYUK_DISABLED") if parseBool(ryukDisabledEnv) { config.RyukDisabled = ryukDisabledEnv == "true" } hubImageNamePrefix := os.Getenv("TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX") if hubImageNamePrefix != "" { config.HubImageNamePrefix = hubImageNamePrefix } ryukPrivilegedEnv := os.Getenv("TESTCONTAINERS_RYUK_CONTAINER_PRIVILEGED") if parseBool(ryukPrivilegedEnv) { config.RyukPrivileged = ryukPrivilegedEnv == "true" } ryukVerboseEnv := os.Getenv("TESTCONTAINERS_RYUK_VERBOSE") if parseBool(ryukVerboseEnv) { config.RyukVerbose = ryukVerboseEnv == "true" } ryukReconnectionTimeoutEnv := os.Getenv("TESTCONTAINERS_RYUK_RECONNECTION_TIMEOUT") if timeout, err := time.ParseDuration(ryukReconnectionTimeoutEnv); err == nil { config.RyukReconnectionTimeout = timeout } ryukConnectionTimeoutEnv := os.Getenv("TESTCONTAINERS_RYUK_CONNECTION_TIMEOUT") if timeout, err := time.ParseDuration(ryukConnectionTimeoutEnv); err == nil { config.RyukConnectionTimeout = timeout } return config } home, err := os.UserHomeDir() if err != nil { return applyEnvironmentConfiguration(config) } tcProp := filepath.Join(home, ".testcontainers.properties") // init from a file properties, err := properties.LoadFile(tcProp, properties.UTF8) if err != nil { return applyEnvironmentConfiguration(config) } if err := properties.Decode(&config); err != nil { fmt.Printf("invalid testcontainers properties file, returning an empty Testcontainers configuration: %v\n", err) return applyEnvironmentConfiguration(config) } return applyEnvironmentConfiguration(config) } func parseBool(input string) bool { _, err := strconv.ParseBool(input) return err == nil }