diff --git a/tiledb/sm/filesystem/azure.cc b/tiledb/sm/filesystem/azure.cc index ea461f24b40..e2402b3e8ee 100644 --- a/tiledb/sm/filesystem/azure.cc +++ b/tiledb/sm/filesystem/azure.cc @@ -79,7 +79,7 @@ std::string get_config_with_env_fallback( return result; } -std::string get_blob_endpoint( +std::optional get_blob_endpoint( const Config& config, const std::string& account_name) { std::string sas_token = get_config_with_env_fallback( config, "vfs.azure.storage_sas_token", "AZURE_STORAGE_SAS_TOKEN"); @@ -90,9 +90,7 @@ std::string get_blob_endpoint( if (!account_name.empty()) { result = "https://" + account_name + ".blob.core.windows.net"; } else { - LOG_WARN( - "Neither the 'vfs.azure.storage_account_name' nor the " - "'vfs.azure.blob_endpoint' options are specified."); + return std::nullopt; } } else if (!(utils::parse::starts_with(result, "http://") || utils::parse::starts_with(result, "https://"))) { @@ -124,7 +122,20 @@ static bool has_sas_token(const Config& config) { return !sas_token.empty(); } -AzureParameters::AzureParameters(const Config& config) +std::optional AzureParameters::create(const Config& config) { + auto account_name = get_config_with_env_fallback( + config, "vfs.azure.storage_account_name", "AZURE_STORAGE_ACCOUNT"); + auto blob_endpoint = get_blob_endpoint(config, account_name); + if (!blob_endpoint) { + return std::nullopt; + } + return AzureParameters{config, account_name, *blob_endpoint}; +} + +AzureParameters::AzureParameters( + const Config& config, + const std::string& account_name, + const std::string& blob_endpoint) : max_parallel_ops_( config.get("vfs.azure.max_parallel_ops", Config::must_find)) , block_list_block_size_(config.get( @@ -138,11 +149,10 @@ AzureParameters::AzureParameters(const Config& config) "vfs.azure.max_retry_delay_ms", Config::must_find))) , use_block_list_upload_(config.get( "vfs.azure.use_block_list_upload", Config::must_find)) - , account_name_(get_config_with_env_fallback( - config, "vfs.azure.storage_account_name", "AZURE_STORAGE_ACCOUNT")) + , account_name_(account_name) , account_key_(get_config_with_env_fallback( config, "vfs.azure.storage_account_key", "AZURE_STORAGE_KEY")) - , blob_endpoint_(get_blob_endpoint(config, account_name_)) + , blob_endpoint_(blob_endpoint) , ssl_cfg_(config) , has_sas_token_(has_sas_token(config)) { } @@ -153,7 +163,7 @@ Status Azure::init(const Config& config, ThreadPool* const thread_pool) { Status_AzureError("Can't initialize with null thread pool.")); } thread_pool_ = thread_pool; - azure_params_ = config; + azure_params_ = AzureParameters::create(config); return Status::Ok(); } diff --git a/tiledb/sm/filesystem/azure.h b/tiledb/sm/filesystem/azure.h index fdd059947b9..489ac581e4a 100644 --- a/tiledb/sm/filesystem/azure.h +++ b/tiledb/sm/filesystem/azure.h @@ -70,7 +70,13 @@ namespace sm { struct AzureParameters { AzureParameters() = delete; - AzureParameters(const Config& config); + /** + * Creates an AzureParameters object. + * + * @return AzureParameters or nullopt if config does not have + * a storage account or blob endpoint set. + */ + static std::optional create(const Config& config); /** The maximum number of parallel requests. */ uint64_t max_parallel_ops_; @@ -107,6 +113,12 @@ struct AzureParameters { /** Whether the config specifies a SAS token. */ bool has_sas_token_; + + private: + AzureParameters( + const Config& config, + const std::string& account_name, + const std::string& blob_endpoint); }; class Azure { @@ -362,7 +374,21 @@ class Azure { * use of the BlobServiceClient. */ const ::Azure::Storage::Blobs::BlobServiceClient& client() const { - assert(azure_params_); + // This branch can be entered in two circumstances: + // 1. The init method has not been called yet. + // 2. The init method has been called, but the config (or environment + // variables) do not contain enough information to get the Azure + // endpoint. + // We don't distinguish between the two, because only the latter can + // happen under normal circumstances, and the former is a C.41 issue + // that will go away once the class is C.41 compliant. + if (!azure_params_) { + throw StatusException(Status_AzureError( + "Azure VFS is not configured. Please set the " + "'vfs.azure.storage_account_name' and/or " + "'vfs.azure.blob_endpoint' configuration options.")); + } + return client_singleton_.get(*azure_params_); }