Skip to content

Commit f150e2c

Browse files
authored
Add telemetry for repository usage (#112133)
Adds to the `GET _cluster/stats` endpoint information about the snapshot repositories in use, including their types, whether they are read-only or read-write, and for Azure repositories the kind of credentials in use.
1 parent fb32adc commit f150e2c

File tree

27 files changed

+400
-37
lines changed

27 files changed

+400
-37
lines changed

docs/changelog/112133.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pr: 112133
2+
summary: Add telemetry for repository usage
3+
area: Snapshot/Restore
4+
type: enhancement
5+
issues: []

docs/reference/cluster/stats.asciidoc

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1282,6 +1282,31 @@ They are included here for expert users, but should otherwise be ignored.
12821282
12831283
=====
12841284

1285+
====
1286+
1287+
`repositories`::
1288+
(object) Contains statistics about the <<snapshot-restore,snapshot>> repositories defined in the cluster, broken down
1289+
by repository type.
1290+
+
1291+
.Properties of `repositories`
1292+
[%collapsible%open]
1293+
=====
1294+
1295+
`count`:::
1296+
(integer) The number of repositories of this type in the cluster.
1297+
1298+
`read_only`:::
1299+
(integer) The number of repositories of this type in the cluster which are registered read-only.
1300+
1301+
`read_write`:::
1302+
(integer) The number of repositories of this type in the cluster which are not registered as read-only.
1303+
1304+
Each repository type may also include other statistics about the repositories of that type here.
1305+
1306+
=====
1307+
1308+
====
1309+
12851310
[[cluster-stats-api-example]]
12861311
==== {api-examples-title}
12871312

@@ -1579,6 +1604,9 @@ The API returns the following response:
15791604
},
15801605
"snapshots": {
15811606
...
1607+
},
1608+
"repositories": {
1609+
...
15821610
}
15831611
}
15841612
--------------------------------------------------
@@ -1589,6 +1617,7 @@ The API returns the following response:
15891617
// TESTRESPONSE[s/"count": \{[^\}]*\}/"count": $body.$_path/]
15901618
// TESTRESPONSE[s/"packaging_types": \[[^\]]*\]/"packaging_types": $body.$_path/]
15911619
// TESTRESPONSE[s/"snapshots": \{[^\}]*\}/"snapshots": $body.$_path/]
1620+
// TESTRESPONSE[s/"repositories": \{[^\}]*\}/"repositories": $body.$_path/]
15921621
// TESTRESPONSE[s/"field_types": \[[^\]]*\]/"field_types": $body.$_path/]
15931622
// TESTRESPONSE[s/"runtime_field_types": \[[^\]]*\]/"runtime_field_types": $body.$_path/]
15941623
// TESTRESPONSE[s/"search": \{[^\}]*\}/"search": $body.$_path/]
@@ -1600,7 +1629,7 @@ The API returns the following response:
16001629
// the plugins that will be in it. And because we figure folks don't need to
16011630
// see an exhaustive list anyway.
16021631
// 2. Similarly, ignore the contents of `network_types`, `discovery_types`,
1603-
// `packaging_types` and `snapshots`.
1632+
// `packaging_types`, `snapshots` and `repositories`.
16041633
// 3. Ignore the contents of the (nodes) count object, as what's shown here
16051634
// depends on the license. Voting-only nodes are e.g. only shown when this
16061635
// test runs with a basic license.

modules/repository-azure/src/main/java/org/elasticsearch/repositories/azure/AzureRepository.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
import java.util.Locale;
2828
import java.util.Map;
29+
import java.util.Set;
2930
import java.util.function.Function;
3031

3132
import static org.elasticsearch.core.Strings.format;
@@ -175,4 +176,9 @@ protected ByteSizeValue chunkSize() {
175176
public boolean isReadOnly() {
176177
return readonly;
177178
}
179+
180+
@Override
181+
protected Set<String> getExtraUsageFeatures() {
182+
return storageService.getExtraUsageFeatures(Repository.CLIENT_NAME.get(getMetadata().settings()));
183+
}
178184
}

modules/repository-azure/src/main/java/org/elasticsearch/repositories/azure/AzureStorageService.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.net.Proxy;
2525
import java.net.URL;
2626
import java.util.Map;
27+
import java.util.Set;
2728
import java.util.function.BiConsumer;
2829

2930
import static java.util.Collections.emptyMap;
@@ -165,4 +166,15 @@ public void refreshSettings(Map<String, AzureStorageSettings> clientsSettings) {
165166
this.storageSettings = Map.copyOf(clientsSettings);
166167
// clients are built lazily by {@link client(String, LocationMode)}
167168
}
169+
170+
/**
171+
* For Azure repositories, we report the different kinds of credentials in use in the telemetry.
172+
*/
173+
public Set<String> getExtraUsageFeatures(String clientName) {
174+
try {
175+
return getClientSettings(clientName).credentialsUsageFeatures();
176+
} catch (Exception e) {
177+
return Set.of();
178+
}
179+
}
168180
}

