-
Notifications
You must be signed in to change notification settings - Fork 25.6k
Use client settings in repository-gcs #28575
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -116,36 +116,90 @@ PUT _snapshot/my_gcs_repository | |
| // CONSOLE | ||
| // TEST[skip:we don't have gcs setup while testing this] | ||
|
|
||
| [[repository-gcs-bucket-permission]] | ||
| ===== Set Bucket Permission | ||
| [[repository-gcs-client]] | ||
| ==== Client Settings | ||
|
|
||
| The service account used to access the bucket must have the "Writer" access to the bucket: | ||
| The client used to connect to Google Cloud Storage has a number of settings available. | ||
| Client setting names are of the form `gcs.client.CLIENT_NAME.SETTING_NAME` and specified | ||
| inside `elasticsearch.yml`. The default client name looked up by a `gcs` repository is | ||
| called `default`, but can be customized with the repository setting `client`. | ||
|
|
||
| 1. Connect to the https://console.cloud.google.com/[Google Cloud Platform Console] | ||
| 2. Select your project | ||
| 3. Got to the https://console.cloud.google.com/storage/browser[Storage Browser] | ||
| 4. Select the bucket and "Edit bucket permission" | ||
| 5. The service account must be configured as a "User" with "Writer" access | ||
| For example: | ||
|
|
||
| [source,js] | ||
| ---- | ||
| PUT _snapshot/my_gcs_repository | ||
| { | ||
| "type": "gcs", | ||
| "settings": { | ||
| "bucket": "my_bucket", | ||
| "client": "my_alternate_client" | ||
| } | ||
| } | ||
| ---- | ||
| // CONSOLE | ||
| // TEST[skip:we don't have gcs setup while testing this] | ||
|
|
||
| Some settings are sensitive and must be stored in the | ||
| {ref}/secure-settings.html[elasticsearch keystore]. This is the case for the service account file: | ||
|
|
||
| [source,sh] | ||
| ---- | ||
| bin/elasticsearch-keystore add gcs.client.default.credentials_file | ||
| bin/elasticsearch-keystore add gcs.client.default.credentials_file | ||
|
||
| ---- | ||
|
|
||
| The following are the available client settings. Those that must be stored in the keystore | ||
| are marked as `Secure`. | ||
|
|
||
| `credentials_file`:: | ||
|
|
||
| The service account file that is used to authenticate to the Google Cloud Storage service. (Secure) | ||
|
|
||
| `endpoint`:: | ||
|
|
||
| The Google Cloud Storage service endpoint to connect to. This will be automatically | ||
| determined by the Google Cloud Storage client but can be specified explicitly. | ||
|
|
||
| `connect_timeout`:: | ||
|
|
||
| The timeout to establish a connection to the Google Cloud Storage service. The value should | ||
| specify the unit. For example, a value of `5s` specifies a 5 second timeout. The value of `-1` | ||
| corresponds to an infinite timeout. The default value is 20 seconds. | ||
|
|
||
| `read_timeout`:: | ||
|
|
||
| The timeout to read data from an established connection. The value should | ||
| specify the unit. For example, a value of `5s` specifies a 5 second timeout. The value of `-1` | ||
| corresponds to an infinite timeout. The default value is 20 seconds. | ||
|
|
||
| `application_name`:: | ||
|
|
||
| Name used by the client when it uses the Google Cloud Storage service. Setting | ||
| a custom name can be useful to authenticate your cluster when requests | ||
| statistics are logged in the Google Cloud Platform. Default to `repository-gcs` | ||
|
|
||
| [[repository-gcs-repository]] | ||
| ==== Create a Repository | ||
| ==== Repository Settings | ||
|
|
||
| The `gcs` repository type supports a number of settings to customize how data | ||
| is stored in Google Cloud Storage. | ||
|
|
||
| Once everything is installed and every node is started, you can create a new repository that | ||
| uses Google Cloud Storage to store snapshots: | ||
| These can be specified when creating the repository. For example: | ||
|
|
||
| [source,js] | ||
| ---- | ||
| PUT _snapshot/my_gcs_repository | ||
| { | ||
| "type": "gcs", | ||
| "settings": { | ||
| "bucket": "my_bucket" | ||
| "bucket": "my_other_bucket", | ||
| "base_path": "dev" | ||
| } | ||
| } | ||
| ---- | ||
| // CONSOLE | ||
| // TEST[skip:we don't have gcs setup while testing this] | ||
| // TEST[skip:we don't have gcs set up while testing this] | ||
|
|
||
| The following settings are supported: | ||
|
|
||
|
|
@@ -155,8 +209,8 @@ The following settings are supported: | |
|
|
||
| `client`:: | ||
|
|
||
| The client congfiguration to use. This controls which credentials are used to connect | ||
| to Compute Engine. | ||
| The name of the client to use to connect to Google Cloud Storage. | ||
| Defaults to `default`. | ||
|
|
||
| `base_path`:: | ||
|
|
||
|
|
@@ -177,6 +231,15 @@ The following settings are supported: | |
|
|
||
| `application_name`:: | ||
|
|
||
| Name used by the plugin when it uses the Google Cloud JSON API. Setting | ||
| a custom name can be useful to authenticate your cluster when requests | ||
| statistics are logged in the Google Cloud Platform. Default to `repository-gcs` | ||
| deprecated[7.0.0, This setting is now defined in the <<repository-gcs-client, client settings>>] | ||
|
|
||
| [[repository-gcs-bucket-permission]] | ||
| ===== Recommended Bucket Permission | ||
|
|
||
| The service account used to access the bucket must have the "Writer" access to the bucket: | ||
|
|
||
| 1. Connect to the https://console.cloud.google.com/[Google Cloud Platform Console] | ||
| 2. Select your project | ||
| 3. Got to the https://console.cloud.google.com/storage/browser[Storage Browser] | ||
| 4. Select the bucket and "Edit bucket permission" | ||
| 5. The service account must be configured as a "User" with "Writer" access | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -36,7 +36,7 @@ PUT _snapshot/my_s3_repository | |
|
|
||
| The client used to connect to S3 has a number of settings available. Client setting names are of | ||
| the form `s3.client.CLIENT_NAME.SETTING_NAME` and specified inside `elasticsearch.yml`. The | ||
| default client name looked up by an s3 repository is called `default`, but can be customized | ||
| default client name looked up by a `s3` repository is called `default`, but can be customized | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe instead "The default client name used by the "s3" repository is called |
||
| with the repository setting `client`. For example: | ||
|
|
||
| [source,js] | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,3 +12,9 @@ You must set it per azure client instead. Like `azure.client.default.timeout: 10 | |
|
|
||
| See {plugins}/repository-azure-usage.html#repository-azure-repository-settings[Azure Repository settings]. | ||
|
|
||
| ==== Google Cloud Storage Repository plugin | ||
|
|
||
| * The repository settings `application_name`, `connect_timeout` and `read_timeout` have been removed and | ||
| must now be specified in the client settings instead. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. link to the docs here? |
||
|
|
||
| See {plugins}/repository-gcs-client.html#repository-gcs-client[Google Cloud Storage Client Settings]. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,173 @@ | ||
| /* | ||
| * Licensed to Elasticsearch under one or more contributor | ||
| * license agreements. See the NOTICE file distributed with | ||
| * this work for additional information regarding copyright | ||
| * ownership. Elasticsearch 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.elasticsearch.repositories.gcs; | ||
|
|
||
| import com.google.api.client.googleapis.auth.oauth2.GoogleCredential; | ||
| import com.google.api.services.storage.StorageScopes; | ||
| import org.elasticsearch.common.settings.SecureSetting; | ||
| import org.elasticsearch.common.settings.Setting; | ||
| import org.elasticsearch.common.settings.Settings; | ||
| import org.elasticsearch.common.unit.TimeValue; | ||
|
|
||
| import java.io.IOException; | ||
| import java.io.InputStream; | ||
| import java.io.UncheckedIOException; | ||
| import java.util.Collections; | ||
| import java.util.HashMap; | ||
| import java.util.Locale; | ||
| import java.util.Map; | ||
|
|
||
| import static org.elasticsearch.common.settings.Setting.timeSetting; | ||
|
|
||
| /** | ||
| * Container for Google Cloud Storage clients settings. | ||
| */ | ||
| public class GoogleCloudStorageClientSettings { | ||
|
|
||
| private static final String PREFIX = "gcs.client."; | ||
|
|
||
| /** A json Service Account file loaded from secure settings. */ | ||
| static final Setting.AffixSetting<InputStream> CREDENTIALS_FILE_SETTING = Setting.affixKeySetting(PREFIX, "credentials_file", | ||
| key -> SecureSetting.secureFile(key, null)); | ||
|
|
||
| /** An override for the Storage endpoint to connect to. */ | ||
| static final Setting.AffixSetting<String> ENDPOINT_SETTING = Setting.affixKeySetting(PREFIX, "endpoint", | ||
| key -> new Setting<>(key, "", s -> s, Setting.Property.NodeScope)); | ||
|
|
||
| /** | ||
| * The timeout to establish a connection. A value of {@code -1} corresponds to an infinite timeout. A value of {@code 0} | ||
| * corresponds to the default timeout of the Google Cloud Storage Java Library. | ||
| */ | ||
| static final Setting.AffixSetting<TimeValue> CONNECT_TIMEOUT_SETTING = Setting.affixKeySetting(PREFIX, "connect_timeout", | ||
| key -> timeSetting(key, TimeValue.ZERO, TimeValue.MINUS_ONE, Setting.Property.NodeScope)); | ||
|
|
||
| /** | ||
| * The timeout to read data from an established connection. A value of {@code -1} corresponds to an infinite timeout. A value of | ||
| * {@code 0} corresponds to the default timeout of the Google Cloud Storage Java Library. | ||
| */ | ||
| static final Setting.AffixSetting<TimeValue> READ_TIMEOUT_SETTING = Setting.affixKeySetting(PREFIX, "read_timeout", | ||
| key -> timeSetting(key, TimeValue.ZERO, TimeValue.MINUS_ONE, Setting.Property.NodeScope)); | ||
|
|
||
| /** Name used by the client when it uses the Google Cloud JSON API. **/ | ||
| static final Setting.AffixSetting<String> APPLICATION_NAME_SETTING = Setting.affixKeySetting(PREFIX, "application_name", | ||
| key -> new Setting<>(key, "repository-gcs", s -> s, Setting.Property.NodeScope)); | ||
|
|
||
| /** The credentials used by the client to connect to the Storage endpoint **/ | ||
| private final GoogleCredential credential; | ||
|
|
||
| /** The Storage root URL the client should talk to, or empty string to use the default. **/ | ||
| private final String endpoint; | ||
|
|
||
| /** The timeout to establish a connection **/ | ||
| private final TimeValue connectTimeout; | ||
|
|
||
| /** The timeout to read data from an established connection **/ | ||
| private final TimeValue readTimeout; | ||
|
|
||
| /** The Storage client application name **/ | ||
| private final String applicationName; | ||
|
|
||
| GoogleCloudStorageClientSettings(final GoogleCredential credential, | ||
| final String endpoint, | ||
| final TimeValue connectTimeout, | ||
| final TimeValue readTimeout, | ||
| final String applicationName) { | ||
| this.credential = credential; | ||
| this.endpoint = endpoint; | ||
| this.connectTimeout = connectTimeout; | ||
| this.readTimeout = readTimeout; | ||
| this.applicationName = applicationName; | ||
| } | ||
|
|
||
| public GoogleCredential getCredential() { | ||
| return credential; | ||
| } | ||
|
|
||
| public String getEndpoint() { | ||
| return endpoint; | ||
| } | ||
|
|
||
| public TimeValue getConnectTimeout() { | ||
| return connectTimeout; | ||
| } | ||
|
|
||
| public TimeValue getReadTimeout() { | ||
| return readTimeout; | ||
| } | ||
|
|
||
| public String getApplicationName() { | ||
| return applicationName; | ||
| } | ||
|
|
||
| public static Map<String, GoogleCloudStorageClientSettings> load(final Settings settings) { | ||
| final Map<String, GoogleCloudStorageClientSettings> clients = new HashMap<>(); | ||
| for (String clientName: settings.getGroups(PREFIX).keySet()) { | ||
| clients.put(clientName, getClientSettings(settings, clientName)); | ||
| } | ||
| if (clients.containsKey("default") == false) { | ||
| // this won't find any settings under the default client, | ||
| // but it will pull all the fallback static settings | ||
| clients.put("default", getClientSettings(settings, "default")); | ||
| } | ||
| return Collections.unmodifiableMap(clients); | ||
| } | ||
|
|
||
| static GoogleCloudStorageClientSettings getClientSettings(final Settings settings, final String clientName) { | ||
| return new GoogleCloudStorageClientSettings( | ||
| loadCredential(settings, clientName), | ||
| getConfigValue(settings, clientName, ENDPOINT_SETTING), | ||
| getConfigValue(settings, clientName, CONNECT_TIMEOUT_SETTING), | ||
| getConfigValue(settings, clientName, READ_TIMEOUT_SETTING), | ||
| getConfigValue(settings, clientName, APPLICATION_NAME_SETTING) | ||
| ); | ||
| } | ||
|
|
||
| /** | ||
| * Loads the service account file corresponding to a given client name. If no file is defined for the client, | ||
| * a {@code null} credential is returned. | ||
| * | ||
| * @param settings the {@link Settings} | ||
| * @param clientName the client name | ||
| * | ||
| * @return the {@link GoogleCredential} to use for the given client, {@code null} if no service account is defined. | ||
| */ | ||
| static GoogleCredential loadCredential(final Settings settings, final String clientName) { | ||
| try { | ||
| if (CREDENTIALS_FILE_SETTING.getConcreteSettingForNamespace(clientName).exists(settings) == false) { | ||
| // explicitly returning null here so that the default credential | ||
| // can be loaded later when creating the Storage client | ||
| return null; | ||
| } | ||
| try (InputStream credStream = CREDENTIALS_FILE_SETTING.getConcreteSettingForNamespace(clientName).get(settings)) { | ||
| GoogleCredential credential = GoogleCredential.fromStream(credStream); | ||
| if (credential.createScopedRequired()) { | ||
| credential = credential.createScoped(Collections.singleton(StorageScopes.DEVSTORAGE_FULL_CONTROL)); | ||
| } | ||
| return credential; | ||
| } | ||
| } catch (IOException e) { | ||
| throw new UncheckedIOException(e); | ||
| } | ||
| } | ||
|
|
||
| private static <T> T getConfigValue(final Settings settings, final String clientName, final Setting.AffixSetting<T> clientSetting) { | ||
| Setting<T> concreteSetting = clientSetting.getConcreteSettingForNamespace(clientName); | ||
| return concreteSetting.get(settings); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,15 +19,8 @@ | |
|
|
||
| package org.elasticsearch.repositories.gcs; | ||
|
|
||
| import java.security.AccessController; | ||
| import java.security.PrivilegedAction; | ||
| import java.util.Collections; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
|
|
||
| import com.google.api.client.auth.oauth2.TokenRequest; | ||
| import com.google.api.client.auth.oauth2.TokenResponse; | ||
| import com.google.api.client.googleapis.auth.oauth2.GoogleCredential; | ||
| import com.google.api.client.googleapis.json.GoogleJsonError; | ||
| import com.google.api.client.http.GenericUrl; | ||
| import com.google.api.client.http.HttpHeaders; | ||
|
|
@@ -48,12 +41,15 @@ | |
| import org.elasticsearch.plugins.Plugin; | ||
| import org.elasticsearch.plugins.RepositoryPlugin; | ||
| import org.elasticsearch.repositories.Repository; | ||
| import org.elasticsearch.repositories.gcs.GoogleCloudStorageRepository; | ||
| import org.elasticsearch.repositories.gcs.GoogleCloudStorageService; | ||
|
|
||
| public class GoogleCloudStoragePlugin extends Plugin implements RepositoryPlugin { | ||
| import java.security.AccessController; | ||
| import java.security.PrivilegedAction; | ||
| import java.util.Arrays; | ||
| import java.util.Collections; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
|
|
||
| public static final String NAME = "repository-gcs"; | ||
| public class GoogleCloudStoragePlugin extends Plugin implements RepositoryPlugin { | ||
|
|
||
| static { | ||
| /* | ||
|
|
@@ -112,15 +108,19 @@ public class GoogleCloudStoragePlugin extends Plugin implements RepositoryPlugin | |
| }); | ||
| } | ||
|
|
||
| private final Map<String, GoogleCredential> credentials; | ||
| private final Map<String, GoogleCloudStorageClientSettings> clientsSettings; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. clientsSettings -> clientSettings?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There can be multiple client settings keyed by their name so I chose the plural form :) |
||
|
|
||
| public GoogleCloudStoragePlugin(final Settings settings) { | ||
| clientsSettings = GoogleCloudStorageClientSettings.load(settings); | ||
| } | ||
|
|
||
| public GoogleCloudStoragePlugin(Settings settings) { | ||
| credentials = GoogleCloudStorageService.loadClientCredentials(settings); | ||
| protected Map<String, GoogleCloudStorageClientSettings> getClientsSettings() { | ||
| return clientsSettings; | ||
| } | ||
|
|
||
| // overridable for tests | ||
| protected GoogleCloudStorageService createStorageService(Environment environment) { | ||
| return new GoogleCloudStorageService.InternalGoogleCloudStorageService(environment, credentials); | ||
| return new GoogleCloudStorageService(environment, clientsSettings); | ||
| } | ||
|
|
||
| @Override | ||
|
|
@@ -131,6 +131,11 @@ public Map<String, Repository.Factory> getRepositories(Environment env, NamedXCo | |
|
|
||
| @Override | ||
| public List<Setting<?>> getSettings() { | ||
| return Collections.singletonList(GoogleCloudStorageService.CREDENTIALS_FILE_SETTING); | ||
| return Arrays.asList( | ||
| GoogleCloudStorageClientSettings.CREDENTIALS_FILE_SETTING, | ||
| GoogleCloudStorageClientSettings.ENDPOINT_SETTING, | ||
| GoogleCloudStorageClientSettings.CONNECT_TIMEOUT_SETTING, | ||
| GoogleCloudStorageClientSettings.READ_TIMEOUT_SETTING, | ||
| GoogleCloudStorageClientSettings.APPLICATION_NAME_SETTING); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The subcommand is
add-file, notadd.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch