diff --git a/docs/en/operations/server-configuration-parameters/settings.md b/docs/en/operations/server-configuration-parameters/settings.md index c017fb7b9f5..5c52319b0c9 100644 --- a/docs/en/operations/server-configuration-parameters/settings.md +++ b/docs/en/operations/server-configuration-parameters/settings.md @@ -2630,3 +2630,114 @@ Possible values: - 1 — Enabled. Default value: 0. + +## proxy {#proxy} + +Define proxy servers for HTTP and HTTPS requests, currently supported by S3 storage, S3 table functions, and URL functions. + +There are three ways to define proxy servers: environment variables, proxy lists, and remote proxy resolvers. + +### Environment variables + +The `http_proxy` and `https_proxy` environment variables allow you to specify a +proxy server for a given protocol. If you have it set on your system, it should work seamlessly. + +This is the simplest approach if a given protocol has +only one proxy server and that proxy server doesn't change. + +### Proxy lists + +This approach allows you to specify one or more +proxy servers for a protocol. If more than one proxy server is defined, +ClickHouse uses the different proxies on a round-robin basis, balancing the +load across the servers. This is the simplest approach if there is more than +one proxy server for a protocol and the list of proxy servers doesn't change. + +### Configuration template + +``` xml + + + http://proxy1 + http://proxy2:3128 + + + http://proxy1:3128 + + +``` + +`` fields + +* `` - A list of one or more HTTP proxies +* `` - A list of one or more HTTPS proxies + +`` and `` fields + +* `` - The URI of the proxy + +### Remote proxy resolvers + +It's possible that the proxy servers change dynamically. In that +case, you can define the endpoint of a resolver. ClickHouse sends +an empty GET request to that endpoint, the remote resolver should return the proxy host. +ClickHouse will use it to form the proxy URI using the following template: `{proxy_scheme}://{proxy_host}:{proxy_port}` + +### Configuration template + +``` xml + + + + http://resolver:8080/hostname + http + 80 + 10 + + + + + + http://resolver:8080/hostname + http + 3128 + 10 + + + + +``` + +`` fields + +* `` - A list of one or more resolvers* +* `` - A list of one or more resolvers* + +`` and `` fields + +* `` - The endpoint and other details for a resolver. + You can have multiple `` elements, but only the first + `` for a given protocol is used. Any other `` + elements for that protocol are ignored. That means load balancing + (if needed) should be implemented by the remote resolver. + +`` fields + +* `` - The URI of the proxy resolver +* `` - The protocol of the final proxy URI. This can be either `http` or `https`. +* `` - The port number of the proxy resolver +* `` - The time in seconds that values from the resolver + should be cached by ClickHouse. Setting this value to `0` causes ClickHouse + to contact the resolver for every HTTP or HTTPS request. + +### Precedence + +Proxy settings are determined in the following order: + +1. Remote proxy resolvers +2. Proxy lists +3. Environment variables + +ClickHouse will check the highest priority resolver type for the request protocol. If it is not defined, +it will check the next highest priority resolver type, until it reaches the environment resolver. +This also allows a mix of resolver types can be used. diff --git a/src/Common/EnvironmentProxyConfigurationResolver.cpp b/src/Common/EnvironmentProxyConfigurationResolver.cpp index 184e2ac5ca5..79b50964cf5 100644 --- a/src/Common/EnvironmentProxyConfigurationResolver.cpp +++ b/src/Common/EnvironmentProxyConfigurationResolver.cpp @@ -25,25 +25,12 @@ namespace * getenv is safe to use here because ClickHouse code does not make any call to `setenv` or `putenv` * aside from tests and a very early call during startup: https://github.com/ClickHouse/ClickHouse/blob/master/src/Daemon/BaseDaemon.cpp#L791 * */ - - if (protocol == DB::ProxyConfiguration::Protocol::HTTP) + switch (protocol) { - return std::getenv(PROXY_HTTP_ENVIRONMENT_VARIABLE); // NOLINT(concurrency-mt-unsafe) - } - else if (protocol == DB::ProxyConfiguration::Protocol::HTTPS) - { - return std::getenv(PROXY_HTTPS_ENVIRONMENT_VARIABLE); // NOLINT(concurrency-mt-unsafe) - } - else - { - if (const char * http_proxy_host = std::getenv(PROXY_HTTP_ENVIRONMENT_VARIABLE)) // NOLINT(concurrency-mt-unsafe) - { - return http_proxy_host; - } - else - { + case ProxyConfiguration::Protocol::HTTP: + return std::getenv(PROXY_HTTP_ENVIRONMENT_VARIABLE); // NOLINT(concurrency-mt-unsafe) + case ProxyConfiguration::Protocol::HTTPS: return std::getenv(PROXY_HTTPS_ENVIRONMENT_VARIABLE); // NOLINT(concurrency-mt-unsafe) - } } } } diff --git a/src/Common/ProxyConfiguration.h b/src/Common/ProxyConfiguration.h index cc951c004bc..421c9fb10d9 100644 --- a/src/Common/ProxyConfiguration.h +++ b/src/Common/ProxyConfiguration.h @@ -1,17 +1,23 @@ #pragma once #include +#include namespace DB { +namespace ErrorCodes +{ + extern const int BAD_ARGUMENTS; +} + + struct ProxyConfiguration { enum class Protocol { HTTP, - HTTPS, - ANY + HTTPS }; static auto protocolFromString(const std::string & str) @@ -24,10 +30,8 @@ struct ProxyConfiguration { return Protocol::HTTPS; } - else - { - return Protocol::ANY; - } + + throw Exception(ErrorCodes::BAD_ARGUMENTS, "Unknown proxy protocol: {}", str); } static auto protocolToString(Protocol protocol) @@ -38,8 +42,6 @@ struct ProxyConfiguration return "http"; case Protocol::HTTPS: return "https"; - case Protocol::ANY: - return "any"; } } diff --git a/src/Common/ProxyConfigurationResolverProvider.cpp b/src/Common/ProxyConfigurationResolverProvider.cpp index 30164c776e5..c7f50b70479 100644 --- a/src/Common/ProxyConfigurationResolverProvider.cpp +++ b/src/Common/ProxyConfigurationResolverProvider.cpp @@ -20,12 +20,13 @@ namespace std::shared_ptr getRemoteResolver( const String & config_prefix, const Poco::Util::AbstractConfiguration & configuration) { - auto endpoint = Poco::URI(configuration.getString(config_prefix + ".endpoint")); - auto proxy_scheme = configuration.getString(config_prefix + ".proxy_scheme"); + auto resolver_prefix = config_prefix + ".resolver"; + auto endpoint = Poco::URI(configuration.getString(resolver_prefix + ".endpoint")); + auto proxy_scheme = configuration.getString(resolver_prefix + ".proxy_scheme"); if (proxy_scheme != "http" && proxy_scheme != "https") throw Exception(ErrorCodes::BAD_ARGUMENTS, "Only HTTP/HTTPS schemas allowed in proxy resolver config: {}", proxy_scheme); - auto proxy_port = configuration.getUInt(config_prefix + ".proxy_port"); - auto cache_ttl = configuration.getUInt(config_prefix + ".proxy_cache_time", 10); + auto proxy_port = configuration.getUInt(resolver_prefix + ".proxy_port"); + auto cache_ttl = configuration.getUInt(resolver_prefix + ".proxy_cache_time", 10); LOG_DEBUG(&Poco::Logger::get("ProxyConfigurationResolverProvider"), "Configured remote proxy resolver: {}, Scheme: {}, Port: {}", endpoint.toString(), proxy_scheme, proxy_port); @@ -33,31 +34,6 @@ namespace return std::make_shared(endpoint, proxy_scheme, proxy_port, cache_ttl); } - std::shared_ptr getRemoteResolver( - ProxyConfiguration::Protocol protocol, const String & config_prefix, const Poco::Util::AbstractConfiguration & configuration) - { - std::vector keys; - configuration.keys(config_prefix, keys); - - std::vector uris; - for (const auto & key : keys) - { - if (startsWith(key, "resolver")) - { - auto prefix_with_key = config_prefix + "." + key; - auto proxy_scheme_config_string = prefix_with_key + ".proxy_scheme"; - auto config_protocol = configuration.getString(proxy_scheme_config_string); - - if (ProxyConfiguration::Protocol::ANY == protocol || config_protocol == ProxyConfiguration::protocolToString(protocol)) - { - return getRemoteResolver(prefix_with_key, configuration); - } - } - } - - return nullptr; - } - auto extractURIList(const String & config_prefix, const Poco::Util::AbstractConfiguration & configuration) { std::vector keys; @@ -84,34 +60,7 @@ namespace return uris; } - std::shared_ptr getListResolverNewSyntax( - ProxyConfiguration::Protocol protocol, - const String & config_prefix, - const Poco::Util::AbstractConfiguration & configuration - ) - { - std::vector uris; - - bool include_http_uris = ProxyConfiguration::Protocol::ANY == protocol || ProxyConfiguration::Protocol::HTTP == protocol; - - if (include_http_uris && configuration.has(config_prefix + ".http")) - { - auto http_uris = extractURIList(config_prefix + ".http", configuration); - uris.insert(uris.end(), http_uris.begin(), http_uris.end()); - } - - bool include_https_uris = ProxyConfiguration::Protocol::ANY == protocol || ProxyConfiguration::Protocol::HTTPS == protocol; - - if (include_https_uris && configuration.has(config_prefix + ".https")) - { - auto https_uris = extractURIList(config_prefix + ".https", configuration); - uris.insert(uris.end(), https_uris.begin(), https_uris.end()); - } - - return uris.empty() ? nullptr : std::make_shared(uris); - } - - std::shared_ptr getListResolverOldSyntax( + std::shared_ptr getListResolver( const String & config_prefix, const Poco::Util::AbstractConfiguration & configuration ) @@ -121,29 +70,58 @@ namespace return uris.empty() ? nullptr : std::make_shared(uris); } - std::shared_ptr getListResolver( - ProxyConfiguration::Protocol protocol, const String & config_prefix, const Poco::Util::AbstractConfiguration & configuration + bool hasRemoteResolver(const String & config_prefix, const Poco::Util::AbstractConfiguration & configuration) + { + return configuration.has(config_prefix + ".resolver"); + } + + bool hasListResolver(const String & config_prefix, const Poco::Util::AbstractConfiguration & configuration) + { + return configuration.has(config_prefix + ".uri"); + } + + /* + * New syntax requires protocol prefix " or " + * */ + std::optional getProtocolPrefix( + ProxyConfiguration::Protocol request_protocol, + const String & config_prefix, + const Poco::Util::AbstractConfiguration & configuration ) { - std::vector keys; - configuration.keys(config_prefix, keys); + auto protocol_prefix = config_prefix + "." + ProxyConfiguration::protocolToString(request_protocol); + if (!configuration.has(protocol_prefix)) + { + return std::nullopt; + } - bool new_setting_syntax = std::find_if( - keys.begin(), - keys.end(), - [](const String & key) - { - return startsWith(key, "http") || startsWith(key, "https"); - }) != keys.end(); + return protocol_prefix; + } - return new_setting_syntax ? getListResolverNewSyntax(protocol, config_prefix, configuration) - : getListResolverOldSyntax(config_prefix, configuration); + template + std::optional calculatePrefixBasedOnSettingsSyntax( + ProxyConfiguration::Protocol request_protocol, + const String & config_prefix, + const Poco::Util::AbstractConfiguration & configuration + ) + { + if (!configuration.has(config_prefix)) + { + return std::nullopt; + } + + if constexpr (new_syntax) + { + return getProtocolPrefix(request_protocol, config_prefix, configuration); + } + + return config_prefix; } } std::shared_ptr ProxyConfigurationResolverProvider::get(Protocol protocol, const Poco::Util::AbstractConfiguration & configuration) { - if (auto resolver = getFromSettings(protocol, "", configuration)) + if (auto resolver = getFromSettings(protocol, "proxy", configuration)) { return resolver; } @@ -151,34 +129,36 @@ std::shared_ptr ProxyConfigurationResolverProvider:: return std::make_shared(protocol); } +template std::shared_ptr ProxyConfigurationResolverProvider::getFromSettings( - Protocol protocol, + Protocol request_protocol, const String & config_prefix, const Poco::Util::AbstractConfiguration & configuration ) { - auto proxy_prefix = config_prefix.empty() ? "proxy" : config_prefix + ".proxy"; + auto prefix_opt = calculatePrefixBasedOnSettingsSyntax(request_protocol, config_prefix, configuration); - if (configuration.has(proxy_prefix)) + if (!prefix_opt) { - std::vector config_keys; - configuration.keys(proxy_prefix, config_keys); + return nullptr; + } - if (auto remote_resolver = getRemoteResolver(protocol, proxy_prefix, configuration)) - { - return remote_resolver; - } + auto prefix = *prefix_opt; - if (auto list_resolver = getListResolver(protocol, proxy_prefix, configuration)) - { - return list_resolver; - } + if (hasRemoteResolver(prefix, configuration)) + { + return getRemoteResolver(prefix, configuration); + } + else if (hasListResolver(prefix, configuration)) + { + return getListResolver(prefix, configuration); } return nullptr; } std::shared_ptr ProxyConfigurationResolverProvider::getFromOldSettingsFormat( + Protocol request_protocol, const String & config_prefix, const Poco::Util::AbstractConfiguration & configuration ) @@ -187,7 +167,7 @@ std::shared_ptr ProxyConfigurationResolverProvider:: * First try to get it from settings only using the combination of config_prefix and configuration. * This logic exists for backward compatibility with old S3 storage specific proxy configuration. * */ - if (auto resolver = ProxyConfigurationResolverProvider::getFromSettings(Protocol::ANY, config_prefix, configuration)) + if (auto resolver = ProxyConfigurationResolverProvider::getFromSettings(request_protocol, config_prefix + ".proxy", configuration)) { return resolver; } @@ -196,7 +176,7 @@ std::shared_ptr ProxyConfigurationResolverProvider:: * In case the combination of config_prefix and configuration does not provide a resolver, try to get it from general / new settings. * Falls back to Environment resolver if no configuration is found. * */ - return ProxyConfigurationResolverProvider::get(Protocol::ANY, configuration); + return ProxyConfigurationResolverProvider::get(request_protocol, configuration); } } diff --git a/src/Common/ProxyConfigurationResolverProvider.h b/src/Common/ProxyConfigurationResolverProvider.h index 26b2261b218..ebf22f7e92a 100644 --- a/src/Common/ProxyConfigurationResolverProvider.h +++ b/src/Common/ProxyConfigurationResolverProvider.h @@ -27,11 +27,13 @@ public: * If no configuration is found, returns nullptr. * */ static std::shared_ptr getFromOldSettingsFormat( + Protocol request_protocol, const String & config_prefix, const Poco::Util::AbstractConfiguration & configuration ); private: + template static std::shared_ptr getFromSettings( Protocol protocol, const String & config_prefix, diff --git a/src/Common/tests/gtest_proxy_configuration_resolver_provider.cpp b/src/Common/tests/gtest_proxy_configuration_resolver_provider.cpp index 884040fcf52..bd6e08522c4 100644 --- a/src/Common/tests/gtest_proxy_configuration_resolver_provider.cpp +++ b/src/Common/tests/gtest_proxy_configuration_resolver_provider.cpp @@ -120,4 +120,78 @@ TEST_F(ProxyConfigurationResolverProviderTests, ListBoth) ASSERT_EQ(https_proxy_configuration.port, https_list_proxy_server.getPort()); } +TEST_F(ProxyConfigurationResolverProviderTests, RemoteResolverIsBasedOnProtocolConfigurationHTTP) +{ + /* + * Since there is no way to call `ProxyConfigurationResolver::resolve` on remote resolver, + * it is hard to verify the remote resolver was actually picked. One hackish way to assert + * the remote resolver was OR was not picked based on the configuration, is to use the + * environment resolver. Since the environment resolver is always returned as a fallback, + * we can assert the remote resolver was not picked if `ProxyConfigurationResolver::resolve` + * succeeds and returns an environment proxy configuration. + * */ + EnvironmentProxySetter setter(http_env_proxy_server, https_env_proxy_server); + + ConfigurationPtr config = Poco::AutoPtr(new Poco::Util::MapConfiguration()); + + config->setString("proxy", ""); + config->setString("proxy.https", ""); + config->setString("proxy.https.resolver", ""); + config->setString("proxy.https.resolver.endpoint", "http://resolver:8080/hostname"); + + // even tho proxy protocol / scheme is http, it should not be picked (prior to this PR, it would be picked) + config->setString("proxy.https.resolver.proxy_scheme", "http"); + config->setString("proxy.https.resolver.proxy_port", "80"); + config->setString("proxy.https.resolver.proxy_cache_time", "10"); + + context->setConfig(config); + + auto http_proxy_configuration = DB::ProxyConfigurationResolverProvider::get(DB::ProxyConfiguration::Protocol::HTTP, *config)->resolve(); + + /* + * Asserts env proxy is used and not the remote resolver. If the remote resolver is picked, it is an error because + * there is no `http` specification for remote resolver + * */ + ASSERT_EQ(http_proxy_configuration.host, http_env_proxy_server.getHost()); + ASSERT_EQ(http_proxy_configuration.port, http_env_proxy_server.getPort()); + ASSERT_EQ(http_proxy_configuration.protocol, DB::ProxyConfiguration::protocolFromString(http_env_proxy_server.getScheme())); +} + +TEST_F(ProxyConfigurationResolverProviderTests, RemoteResolverIsBasedOnProtocolConfigurationHTTPS) +{ + /* + * Since there is no way to call `ProxyConfigurationResolver::resolve` on remote resolver, + * it is hard to verify the remote resolver was actually picked. One hackish way to assert + * the remote resolver was OR was not picked based on the configuration, is to use the + * environment resolver. Since the environment resolver is always returned as a fallback, + * we can assert the remote resolver was not picked if `ProxyConfigurationResolver::resolve` + * succeeds and returns an environment proxy configuration. + * */ + EnvironmentProxySetter setter(http_env_proxy_server, https_env_proxy_server); + + ConfigurationPtr config = Poco::AutoPtr(new Poco::Util::MapConfiguration()); + + config->setString("proxy", ""); + config->setString("proxy.http", ""); + config->setString("proxy.http.resolver", ""); + config->setString("proxy.http.resolver.endpoint", "http://resolver:8080/hostname"); + + // even tho proxy protocol / scheme is https, it should not be picked (prior to this PR, it would be picked) + config->setString("proxy.http.resolver.proxy_scheme", "https"); + config->setString("proxy.http.resolver.proxy_port", "80"); + config->setString("proxy.http.resolver.proxy_cache_time", "10"); + + context->setConfig(config); + + auto http_proxy_configuration = DB::ProxyConfigurationResolverProvider::get(DB::ProxyConfiguration::Protocol::HTTPS, *config)->resolve(); + + /* + * Asserts env proxy is used and not the remote resolver. If the remote resolver is picked, it is an error because + * there is no `http` specification for remote resolver + * */ + ASSERT_EQ(http_proxy_configuration.host, https_env_proxy_server.getHost()); + ASSERT_EQ(http_proxy_configuration.port, https_env_proxy_server.getPort()); + ASSERT_EQ(http_proxy_configuration.protocol, DB::ProxyConfiguration::protocolFromString(https_env_proxy_server.getScheme())); +} + // remote resolver is tricky to be tested in unit tests diff --git a/src/Common/tests/gtest_proxy_environment_configuration.cpp b/src/Common/tests/gtest_proxy_environment_configuration.cpp index b14307d879a..6b189030b1a 100644 --- a/src/Common/tests/gtest_proxy_environment_configuration.cpp +++ b/src/Common/tests/gtest_proxy_environment_configuration.cpp @@ -57,40 +57,3 @@ TEST(EnvironmentProxyConfigurationResolver, TestHTTPsNoEnv) ASSERT_EQ(configuration.protocol, DB::ProxyConfiguration::Protocol::HTTP); ASSERT_EQ(configuration.port, 0u); } - -TEST(EnvironmentProxyConfigurationResolver, TestANYHTTP) -{ - EnvironmentProxySetter setter(http_proxy_server, {}); - - DB::EnvironmentProxyConfigurationResolver resolver(DB::ProxyConfiguration::Protocol::ANY); - - auto configuration = resolver.resolve(); - - ASSERT_EQ(configuration.host, http_proxy_server.getHost()); - ASSERT_EQ(configuration.port, http_proxy_server.getPort()); - ASSERT_EQ(configuration.protocol, DB::ProxyConfiguration::protocolFromString(http_proxy_server.getScheme())); -} - -TEST(EnvironmentProxyConfigurationResolver, TestANYHTTPS) -{ - EnvironmentProxySetter setter({}, https_proxy_server); - - DB::EnvironmentProxyConfigurationResolver resolver(DB::ProxyConfiguration::Protocol::ANY); - - auto configuration = resolver.resolve(); - - ASSERT_EQ(configuration.host, https_proxy_server.getHost()); - ASSERT_EQ(configuration.port, https_proxy_server.getPort()); - ASSERT_EQ(configuration.protocol, DB::ProxyConfiguration::protocolFromString(https_proxy_server.getScheme())); -} - -TEST(EnvironmentProxyConfigurationResolver, TestANYNoEnv) -{ - DB::EnvironmentProxyConfigurationResolver resolver(DB::ProxyConfiguration::Protocol::ANY); - - auto configuration = resolver.resolve(); - - ASSERT_EQ(configuration.host, ""); - ASSERT_EQ(configuration.protocol, DB::ProxyConfiguration::Protocol::HTTP); - ASSERT_EQ(configuration.port, 0u); -} diff --git a/src/Disks/ObjectStorages/S3/diskSettings.cpp b/src/Disks/ObjectStorages/S3/diskSettings.cpp index 3e38d0a7912..de88c876922 100644 --- a/src/Disks/ObjectStorages/S3/diskSettings.cpp +++ b/src/Disks/ObjectStorages/S3/diskSettings.cpp @@ -71,7 +71,11 @@ std::unique_ptr getClient( /* * Override proxy configuration for backwards compatibility with old configuration format. * */ - auto proxy_config = DB::ProxyConfigurationResolverProvider::getFromOldSettingsFormat(config_prefix, config); + auto proxy_config = DB::ProxyConfigurationResolverProvider::getFromOldSettingsFormat( + ProxyConfiguration::protocolFromString(uri.uri.getScheme()), + config_prefix, + config + ); if (proxy_config) { client_configuration.per_request_configuration diff --git a/tests/integration/test_s3_storage_conf_new_proxy/configs/config.d/proxy_list.xml b/tests/integration/test_s3_storage_conf_new_proxy/configs/config.d/proxy_list.xml index af5687d88ac..24c1eb29fbc 100644 --- a/tests/integration/test_s3_storage_conf_new_proxy/configs/config.d/proxy_list.xml +++ b/tests/integration/test_s3_storage_conf_new_proxy/configs/config.d/proxy_list.xml @@ -5,4 +5,4 @@ http://proxy2 - \ No newline at end of file + diff --git a/tests/integration/test_s3_storage_conf_new_proxy/proxy-resolver/resolver.py b/tests/integration/test_s3_storage_conf_new_proxy/proxy-resolver/resolver.py deleted file mode 100644 index eaea4c1dab2..00000000000 --- a/tests/integration/test_s3_storage_conf_new_proxy/proxy-resolver/resolver.py +++ /dev/null @@ -1,14 +0,0 @@ -import random - -import bottle - - -@bottle.route("/hostname") -def index(): - if random.randrange(2) == 0: - return "proxy1" - else: - return "proxy2" - - -bottle.run(host="0.0.0.0", port=8080) diff --git a/tests/integration/test_s3_table_function_with_http_proxy/configs/config.d/proxy_remote.xml b/tests/integration/test_s3_table_function_with_http_proxy/configs/config.d/proxy_remote.xml index 30d99605458..72546d49111 100644 --- a/tests/integration/test_s3_table_function_with_http_proxy/configs/config.d/proxy_remote.xml +++ b/tests/integration/test_s3_table_function_with_http_proxy/configs/config.d/proxy_remote.xml @@ -5,11 +5,13 @@ Proxy host is returned as string in response body. Then S3 client uses proxy URL formed as proxy_scheme://proxy_host:proxy_port to make request. --> - - http://resolver:8080/hostname - http - 80 - 10 - + + + http://resolver:8080/hostname + http + 80 + 10 + + diff --git a/tests/integration/test_s3_table_function_with_https_proxy/configs/config.d/proxy_remote.xml b/tests/integration/test_s3_table_function_with_https_proxy/configs/config.d/proxy_remote.xml index c0f5975224d..a310ea999d1 100644 --- a/tests/integration/test_s3_table_function_with_https_proxy/configs/config.d/proxy_remote.xml +++ b/tests/integration/test_s3_table_function_with_https_proxy/configs/config.d/proxy_remote.xml @@ -1,22 +1,12 @@ - - - http://resolver:8080/hostname - http - 80 - 10 - - - - http://resolver:8080/hostname - https - 443 - 10 - + + + http://resolver:8080/hostname + https + 443 + 10 + + diff --git a/tests/integration/test_s3_table_function_with_https_proxy/test.py b/tests/integration/test_s3_table_function_with_https_proxy/test.py index a498410a4d4..83af407093c 100644 --- a/tests/integration/test_s3_table_function_with_https_proxy/test.py +++ b/tests/integration/test_s3_table_function_with_https_proxy/test.py @@ -41,6 +41,7 @@ def cluster(): env_variables={ "https_proxy": "https://proxy1", }, + instance_env_variables=True, ) logging.info("Starting cluster...") diff --git a/utils/check-style/aspell-ignore/en/aspell-dict.txt b/utils/check-style/aspell-ignore/en/aspell-dict.txt index 3a5bd023f7d..2c73c1032f9 100644 --- a/utils/check-style/aspell-ignore/en/aspell-dict.txt +++ b/utils/check-style/aspell-ignore/en/aspell-dict.txt @@ -2147,6 +2147,7 @@ repo representable requestor requireTLSv +resolvers resharding reshards resultset