modules/repository-azure/src/main/java/org/elasticsearch/repositories/azure/AzureStorageSettings.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import java.util.HashMap;
3030
import java.util.Locale;
3131
import java.util.Map;
32+
import java.util.Set;
3233

3334
final class AzureStorageSettings {
3435

@@ -130,6 +131,7 @@ final class AzureStorageSettings {
130131
private final int maxRetries;
131132
private final Proxy proxy;
132133
private final boolean hasCredentials;
134+
private final Set<String> credentialsUsageFeatures;
133135

134136
private AzureStorageSettings(
135137
String account,
@@ -150,6 +152,12 @@ private AzureStorageSettings(
150152
this.endpointSuffix = endpointSuffix;
151153
this.timeout = timeout;
152154
this.maxRetries = maxRetries;
155+
this.credentialsUsageFeatures = Strings.hasText(key) ? Set.of("uses_key_credentials")
156+
: Strings.hasText(sasToken) ? Set.of("uses_sas_token")
157+
: SocketAccess.doPrivilegedException(() -> System.getenv("AZURE_FEDERATED_TOKEN_FILE")) == null
158+
? Set.of("uses_default_credentials", "uses_managed_identity")
159+
: Set.of("uses_default_credentials", "uses_workload_identity");
160+
153161
// Register the proxy if we have any
154162
// Validate proxy settings
155163
if (proxyType.equals(Proxy.Type.DIRECT) && ((proxyPort != 0) || Strings.hasText(proxyHost))) {
@@ -366,4 +374,8 @@ private String deriveURIFromSettings(boolean isPrimary) {
366374
throw new IllegalArgumentException(e);
367375
}
368376
}
377+
378+
public Set<String> credentialsUsageFeatures() {
379+
return credentialsUsageFeatures;
380+
}
369381
}

modules/repository-azure/src/yamlRestTest/resources/rest-api-spec/test/repository_azure/20_repository.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,19 @@ setup:
235235
snapshot: missing
236236
wait_for_completion: true
237237

238+
---
239+
"Usage stats":
240+
- requires:
241+
cluster_features:
242+
- repositories.supports_usage_stats
243+
reason: requires this feature
244+
245+
- do:
246+
cluster.stats: {}
247+
248+
- gte: { repositories.azure.count: 1 }
249+
- gte: { repositories.azure.read_write: 1 }
250+
238251
---
239252
teardown:
240253

modules/repository-gcs/src/yamlRestTest/resources/rest-api-spec/test/repository_gcs/20_repository.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,19 @@ setup:
232232
snapshot: missing
233233
wait_for_completion: true
234234

235+
---
236+
"Usage stats":
237+
- requires:
238+
cluster_features:
239+
- repositories.supports_usage_stats
240+
reason: requires this feature
241+
242+
- do:
243+
cluster.stats: {}
244+
245+
- gte: { repositories.gcs.count: 1 }
246+
- gte: { repositories.gcs.read_write: 1 }
247+
235248
---
236249
teardown:
237250

modules/repository-s3/src/yamlRestTest/resources/rest-api-spec/test/repository_s3/20_repository_permanent_credentials.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,19 @@ setup:
345345
snapshot: missing
346346
wait_for_completion: true
347347

348+
---
349+
"Usage stats":
350+
- requires:
351+
cluster_features:
352+
- repositories.supports_usage_stats
353+
reason: requires this feature
354+
355+
- do:
356+
cluster.stats: {}
357+
358+
- gte: { repositories.s3.count: 1 }
359+
- gte: { repositories.s3.read_write: 1 }
360+
348361
---
349362
teardown:
350363

modules/repository-s3/src/yamlRestTest/resources/rest-api-spec/test/repository_s3/30_repository_temporary_credentials.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,19 @@ setup:
256256
snapshot: missing
257257
wait_for_completion: true
258258

259+
---
260+
"Usage stats":
261+
- requires:
262+
cluster_features:
263+
- repositories.supports_usage_stats
264+
reason: requires this feature
265+
266+
- do:
267+
cluster.stats: {}
268+
269+
- gte: { repositories.s3.count: 1 }
270+
- gte: { repositories.s3.read_write: 1 }
271+
259272
---
260273
teardown:
261274

modules/repository-s3/src/yamlRestTest/resources/rest-api-spec/test/repository_s3/40_repository_ec2_credentials.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,19 @@ setup:
256256
snapshot: missing
257257
wait_for_completion: true
258258

259+
---
260+
"Usage stats":
261+
- requires:
262+
cluster_features:
263+
- repositories.supports_usage_stats
264+
reason: requires this feature
265+
266+
- do:
267+
cluster.stats: {}
268+
269+
- gte: { repositories.s3.count: 1 }
270+
- gte: { repositories.s3.read_write: 1 }
271+
259272
---
260273
teardown:
261274

0 commit comments

Comments
 (0)