blob: 0e364d0afb5c8008675b311dc4cb966e5c09d35d [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
package org.apache.solr.gcs;
import com.google.api.gax.retrying.RetrySettings;
import com.google.cloud.storage.StorageOptions;
import org.apache.solr.common.util.NamedList;
import org.threeten.bp.Duration;
import java.util.Map;
/**
* Parses configuration for {@link GCSBackupRepository} from NamedList and environment variables
*/
public class GCSConfigParser {
private static final String GCS_BUCKET_ENV_VAR_NAME = "GCS_BUCKET";
private static final String GCS_CREDENTIAL_ENV_VAR_NAME = "GCS_CREDENTIAL_PATH";
private static final String GCS_BUCKET_PARAM_NAME = "gcsBucket";
private static final String GCS_CREDENTIAL_PARAM_NAME = "gcsCredentialPath";
private static final String GCS_WRITE_BUFFER_SIZE_PARAM_NAME = "gcsWriteBufferSizeBytes";
private static final String GCS_READ_BUFFER_SIZE_PARAM_NAME = "gcsReadBufferSizeBytes";
private static final String HTTP_CONNECT_TIMEOUT_MILLIS_NAME = "gcsClientHttpConnectTimeoutMillis";
private static final String HTTP_READ_TIMEOUT_MILLIS_NAME = "gcsClientHttpReadTimeoutMillis";
private static final String MAX_REQUEST_RETRIES_NAME = "gcsClientMaxRetries";
private static final String TOTAL_TIMEOUT_MILLIS_NAME = "gcsClientMaxRequestTimeoutMillis";
private static final String HTTP_INITIAL_RETRY_DELAY_MILLIS_NAME = "gcsClientHttpInitialRetryDelayMillis";
private static final String HTTP_SUBSEQUENT_RETRY_DELAY_MULTIPLIER_NAME = "gcsClientHttpRetryDelayMultiplier";
private static final String HTTP_MAX_RETRY_DELAY_MILLIS_NAME = "gcsClientHttpMaxRetryDelayMillis";
private static final String RPC_INITIAL_TIMEOUT_MILLIS_NAME = "gcsClientRpcInitialTimeoutMillis";
private static final String RPC_SUBSEQUENT_TIMEOUT_MULTIPLIER_NAME = "gcsClientRpcTimeoutMultiplier";
private static final String RPC_MAX_TIMEOUT_MILLIS_NAME = "gcsClientRpcMaxTimeoutMillis";
private static final String DEFAULT_GCS_BUCKET_VALUE = "solrBackupsBucket";
private static final int DEFAULT_GCS_WRITE_BUFFER_SIZE_VALUE = 16 * 1024 * 1024;
private static final int DEFAULT_GCS_READ_BUFFER_SIZE_VALUE = 2 * 1024 * 1024;
private static final int DEFAULT_HTTP_CONNECT_TIMEOUT_MILLIS = 20000;
private static final int DEFAULT_HTTP_READ_TIMEOUT_MILLIS = 20000;
private static final int DEFAULT_MAX_RETRIES = 10;
private static final int DEFAULT_TOTAL_TIMEOUT_MILLIS = 300000;
private static final int DEFAULT_HTTP_INITIAL_RETRY_DELAY_MILLIS = 1000;
private static final int DEFAULT_HTTP_MAX_RETRY_DELAY_MILLIS = 30000;
private static final double DEFAULT_HTTP_SUBSEQUENT_RETRY_DELAY_MULTIPLIER = 1.0;
private static final int DEFAULT_RPC_INITIAL_TIMEOUT_MILLIS = 10000;
private static final int DEFAULT_RPC_MAX_TIMEOUT_MILLIS = 30000;
private static final double DEFAULT_RPC_SUBSEQUENT_TIMEOUT_MULTIPLIER = 1.0;
public GCSConfig parseConfiguration(NamedList<Object> repositoryConfig) {
return parseConfiguration(repositoryConfig, System.getenv());
}
public GCSConfig parseConfiguration(NamedList<Object> repoConfig, Map<String, String> envVars) {
final String bucketName = parseBucket(repoConfig, envVars);
final String credentialPathStr = parseCredentialPath(repoConfig, envVars);
final int writeBufferSizeBytes = getIntOrDefault(repoConfig, GCS_WRITE_BUFFER_SIZE_PARAM_NAME, DEFAULT_GCS_WRITE_BUFFER_SIZE_VALUE);
final int readBufferSizeBytes = getIntOrDefault(repoConfig, GCS_READ_BUFFER_SIZE_PARAM_NAME, DEFAULT_GCS_READ_BUFFER_SIZE_VALUE);
final StorageOptions.Builder storageOptionsBuilder = parseStorageOptions(repoConfig);
return new GCSConfig(bucketName, credentialPathStr, writeBufferSizeBytes, readBufferSizeBytes, storageOptionsBuilder);
}
/*
* The GCS bucket name is retrieved from the NL 'bucket' key, or the 'GCS_BUCKET' env-var, or the value
* 'solrBackupsBucket' is used (in that order).
*/
private String parseBucket(NamedList<Object> repoConfig, Map<String, String> envVars) {
if (repoConfig.get(GCS_BUCKET_PARAM_NAME) != null) {
return repoConfig.get(GCS_BUCKET_PARAM_NAME).toString();
}
return envVars.getOrDefault(GCS_BUCKET_ENV_VAR_NAME, DEFAULT_GCS_BUCKET_VALUE);
}
private String parseCredentialPath(NamedList<Object> repoConfig, Map<String, String> envVars) {
if (repoConfig.get(GCS_CREDENTIAL_PARAM_NAME) != null) {
return repoConfig.get(GCS_CREDENTIAL_PARAM_NAME).toString();
}
return envVars.get(GCS_CREDENTIAL_ENV_VAR_NAME);
}
public static String missingCredentialErrorMsg() {
return "GCSBackupRepository requires a credential for GCS communication, but none was provided. Please specify a " +
"path to this GCS credential by adding a '" + GCS_CREDENTIAL_PARAM_NAME + "' property to the repository " +
"definition in your solrconfig, or by setting the path value in an env-var named '" +
GCS_CREDENTIAL_ENV_VAR_NAME + "'";
}
private int getIntOrDefault(NamedList<Object> config, String propName, int defaultValue) {
if (config.get(propName) != null) {
return Integer.parseInt(config.get(propName).toString());
}
return defaultValue;
}
private double getDoubleOrDefault(NamedList<Object> config, String propName, double defaultValue) {
if (config.get(propName) != null) {
return Double.parseDouble(config.get(propName).toString());
}
return defaultValue;
}
private StorageOptions.Builder parseStorageOptions(NamedList<Object> repoConfig) {
final StorageOptions.Builder builder = StorageOptions.newBuilder();
builder.setTransportOptions(StorageOptions.getDefaultHttpTransportOptions().toBuilder()
.setConnectTimeout(getIntOrDefault(repoConfig, HTTP_CONNECT_TIMEOUT_MILLIS_NAME, DEFAULT_HTTP_CONNECT_TIMEOUT_MILLIS))
.setReadTimeout(getIntOrDefault(repoConfig, HTTP_READ_TIMEOUT_MILLIS_NAME, DEFAULT_HTTP_READ_TIMEOUT_MILLIS))
.build());
builder.setRetrySettings(RetrySettings.newBuilder()
// All retries
.setMaxAttempts(getIntOrDefault(repoConfig, MAX_REQUEST_RETRIES_NAME, DEFAULT_MAX_RETRIES))
.setTotalTimeout(Duration.ofMillis(getIntOrDefault(repoConfig, TOTAL_TIMEOUT_MILLIS_NAME, DEFAULT_TOTAL_TIMEOUT_MILLIS)))
//http requests
.setInitialRetryDelay(Duration.ofMillis(getIntOrDefault(repoConfig, HTTP_INITIAL_RETRY_DELAY_MILLIS_NAME, DEFAULT_HTTP_INITIAL_RETRY_DELAY_MILLIS)))
.setMaxRetryDelay(Duration.ofMillis(getIntOrDefault(repoConfig, HTTP_MAX_RETRY_DELAY_MILLIS_NAME, DEFAULT_HTTP_MAX_RETRY_DELAY_MILLIS)))
.setRetryDelayMultiplier(getDoubleOrDefault(repoConfig, HTTP_SUBSEQUENT_RETRY_DELAY_MULTIPLIER_NAME, DEFAULT_HTTP_SUBSEQUENT_RETRY_DELAY_MULTIPLIER))
//rpc requests
.setInitialRpcTimeout(Duration.ofMillis(getIntOrDefault(repoConfig, RPC_INITIAL_TIMEOUT_MILLIS_NAME, DEFAULT_RPC_INITIAL_TIMEOUT_MILLIS)))
.setMaxRpcTimeout(Duration.ofMillis(getIntOrDefault(repoConfig, RPC_MAX_TIMEOUT_MILLIS_NAME, DEFAULT_RPC_MAX_TIMEOUT_MILLIS)))
.setRpcTimeoutMultiplier(getDoubleOrDefault(repoConfig, RPC_SUBSEQUENT_TIMEOUT_MULTIPLIER_NAME, DEFAULT_RPC_SUBSEQUENT_TIMEOUT_MULTIPLIER))
.build());
return builder;
}
public static class GCSConfig {
private final StorageOptions.Builder optionsBuilder;
private final String bucketName;
private final String gcsCredentialPath;
private final int writeBufferSizeBytes;
private final int readBufferSizeBytes;
public GCSConfig(String bucketName, String gcsCredentialPath, int writeBufferSizeBytes, int readBufferSizeBytes, StorageOptions.Builder optionsBuilder) {
this.bucketName = bucketName;
this.gcsCredentialPath = gcsCredentialPath;
this.writeBufferSizeBytes = writeBufferSizeBytes;
this.readBufferSizeBytes = readBufferSizeBytes;
this.optionsBuilder = optionsBuilder;
}
public StorageOptions.Builder getStorageOptionsBuilder() {
return optionsBuilder;
}
public String getBucketName() {
return bucketName;
}
public String getCredentialPath() {
return gcsCredentialPath;
}
public int getWriteBufferSize() {
return writeBufferSizeBytes;
}
public int getReadBufferSize() {
return readBufferSizeBytes;
}
}
}