Add an API for exporting activity log data (#15586)

* Add an API for exporting activity log data

* Add changelog entry

* Switch to error logs
This commit is contained in:
Brian Kassouf 2022-05-24 17:00:46 -07:00 committed by GitHub
parent 6d668aa60a
commit df8ae055be
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 779 additions and 13 deletions

3
changelog/15586.txt Normal file
View File

@ -0,0 +1,3 @@
```release-note:improvement
core: Add an export API for historical activity log data
```

View File

@ -88,6 +88,8 @@ func buildLogicalRequestNoAuth(perfStandby bool, w http.ResponseWriter, r *http.
responseWriter = w responseWriter = w
case path == "sys/storage/raft/snapshot": case path == "sys/storage/raft/snapshot":
responseWriter = w responseWriter = w
case path == "sys/internal/counters/activity/export":
responseWriter = w
case path == "sys/monitor": case path == "sys/monitor":
passHTTPReq = true passHTTPReq = true
responseWriter = w responseWriter = w

View File

@ -0,0 +1,21 @@
client_id,namespace_id,timestamp,non_entity,mount_accessor
111122222-3333-4444-5555-000000000000,root,1,false,auth_1
111122222-3333-4444-5555-000000000001,root,1,false,auth_1
111122222-3333-4444-5555-000000000002,root,1,false,auth_1
111122222-3333-4444-5555-000000000003,root,1,false,auth_1
111122222-3333-4444-5555-000000000004,root,1,false,auth_1
111122222-3333-4444-5555-000000000005,aaaaa,1,false,auth_2
111122222-3333-4444-5555-000000000006,aaaaa,1,false,auth_2
111122222-3333-4444-5555-000000000007,aaaaa,1,false,auth_2
111122222-3333-4444-5555-000000000008,aaaaa,1,false,auth_2
111122222-3333-4444-5555-000000000009,aaaaa,1,false,auth_2
111122222-3333-4444-5555-000000000010,bbbbb,1,false,auth_3
111122222-3333-4444-5555-000000000011,bbbbb,1,false,auth_3
111122222-3333-4444-5555-000000000012,bbbbb,1,false,auth_3
111122222-3333-4444-5555-000000000013,bbbbb,2,false,auth_3
111122222-3333-4444-5555-000000000014,bbbbb,2,false,auth_3
111122222-3333-4444-5555-000000000015,root,2,false,auth_4
111122222-3333-4444-5555-000000000016,root,2,false,auth_4
111122222-3333-4444-5555-000000000017,root,2,false,auth_4
111122222-3333-4444-5555-000000000018,root,2,false,auth_4
111122222-3333-4444-5555-000000000019,root,2,false,auth_4
1 client_id namespace_id timestamp non_entity mount_accessor
2 111122222-3333-4444-5555-000000000000 root 1 false auth_1
3 111122222-3333-4444-5555-000000000001 root 1 false auth_1
4 111122222-3333-4444-5555-000000000002 root 1 false auth_1
5 111122222-3333-4444-5555-000000000003 root 1 false auth_1
6 111122222-3333-4444-5555-000000000004 root 1 false auth_1
7 111122222-3333-4444-5555-000000000005 aaaaa 1 false auth_2
8 111122222-3333-4444-5555-000000000006 aaaaa 1 false auth_2
9 111122222-3333-4444-5555-000000000007 aaaaa 1 false auth_2
10 111122222-3333-4444-5555-000000000008 aaaaa 1 false auth_2
11 111122222-3333-4444-5555-000000000009 aaaaa 1 false auth_2
12 111122222-3333-4444-5555-000000000010 bbbbb 1 false auth_3
13 111122222-3333-4444-5555-000000000011 bbbbb 1 false auth_3
14 111122222-3333-4444-5555-000000000012 bbbbb 1 false auth_3
15 111122222-3333-4444-5555-000000000013 bbbbb 2 false auth_3
16 111122222-3333-4444-5555-000000000014 bbbbb 2 false auth_3
17 111122222-3333-4444-5555-000000000015 root 2 false auth_4
18 111122222-3333-4444-5555-000000000016 root 2 false auth_4
19 111122222-3333-4444-5555-000000000017 root 2 false auth_4
20 111122222-3333-4444-5555-000000000018 root 2 false auth_4
21 111122222-3333-4444-5555-000000000019 root 2 false auth_4

View File

@ -0,0 +1,20 @@
{"client_id":"111122222-3333-4444-5555-000000000000","namespace_id":"root","timestamp":1,"mount_accessor":"auth_1"}
{"client_id":"111122222-3333-4444-5555-000000000001","namespace_id":"root","timestamp":1,"mount_accessor":"auth_1"}
{"client_id":"111122222-3333-4444-5555-000000000002","namespace_id":"root","timestamp":1,"mount_accessor":"auth_1"}
{"client_id":"111122222-3333-4444-5555-000000000003","namespace_id":"root","timestamp":1,"mount_accessor":"auth_1"}
{"client_id":"111122222-3333-4444-5555-000000000004","namespace_id":"root","timestamp":1,"mount_accessor":"auth_1"}
{"client_id":"111122222-3333-4444-5555-000000000005","namespace_id":"aaaaa","timestamp":1,"mount_accessor":"auth_2"}
{"client_id":"111122222-3333-4444-5555-000000000006","namespace_id":"aaaaa","timestamp":1,"mount_accessor":"auth_2"}
{"client_id":"111122222-3333-4444-5555-000000000007","namespace_id":"aaaaa","timestamp":1,"mount_accessor":"auth_2"}
{"client_id":"111122222-3333-4444-5555-000000000008","namespace_id":"aaaaa","timestamp":1,"mount_accessor":"auth_2"}
{"client_id":"111122222-3333-4444-5555-000000000009","namespace_id":"aaaaa","timestamp":1,"mount_accessor":"auth_2"}
{"client_id":"111122222-3333-4444-5555-000000000010","namespace_id":"bbbbb","timestamp":1,"mount_accessor":"auth_3"}
{"client_id":"111122222-3333-4444-5555-000000000011","namespace_id":"bbbbb","timestamp":1,"mount_accessor":"auth_3"}
{"client_id":"111122222-3333-4444-5555-000000000012","namespace_id":"bbbbb","timestamp":1,"mount_accessor":"auth_3"}
{"client_id":"111122222-3333-4444-5555-000000000013","namespace_id":"bbbbb","timestamp":2,"mount_accessor":"auth_3"}
{"client_id":"111122222-3333-4444-5555-000000000014","namespace_id":"bbbbb","timestamp":2,"mount_accessor":"auth_3"}
{"client_id":"111122222-3333-4444-5555-000000000015","namespace_id":"root","timestamp":2,"mount_accessor":"auth_4"}
{"client_id":"111122222-3333-4444-5555-000000000016","namespace_id":"root","timestamp":2,"mount_accessor":"auth_4"}
{"client_id":"111122222-3333-4444-5555-000000000017","namespace_id":"root","timestamp":2,"mount_accessor":"auth_4"}
{"client_id":"111122222-3333-4444-5555-000000000018","namespace_id":"root","timestamp":2,"mount_accessor":"auth_4"}
{"client_id":"111122222-3333-4444-5555-000000000019","namespace_id":"root","timestamp":2,"mount_accessor":"auth_4"}

View File

@ -0,0 +1,41 @@
client_id,namespace_id,timestamp,non_entity,mount_accessor
111122222-3333-4444-5555-000000000000,root,1,false,auth_1
111122222-3333-4444-5555-000000000001,root,1,false,auth_1
111122222-3333-4444-5555-000000000002,root,1,false,auth_1
111122222-3333-4444-5555-000000000003,root,1,false,auth_1
111122222-3333-4444-5555-000000000004,root,1,false,auth_1
111122222-3333-4444-5555-000000000005,aaaaa,1,false,auth_2
111122222-3333-4444-5555-000000000006,aaaaa,1,false,auth_2
111122222-3333-4444-5555-000000000007,aaaaa,1,false,auth_2
111122222-3333-4444-5555-000000000008,aaaaa,1,false,auth_2
111122222-3333-4444-5555-000000000009,aaaaa,1,false,auth_2
111122222-3333-4444-5555-000000000010,bbbbb,1,false,auth_3
111122222-3333-4444-5555-000000000011,bbbbb,1,false,auth_3
111122222-3333-4444-5555-000000000012,bbbbb,1,false,auth_3
111122222-3333-4444-5555-000000000013,bbbbb,2,false,auth_3
111122222-3333-4444-5555-000000000014,bbbbb,2,false,auth_3
111122222-3333-4444-5555-000000000015,root,2,false,auth_4
111122222-3333-4444-5555-000000000016,root,2,false,auth_4
111122222-3333-4444-5555-000000000017,root,2,false,auth_4
111122222-3333-4444-5555-000000000018,root,2,false,auth_4
111122222-3333-4444-5555-000000000019,root,2,false,auth_4
111122222-3333-4444-5555-000000000020,root,3,false,auth_5
111122222-3333-4444-5555-000000000021,root,3,false,auth_5
111122222-3333-4444-5555-000000000022,root,3,false,auth_5
111122222-3333-4444-5555-000000000023,root,3,false,auth_5
111122222-3333-4444-5555-000000000024,root,3,false,auth_5
111122222-3333-4444-5555-000000000025,ccccc,3,false,auth_6
111122222-3333-4444-5555-000000000026,ccccc,3,false,auth_6
111122222-3333-4444-5555-000000000027,ccccc,3,false,auth_6
111122222-3333-4444-5555-000000000028,ccccc,3,false,auth_6
111122222-3333-4444-5555-000000000029,ccccc,3,false,auth_6
111122222-3333-4444-5555-000000000030,root,4,false,auth_7
111122222-3333-4444-5555-000000000031,root,4,false,auth_7
111122222-3333-4444-5555-000000000032,root,4,false,auth_7
111122222-3333-4444-5555-000000000033,root,4,false,auth_7
111122222-3333-4444-5555-000000000034,root,4,false,auth_7
111122222-3333-4444-5555-000000000035,bbbbb,4,false,auth_8
111122222-3333-4444-5555-000000000036,bbbbb,4,false,auth_8
111122222-3333-4444-5555-000000000037,bbbbb,4,false,auth_8
111122222-3333-4444-5555-000000000038,bbbbb,4,false,auth_8
111122222-3333-4444-5555-000000000039,bbbbb,4,false,auth_8
1 client_id namespace_id timestamp non_entity mount_accessor
2 111122222-3333-4444-5555-000000000000 root 1 false auth_1
3 111122222-3333-4444-5555-000000000001 root 1 false auth_1
4 111122222-3333-4444-5555-000000000002 root 1 false auth_1
5 111122222-3333-4444-5555-000000000003 root 1 false auth_1
6 111122222-3333-4444-5555-000000000004 root 1 false auth_1
7 111122222-3333-4444-5555-000000000005 aaaaa 1 false auth_2
8 111122222-3333-4444-5555-000000000006 aaaaa 1 false auth_2
9 111122222-3333-4444-5555-000000000007 aaaaa 1 false auth_2
10 111122222-3333-4444-5555-000000000008 aaaaa 1 false auth_2
11 111122222-3333-4444-5555-000000000009 aaaaa 1 false auth_2
12 111122222-3333-4444-5555-000000000010 bbbbb 1 false auth_3
13 111122222-3333-4444-5555-000000000011 bbbbb 1 false auth_3
14 111122222-3333-4444-5555-000000000012 bbbbb 1 false auth_3
15 111122222-3333-4444-5555-000000000013 bbbbb 2 false auth_3
16 111122222-3333-4444-5555-000000000014 bbbbb 2 false auth_3
17 111122222-3333-4444-5555-000000000015 root 2 false auth_4
18 111122222-3333-4444-5555-000000000016 root 2 false auth_4
19 111122222-3333-4444-5555-000000000017 root 2 false auth_4
20 111122222-3333-4444-5555-000000000018 root 2 false auth_4
21 111122222-3333-4444-5555-000000000019 root 2 false auth_4
22 111122222-3333-4444-5555-000000000020 root 3 false auth_5
23 111122222-3333-4444-5555-000000000021 root 3 false auth_5
24 111122222-3333-4444-5555-000000000022 root 3 false auth_5
25 111122222-3333-4444-5555-000000000023 root 3 false auth_5
26 111122222-3333-4444-5555-000000000024 root 3 false auth_5
27 111122222-3333-4444-5555-000000000025 ccccc 3 false auth_6
28 111122222-3333-4444-5555-000000000026 ccccc 3 false auth_6
29 111122222-3333-4444-5555-000000000027 ccccc 3 false auth_6
30 111122222-3333-4444-5555-000000000028 ccccc 3 false auth_6
31 111122222-3333-4444-5555-000000000029 ccccc 3 false auth_6
32 111122222-3333-4444-5555-000000000030 root 4 false auth_7
33 111122222-3333-4444-5555-000000000031 root 4 false auth_7
34 111122222-3333-4444-5555-000000000032 root 4 false auth_7
35 111122222-3333-4444-5555-000000000033 root 4 false auth_7
36 111122222-3333-4444-5555-000000000034 root 4 false auth_7
37 111122222-3333-4444-5555-000000000035 bbbbb 4 false auth_8
38 111122222-3333-4444-5555-000000000036 bbbbb 4 false auth_8
39 111122222-3333-4444-5555-000000000037 bbbbb 4 false auth_8
40 111122222-3333-4444-5555-000000000038 bbbbb 4 false auth_8
41 111122222-3333-4444-5555-000000000039 bbbbb 4 false auth_8

View File

@ -0,0 +1,40 @@
{"client_id":"111122222-3333-4444-5555-000000000000","namespace_id":"root","timestamp":1,"mount_accessor":"auth_1"}
{"client_id":"111122222-3333-4444-5555-000000000001","namespace_id":"root","timestamp":1,"mount_accessor":"auth_1"}
{"client_id":"111122222-3333-4444-5555-000000000002","namespace_id":"root","timestamp":1,"mount_accessor":"auth_1"}
{"client_id":"111122222-3333-4444-5555-000000000003","namespace_id":"root","timestamp":1,"mount_accessor":"auth_1"}
{"client_id":"111122222-3333-4444-5555-000000000004","namespace_id":"root","timestamp":1,"mount_accessor":"auth_1"}
{"client_id":"111122222-3333-4444-5555-000000000005","namespace_id":"aaaaa","timestamp":1,"mount_accessor":"auth_2"}
{"client_id":"111122222-3333-4444-5555-000000000006","namespace_id":"aaaaa","timestamp":1,"mount_accessor":"auth_2"}
{"client_id":"111122222-3333-4444-5555-000000000007","namespace_id":"aaaaa","timestamp":1,"mount_accessor":"auth_2"}
{"client_id":"111122222-3333-4444-5555-000000000008","namespace_id":"aaaaa","timestamp":1,"mount_accessor":"auth_2"}
{"client_id":"111122222-3333-4444-5555-000000000009","namespace_id":"aaaaa","timestamp":1,"mount_accessor":"auth_2"}
{"client_id":"111122222-3333-4444-5555-000000000010","namespace_id":"bbbbb","timestamp":1,"mount_accessor":"auth_3"}
{"client_id":"111122222-3333-4444-5555-000000000011","namespace_id":"bbbbb","timestamp":1,"mount_accessor":"auth_3"}
{"client_id":"111122222-3333-4444-5555-000000000012","namespace_id":"bbbbb","timestamp":1,"mount_accessor":"auth_3"}
{"client_id":"111122222-3333-4444-5555-000000000013","namespace_id":"bbbbb","timestamp":2,"mount_accessor":"auth_3"}
{"client_id":"111122222-3333-4444-5555-000000000014","namespace_id":"bbbbb","timestamp":2,"mount_accessor":"auth_3"}
{"client_id":"111122222-3333-4444-5555-000000000015","namespace_id":"root","timestamp":2,"mount_accessor":"auth_4"}
{"client_id":"111122222-3333-4444-5555-000000000016","namespace_id":"root","timestamp":2,"mount_accessor":"auth_4"}
{"client_id":"111122222-3333-4444-5555-000000000017","namespace_id":"root","timestamp":2,"mount_accessor":"auth_4"}
{"client_id":"111122222-3333-4444-5555-000000000018","namespace_id":"root","timestamp":2,"mount_accessor":"auth_4"}
{"client_id":"111122222-3333-4444-5555-000000000019","namespace_id":"root","timestamp":2,"mount_accessor":"auth_4"}
{"client_id":"111122222-3333-4444-5555-000000000020","namespace_id":"root","timestamp":3,"mount_accessor":"auth_5"}
{"client_id":"111122222-3333-4444-5555-000000000021","namespace_id":"root","timestamp":3,"mount_accessor":"auth_5"}
{"client_id":"111122222-3333-4444-5555-000000000022","namespace_id":"root","timestamp":3,"mount_accessor":"auth_5"}
{"client_id":"111122222-3333-4444-5555-000000000023","namespace_id":"root","timestamp":3,"mount_accessor":"auth_5"}
{"client_id":"111122222-3333-4444-5555-000000000024","namespace_id":"root","timestamp":3,"mount_accessor":"auth_5"}
{"client_id":"111122222-3333-4444-5555-000000000025","namespace_id":"ccccc","timestamp":3,"mount_accessor":"auth_6"}
{"client_id":"111122222-3333-4444-5555-000000000026","namespace_id":"ccccc","timestamp":3,"mount_accessor":"auth_6"}
{"client_id":"111122222-3333-4444-5555-000000000027","namespace_id":"ccccc","timestamp":3,"mount_accessor":"auth_6"}
{"client_id":"111122222-3333-4444-5555-000000000028","namespace_id":"ccccc","timestamp":3,"mount_accessor":"auth_6"}
{"client_id":"111122222-3333-4444-5555-000000000029","namespace_id":"ccccc","timestamp":3,"mount_accessor":"auth_6"}
{"client_id":"111122222-3333-4444-5555-000000000030","namespace_id":"root","timestamp":4,"mount_accessor":"auth_7"}
{"client_id":"111122222-3333-4444-5555-000000000031","namespace_id":"root","timestamp":4,"mount_accessor":"auth_7"}
{"client_id":"111122222-3333-4444-5555-000000000032","namespace_id":"root","timestamp":4,"mount_accessor":"auth_7"}
{"client_id":"111122222-3333-4444-5555-000000000033","namespace_id":"root","timestamp":4,"mount_accessor":"auth_7"}
{"client_id":"111122222-3333-4444-5555-000000000034","namespace_id":"root","timestamp":4,"mount_accessor":"auth_7"}
{"client_id":"111122222-3333-4444-5555-000000000035","namespace_id":"bbbbb","timestamp":4,"mount_accessor":"auth_8"}
{"client_id":"111122222-3333-4444-5555-000000000036","namespace_id":"bbbbb","timestamp":4,"mount_accessor":"auth_8"}
{"client_id":"111122222-3333-4444-5555-000000000037","namespace_id":"bbbbb","timestamp":4,"mount_accessor":"auth_8"}
{"client_id":"111122222-3333-4444-5555-000000000038","namespace_id":"bbbbb","timestamp":4,"mount_accessor":"auth_8"}
{"client_id":"111122222-3333-4444-5555-000000000039","namespace_id":"bbbbb","timestamp":4,"mount_accessor":"auth_8"}

View File

@ -0,0 +1,31 @@
client_id,namespace_id,timestamp,non_entity,mount_accessor
111122222-3333-4444-5555-000000000000,root,1,false,auth_1
111122222-3333-4444-5555-000000000001,root,1,false,auth_1
111122222-3333-4444-5555-000000000002,root,1,false,auth_1
111122222-3333-4444-5555-000000000003,root,1,false,auth_1
111122222-3333-4444-5555-000000000004,root,1,false,auth_1
111122222-3333-4444-5555-000000000005,aaaaa,1,false,auth_2
111122222-3333-4444-5555-000000000006,aaaaa,1,false,auth_2
111122222-3333-4444-5555-000000000007,aaaaa,1,false,auth_2
111122222-3333-4444-5555-000000000008,aaaaa,1,false,auth_2
111122222-3333-4444-5555-000000000009,aaaaa,1,false,auth_2
111122222-3333-4444-5555-000000000010,bbbbb,1,false,auth_3
111122222-3333-4444-5555-000000000011,bbbbb,1,false,auth_3
111122222-3333-4444-5555-000000000012,bbbbb,1,false,auth_3
111122222-3333-4444-5555-000000000013,bbbbb,2,false,auth_3
111122222-3333-4444-5555-000000000014,bbbbb,2,false,auth_3
111122222-3333-4444-5555-000000000015,root,2,false,auth_4
111122222-3333-4444-5555-000000000016,root,2,false,auth_4
111122222-3333-4444-5555-000000000017,root,2,false,auth_4
111122222-3333-4444-5555-000000000018,root,2,false,auth_4
111122222-3333-4444-5555-000000000019,root,2,false,auth_4
111122222-3333-4444-5555-000000000020,root,3,false,auth_5
111122222-3333-4444-5555-000000000021,root,3,false,auth_5
111122222-3333-4444-5555-000000000022,root,3,false,auth_5
111122222-3333-4444-5555-000000000023,root,3,false,auth_5
111122222-3333-4444-5555-000000000024,root,3,false,auth_5
111122222-3333-4444-5555-000000000025,ccccc,3,false,auth_6
111122222-3333-4444-5555-000000000026,ccccc,3,false,auth_6
111122222-3333-4444-5555-000000000027,ccccc,3,false,auth_6
111122222-3333-4444-5555-000000000028,ccccc,3,false,auth_6
111122222-3333-4444-5555-000000000029,ccccc,3,false,auth_6
1 client_id namespace_id timestamp non_entity mount_accessor
2 111122222-3333-4444-5555-000000000000 root 1 false auth_1
3 111122222-3333-4444-5555-000000000001 root 1 false auth_1
4 111122222-3333-4444-5555-000000000002 root 1 false auth_1
5 111122222-3333-4444-5555-000000000003 root 1 false auth_1
6 111122222-3333-4444-5555-000000000004 root 1 false auth_1
7 111122222-3333-4444-5555-000000000005 aaaaa 1 false auth_2
8 111122222-3333-4444-5555-000000000006 aaaaa 1 false auth_2
9 111122222-3333-4444-5555-000000000007 aaaaa 1 false auth_2
10 111122222-3333-4444-5555-000000000008 aaaaa 1 false auth_2
11 111122222-3333-4444-5555-000000000009 aaaaa 1 false auth_2
12 111122222-3333-4444-5555-000000000010 bbbbb 1 false auth_3
13 111122222-3333-4444-5555-000000000011 bbbbb 1 false auth_3
14 111122222-3333-4444-5555-000000000012 bbbbb 1 false auth_3
15 111122222-3333-4444-5555-000000000013 bbbbb 2 false auth_3
16 111122222-3333-4444-5555-000000000014 bbbbb 2 false auth_3
17 111122222-3333-4444-5555-000000000015 root 2 false auth_4
18 111122222-3333-4444-5555-000000000016 root 2 false auth_4
19 111122222-3333-4444-5555-000000000017 root 2 false auth_4
20 111122222-3333-4444-5555-000000000018 root 2 false auth_4
21 111122222-3333-4444-5555-000000000019 root 2 false auth_4
22 111122222-3333-4444-5555-000000000020 root 3 false auth_5
23 111122222-3333-4444-5555-000000000021 root 3 false auth_5
24 111122222-3333-4444-5555-000000000022 root 3 false auth_5
25 111122222-3333-4444-5555-000000000023 root 3 false auth_5
26 111122222-3333-4444-5555-000000000024 root 3 false auth_5
27 111122222-3333-4444-5555-000000000025 ccccc 3 false auth_6
28 111122222-3333-4444-5555-000000000026 ccccc 3 false auth_6
29 111122222-3333-4444-5555-000000000027 ccccc 3 false auth_6
30 111122222-3333-4444-5555-000000000028 ccccc 3 false auth_6
31 111122222-3333-4444-5555-000000000029 ccccc 3 false auth_6

View File

@ -0,0 +1,30 @@
{"client_id":"111122222-3333-4444-5555-000000000000","namespace_id":"root","timestamp":1,"mount_accessor":"auth_1"}
{"client_id":"111122222-3333-4444-5555-000000000001","namespace_id":"root","timestamp":1,"mount_accessor":"auth_1"}
{"client_id":"111122222-3333-4444-5555-000000000002","namespace_id":"root","timestamp":1,"mount_accessor":"auth_1"}
{"client_id":"111122222-3333-4444-5555-000000000003","namespace_id":"root","timestamp":1,"mount_accessor":"auth_1"}
{"client_id":"111122222-3333-4444-5555-000000000004","namespace_id":"root","timestamp":1,"mount_accessor":"auth_1"}
{"client_id":"111122222-3333-4444-5555-000000000005","namespace_id":"aaaaa","timestamp":1,"mount_accessor":"auth_2"}
{"client_id":"111122222-3333-4444-5555-000000000006","namespace_id":"aaaaa","timestamp":1,"mount_accessor":"auth_2"}
{"client_id":"111122222-3333-4444-5555-000000000007","namespace_id":"aaaaa","timestamp":1,"mount_accessor":"auth_2"}
{"client_id":"111122222-3333-4444-5555-000000000008","namespace_id":"aaaaa","timestamp":1,"mount_accessor":"auth_2"}
{"client_id":"111122222-3333-4444-5555-000000000009","namespace_id":"aaaaa","timestamp":1,"mount_accessor":"auth_2"}
{"client_id":"111122222-3333-4444-5555-000000000010","namespace_id":"bbbbb","timestamp":1,"mount_accessor":"auth_3"}
{"client_id":"111122222-3333-4444-5555-000000000011","namespace_id":"bbbbb","timestamp":1,"mount_accessor":"auth_3"}
{"client_id":"111122222-3333-4444-5555-000000000012","namespace_id":"bbbbb","timestamp":1,"mount_accessor":"auth_3"}
{"client_id":"111122222-3333-4444-5555-000000000013","namespace_id":"bbbbb","timestamp":2,"mount_accessor":"auth_3"}
{"client_id":"111122222-3333-4444-5555-000000000014","namespace_id":"bbbbb","timestamp":2,"mount_accessor":"auth_3"}
{"client_id":"111122222-3333-4444-5555-000000000015","namespace_id":"root","timestamp":2,"mount_accessor":"auth_4"}
{"client_id":"111122222-3333-4444-5555-000000000016","namespace_id":"root","timestamp":2,"mount_accessor":"auth_4"}
{"client_id":"111122222-3333-4444-5555-000000000017","namespace_id":"root","timestamp":2,"mount_accessor":"auth_4"}
{"client_id":"111122222-3333-4444-5555-000000000018","namespace_id":"root","timestamp":2,"mount_accessor":"auth_4"}
{"client_id":"111122222-3333-4444-5555-000000000019","namespace_id":"root","timestamp":2,"mount_accessor":"auth_4"}
{"client_id":"111122222-3333-4444-5555-000000000020","namespace_id":"root","timestamp":3,"mount_accessor":"auth_5"}
{"client_id":"111122222-3333-4444-5555-000000000021","namespace_id":"root","timestamp":3,"mount_accessor":"auth_5"}
{"client_id":"111122222-3333-4444-5555-000000000022","namespace_id":"root","timestamp":3,"mount_accessor":"auth_5"}
{"client_id":"111122222-3333-4444-5555-000000000023","namespace_id":"root","timestamp":3,"mount_accessor":"auth_5"}
{"client_id":"111122222-3333-4444-5555-000000000024","namespace_id":"root","timestamp":3,"mount_accessor":"auth_5"}
{"client_id":"111122222-3333-4444-5555-000000000025","namespace_id":"ccccc","timestamp":3,"mount_accessor":"auth_6"}
{"client_id":"111122222-3333-4444-5555-000000000026","namespace_id":"ccccc","timestamp":3,"mount_accessor":"auth_6"}
{"client_id":"111122222-3333-4444-5555-000000000027","namespace_id":"ccccc","timestamp":3,"mount_accessor":"auth_6"}
{"client_id":"111122222-3333-4444-5555-000000000028","namespace_id":"ccccc","timestamp":3,"mount_accessor":"auth_6"}
{"client_id":"111122222-3333-4444-5555-000000000029","namespace_id":"ccccc","timestamp":3,"mount_accessor":"auth_6"}

View File

@ -0,0 +1,46 @@
client_id,namespace_id,timestamp,non_entity,mount_accessor
111122222-3333-4444-5555-000000000040,rrrrr,0,false,auth_9
111122222-3333-4444-5555-000000000041,rrrrr,0,false,auth_9
111122222-3333-4444-5555-000000000042,rrrrr,0,false,auth_9
111122222-3333-4444-5555-000000000043,rrrrr,0,false,auth_9
111122222-3333-4444-5555-000000000044,rrrrr,0,false,auth_9
111122222-3333-4444-5555-000000000000,root,1,false,auth_1
111122222-3333-4444-5555-000000000001,root,1,false,auth_1
111122222-3333-4444-5555-000000000002,root,1,false,auth_1
111122222-3333-4444-5555-000000000003,root,1,false,auth_1
111122222-3333-4444-5555-000000000004,root,1,false,auth_1
111122222-3333-4444-5555-000000000005,aaaaa,1,false,auth_2
111122222-3333-4444-5555-000000000006,aaaaa,1,false,auth_2
111122222-3333-4444-5555-000000000007,aaaaa,1,false,auth_2
111122222-3333-4444-5555-000000000008,aaaaa,1,false,auth_2
111122222-3333-4444-5555-000000000009,aaaaa,1,false,auth_2
111122222-3333-4444-5555-000000000010,bbbbb,1,false,auth_3
111122222-3333-4444-5555-000000000011,bbbbb,1,false,auth_3
111122222-3333-4444-5555-000000000012,bbbbb,1,false,auth_3
111122222-3333-4444-5555-000000000013,bbbbb,2,false,auth_3
111122222-3333-4444-5555-000000000014,bbbbb,2,false,auth_3
111122222-3333-4444-5555-000000000015,root,2,false,auth_4
111122222-3333-4444-5555-000000000016,root,2,false,auth_4
111122222-3333-4444-5555-000000000017,root,2,false,auth_4
111122222-3333-4444-5555-000000000018,root,2,false,auth_4
111122222-3333-4444-5555-000000000019,root,2,false,auth_4
111122222-3333-4444-5555-000000000020,root,3,false,auth_5
111122222-3333-4444-5555-000000000021,root,3,false,auth_5
111122222-3333-4444-5555-000000000022,root,3,false,auth_5
111122222-3333-4444-5555-000000000023,root,3,false,auth_5
111122222-3333-4444-5555-000000000024,root,3,false,auth_5
111122222-3333-4444-5555-000000000025,ccccc,3,false,auth_6
111122222-3333-4444-5555-000000000026,ccccc,3,false,auth_6
111122222-3333-4444-5555-000000000027,ccccc,3,false,auth_6
111122222-3333-4444-5555-000000000028,ccccc,3,false,auth_6
111122222-3333-4444-5555-000000000029,ccccc,3,false,auth_6
111122222-3333-4444-5555-000000000030,root,4,false,auth_7
111122222-3333-4444-5555-000000000031,root,4,false,auth_7
111122222-3333-4444-5555-000000000032,root,4,false,auth_7
111122222-3333-4444-5555-000000000033,root,4,false,auth_7
111122222-3333-4444-5555-000000000034,root,4,false,auth_7
111122222-3333-4444-5555-000000000035,bbbbb,4,false,auth_8
111122222-3333-4444-5555-000000000036,bbbbb,4,false,auth_8
111122222-3333-4444-5555-000000000037,bbbbb,4,false,auth_8
111122222-3333-4444-5555-000000000038,bbbbb,4,false,auth_8
111122222-3333-4444-5555-000000000039,bbbbb,4,false,auth_8
1 client_id namespace_id timestamp non_entity mount_accessor
2 111122222-3333-4444-5555-000000000040 rrrrr 0 false auth_9
3 111122222-3333-4444-5555-000000000041 rrrrr 0 false auth_9
4 111122222-3333-4444-5555-000000000042 rrrrr 0 false auth_9
5 111122222-3333-4444-5555-000000000043 rrrrr 0 false auth_9
6 111122222-3333-4444-5555-000000000044 rrrrr 0 false auth_9
7 111122222-3333-4444-5555-000000000000 root 1 false auth_1
8 111122222-3333-4444-5555-000000000001 root 1 false auth_1
9 111122222-3333-4444-5555-000000000002 root 1 false auth_1
10 111122222-3333-4444-5555-000000000003 root 1 false auth_1
11 111122222-3333-4444-5555-000000000004 root 1 false auth_1
12 111122222-3333-4444-5555-000000000005 aaaaa 1 false auth_2
13 111122222-3333-4444-5555-000000000006 aaaaa 1 false auth_2
14 111122222-3333-4444-5555-000000000007 aaaaa 1 false auth_2
15 111122222-3333-4444-5555-000000000008 aaaaa 1 false auth_2
16 111122222-3333-4444-5555-000000000009 aaaaa 1 false auth_2
17 111122222-3333-4444-5555-000000000010 bbbbb 1 false auth_3
18 111122222-3333-4444-5555-000000000011 bbbbb 1 false auth_3
19 111122222-3333-4444-5555-000000000012 bbbbb 1 false auth_3
20 111122222-3333-4444-5555-000000000013 bbbbb 2 false auth_3
21 111122222-3333-4444-5555-000000000014 bbbbb 2 false auth_3
22 111122222-3333-4444-5555-000000000015 root 2 false auth_4
23 111122222-3333-4444-5555-000000000016 root 2 false auth_4
24 111122222-3333-4444-5555-000000000017 root 2 false auth_4
25 111122222-3333-4444-5555-000000000018 root 2 false auth_4
26 111122222-3333-4444-5555-000000000019 root 2 false auth_4
27 111122222-3333-4444-5555-000000000020 root 3 false auth_5
28 111122222-3333-4444-5555-000000000021 root 3 false auth_5
29 111122222-3333-4444-5555-000000000022 root 3 false auth_5
30 111122222-3333-4444-5555-000000000023 root 3 false auth_5
31 111122222-3333-4444-5555-000000000024 root 3 false auth_5
32 111122222-3333-4444-5555-000000000025 ccccc 3 false auth_6
33 111122222-3333-4444-5555-000000000026 ccccc 3 false auth_6
34 111122222-3333-4444-5555-000000000027 ccccc 3 false auth_6
35 111122222-3333-4444-5555-000000000028 ccccc 3 false auth_6
36 111122222-3333-4444-5555-000000000029 ccccc 3 false auth_6
37 111122222-3333-4444-5555-000000000030 root 4 false auth_7
38 111122222-3333-4444-5555-000000000031 root 4 false auth_7
39 111122222-3333-4444-5555-000000000032 root 4 false auth_7
40 111122222-3333-4444-5555-000000000033 root 4 false auth_7
41 111122222-3333-4444-5555-000000000034 root 4 false auth_7
42 111122222-3333-4444-5555-000000000035 bbbbb 4 false auth_8
43 111122222-3333-4444-5555-000000000036 bbbbb 4 false auth_8
44 111122222-3333-4444-5555-000000000037 bbbbb 4 false auth_8
45 111122222-3333-4444-5555-000000000038 bbbbb 4 false auth_8
46 111122222-3333-4444-5555-000000000039 bbbbb 4 false auth_8

View File

@ -0,0 +1,45 @@
{"client_id":"111122222-3333-4444-5555-000000000040","namespace_id":"rrrrr","mount_accessor":"auth_9"}
{"client_id":"111122222-3333-4444-5555-000000000041","namespace_id":"rrrrr","mount_accessor":"auth_9"}
{"client_id":"111122222-3333-4444-5555-000000000042","namespace_id":"rrrrr","mount_accessor":"auth_9"}
{"client_id":"111122222-3333-4444-5555-000000000043","namespace_id":"rrrrr","mount_accessor":"auth_9"}
{"client_id":"111122222-3333-4444-5555-000000000044","namespace_id":"rrrrr","mount_accessor":"auth_9"}
{"client_id":"111122222-3333-4444-5555-000000000000","namespace_id":"root","timestamp":1,"mount_accessor":"auth_1"}
{"client_id":"111122222-3333-4444-5555-000000000001","namespace_id":"root","timestamp":1,"mount_accessor":"auth_1"}
{"client_id":"111122222-3333-4444-5555-000000000002","namespace_id":"root","timestamp":1,"mount_accessor":"auth_1"}
{"client_id":"111122222-3333-4444-5555-000000000003","namespace_id":"root","timestamp":1,"mount_accessor":"auth_1"}
{"client_id":"111122222-3333-4444-5555-000000000004","namespace_id":"root","timestamp":1,"mount_accessor":"auth_1"}
{"client_id":"111122222-3333-4444-5555-000000000005","namespace_id":"aaaaa","timestamp":1,"mount_accessor":"auth_2"}
{"client_id":"111122222-3333-4444-5555-000000000006","namespace_id":"aaaaa","timestamp":1,"mount_accessor":"auth_2"}
{"client_id":"111122222-3333-4444-5555-000000000007","namespace_id":"aaaaa","timestamp":1,"mount_accessor":"auth_2"}
{"client_id":"111122222-3333-4444-5555-000000000008","namespace_id":"aaaaa","timestamp":1,"mount_accessor":"auth_2"}
{"client_id":"111122222-3333-4444-5555-000000000009","namespace_id":"aaaaa","timestamp":1,"mount_accessor":"auth_2"}
{"client_id":"111122222-3333-4444-5555-000000000010","namespace_id":"bbbbb","timestamp":1,"mount_accessor":"auth_3"}
{"client_id":"111122222-3333-4444-5555-000000000011","namespace_id":"bbbbb","timestamp":1,"mount_accessor":"auth_3"}
{"client_id":"111122222-3333-4444-5555-000000000012","namespace_id":"bbbbb","timestamp":1,"mount_accessor":"auth_3"}
{"client_id":"111122222-3333-4444-5555-000000000013","namespace_id":"bbbbb","timestamp":2,"mount_accessor":"auth_3"}
{"client_id":"111122222-3333-4444-5555-000000000014","namespace_id":"bbbbb","timestamp":2,"mount_accessor":"auth_3"}
{"client_id":"111122222-3333-4444-5555-000000000015","namespace_id":"root","timestamp":2,"mount_accessor":"auth_4"}
{"client_id":"111122222-3333-4444-5555-000000000016","namespace_id":"root","timestamp":2,"mount_accessor":"auth_4"}
{"client_id":"111122222-3333-4444-5555-000000000017","namespace_id":"root","timestamp":2,"mount_accessor":"auth_4"}
{"client_id":"111122222-3333-4444-5555-000000000018","namespace_id":"root","timestamp":2,"mount_accessor":"auth_4"}
{"client_id":"111122222-3333-4444-5555-000000000019","namespace_id":"root","timestamp":2,"mount_accessor":"auth_4"}
{"client_id":"111122222-3333-4444-5555-000000000020","namespace_id":"root","timestamp":3,"mount_accessor":"auth_5"}
{"client_id":"111122222-3333-4444-5555-000000000021","namespace_id":"root","timestamp":3,"mount_accessor":"auth_5"}
{"client_id":"111122222-3333-4444-5555-000000000022","namespace_id":"root","timestamp":3,"mount_accessor":"auth_5"}
{"client_id":"111122222-3333-4444-5555-000000000023","namespace_id":"root","timestamp":3,"mount_accessor":"auth_5"}
{"client_id":"111122222-3333-4444-5555-000000000024","namespace_id":"root","timestamp":3,"mount_accessor":"auth_5"}
{"client_id":"111122222-3333-4444-5555-000000000025","namespace_id":"ccccc","timestamp":3,"mount_accessor":"auth_6"}
{"client_id":"111122222-3333-4444-5555-000000000026","namespace_id":"ccccc","timestamp":3,"mount_accessor":"auth_6"}
{"client_id":"111122222-3333-4444-5555-000000000027","namespace_id":"ccccc","timestamp":3,"mount_accessor":"auth_6"}
{"client_id":"111122222-3333-4444-5555-000000000028","namespace_id":"ccccc","timestamp":3,"mount_accessor":"auth_6"}
{"client_id":"111122222-3333-4444-5555-000000000029","namespace_id":"ccccc","timestamp":3,"mount_accessor":"auth_6"}
{"client_id":"111122222-3333-4444-5555-000000000030","namespace_id":"root","timestamp":4,"mount_accessor":"auth_7"}
{"client_id":"111122222-3333-4444-5555-000000000031","namespace_id":"root","timestamp":4,"mount_accessor":"auth_7"}
{"client_id":"111122222-3333-4444-5555-000000000032","namespace_id":"root","timestamp":4,"mount_accessor":"auth_7"}
{"client_id":"111122222-3333-4444-5555-000000000033","namespace_id":"root","timestamp":4,"mount_accessor":"auth_7"}
{"client_id":"111122222-3333-4444-5555-000000000034","namespace_id":"root","timestamp":4,"mount_accessor":"auth_7"}
{"client_id":"111122222-3333-4444-5555-000000000035","namespace_id":"bbbbb","timestamp":4,"mount_accessor":"auth_8"}
{"client_id":"111122222-3333-4444-5555-000000000036","namespace_id":"bbbbb","timestamp":4,"mount_accessor":"auth_8"}
{"client_id":"111122222-3333-4444-5555-000000000037","namespace_id":"bbbbb","timestamp":4,"mount_accessor":"auth_8"}
{"client_id":"111122222-3333-4444-5555-000000000038","namespace_id":"bbbbb","timestamp":4,"mount_accessor":"auth_8"}
{"client_id":"111122222-3333-4444-5555-000000000039","namespace_id":"bbbbb","timestamp":4,"mount_accessor":"auth_8"}

View File

@ -2,9 +2,12 @@ package vault
import ( import (
"context" "context"
"encoding/csv"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"io"
"net/http"
"os" "os"
"sort" "sort"
"strconv" "strconv"
@ -20,6 +23,7 @@ import (
"github.com/hashicorp/vault/helper/timeutil" "github.com/hashicorp/vault/helper/timeutil"
"github.com/hashicorp/vault/sdk/logical" "github.com/hashicorp/vault/sdk/logical"
"github.com/hashicorp/vault/vault/activity" "github.com/hashicorp/vault/vault/activity"
"go.uber.org/atomic"
) )
const ( const (
@ -160,6 +164,8 @@ type ActivityLog struct {
// partialMonthClientTracker tracks active clients this month. Protected by fragmentLock. // partialMonthClientTracker tracks active clients this month. Protected by fragmentLock.
partialMonthClientTracker map[string]*activity.EntityRecord partialMonthClientTracker map[string]*activity.EntityRecord
inprocessExport *atomic.Bool
} }
// These non-persistent configuration options allow us to disable // These non-persistent configuration options allow us to disable
@ -207,6 +213,7 @@ func NewActivityLog(core *Core, logger log.Logger, view *BarrierView, metrics me
clientSequenceNumber: 0, clientSequenceNumber: 0,
}, },
standbyFragmentsReceived: make([]*activity.LogFragment, 0), standbyFragmentsReceived: make([]*activity.LogFragment, 0),
inprocessExport: atomic.NewBool(false),
} }
config, err := a.loadConfigOrDefault(core.activeContext) config, err := a.loadConfigOrDefault(core.activeContext)
@ -525,10 +532,7 @@ func (a *ActivityLog) getLastEntitySegmentNumber(ctx context.Context, startTime
} }
// WalkEntitySegments loads each of the entity segments for a particular start time // WalkEntitySegments loads each of the entity segments for a particular start time
func (a *ActivityLog) WalkEntitySegments(ctx context.Context, func (a *ActivityLog) WalkEntitySegments(ctx context.Context, startTime time.Time, walkFn func(*activity.EntityActivityLog, time.Time) error) error {
startTime time.Time,
walkFn func(*activity.EntityActivityLog, time.Time),
) error {
basePath := activityEntityBasePath + fmt.Sprint(startTime.Unix()) + "/" basePath := activityEntityBasePath + fmt.Sprint(startTime.Unix()) + "/"
pathList, err := a.view.List(ctx, basePath) pathList, err := a.view.List(ctx, basePath)
if err != nil { if err != nil {
@ -550,7 +554,10 @@ func (a *ActivityLog) WalkEntitySegments(ctx context.Context,
if err != nil { if err != nil {
return fmt.Errorf("unable to parse segment %v%v: %w", basePath, path, err) return fmt.Errorf("unable to parse segment %v%v: %w", basePath, path, err)
} }
walkFn(out, startTime) err = walkFn(out, startTime)
if err != nil {
return fmt.Errorf("unable to walk entities: %w", err)
}
} }
return nil return nil
} }
@ -2054,7 +2061,7 @@ func (a *ActivityLog) precomputedQueryWorker(ctx context.Context) error {
byNamespace := make(map[string]*processByNamespace) byNamespace := make(map[string]*processByNamespace)
byMonth := make(map[int64]*processMonth) byMonth := make(map[int64]*processMonth)
walkEntities := func(l *activity.EntityActivityLog, startTime time.Time) { walkEntities := func(l *activity.EntityActivityLog, startTime time.Time) error {
for _, e := range l.Clients { for _, e := range l.Clients {
processClientRecord(e, byNamespace, byMonth, startTime) processClientRecord(e, byNamespace, byMonth, startTime)
@ -2102,6 +2109,8 @@ func (a *ActivityLog) precomputedQueryWorker(ctx context.Context) error {
} }
} }
} }
return nil
} }
walkTokens := func(l *activity.TokenCount) { walkTokens := func(l *activity.TokenCount) {
@ -2569,3 +2578,163 @@ func (a *ActivityLog) partialMonthClientCount(ctx context.Context) (map[string]i
return responseData, nil return responseData, nil
} }
func (a *ActivityLog) writeExport(ctx context.Context, rw http.ResponseWriter, format string, startTime, endTime time.Time) error {
// For capacity reasons only allow a single in-process export at a time.
// TODO do we really need to do this?
if !a.inprocessExport.CAS(false, true) {
return fmt.Errorf("existing export in progress")
}
defer a.inprocessExport.Store(false)
// Find the months with activity log data that are between the start and end
// months. We want to walk this in cronological order so the oldest instance of a
// client usage is recorded, not the most recent.
times, err := a.getMostRecentNonContiguousActivityLogSegments(ctx)
if err != nil {
a.logger.Warn("failed to list recent segments", "error", err)
return fmt.Errorf("failed to list recent segments: %w", err)
}
sort.Slice(times, func(i, j int) bool {
// sort in chronological order to produce the output we want showing what
// month an entity first had activity.
return times[i].Before(times[j])
})
// Filter over just the months we care about
filteredList := make([]time.Time, 0, len(times))
for _, t := range times {
if timeutil.InRange(t, startTime, endTime) {
filteredList = append(filteredList, t)
}
}
if len(filteredList) == 0 {
a.logger.Info("no data to export", "start_time", startTime, "end_time", endTime)
return fmt.Errorf("no data to export in provided time range")
}
actualStartTime := filteredList[len(filteredList)-1]
a.logger.Trace("choose start time for export", "actualStartTime", actualStartTime, "months_included", filteredList)
// Add headers here because we start to immediately write in the csv encoder
// constructor.
rw.Header().Add("Content-Disposition", fmt.Sprintf("attachment; filename=\"activity_export_%d_to_%d.%s\"", actualStartTime.Unix(), endTime.Unix(), format))
rw.Header().Add("Content-Type", fmt.Sprintf("application/%s", format))
var encoder encoder
switch format {
case "json":
encoder = newJSONEncoder(rw)
case "csv":
var err error
encoder, err = newCSVEncoder(rw)
if err != nil {
return fmt.Errorf("failed to create csv encoder: %w", err)
}
default:
return fmt.Errorf("invalid format: %s", format)
}
a.logger.Info("starting activity log export", "start_time", startTime, "end_time", endTime, "format", format)
dedupedIds := make(map[string]struct{})
walkEntities := func(l *activity.EntityActivityLog, startTime time.Time) error {
for _, e := range l.Clients {
if _, ok := dedupedIds[e.ClientID]; ok {
continue
}
dedupedIds[e.ClientID] = struct{}{}
err := encoder.Encode(e)
if err != nil {
return err
}
}
return nil
}
// For each month in the filtered list walk all the log segments
for _, startTime := range filteredList {
err := a.WalkEntitySegments(ctx, startTime, walkEntities)
if err != nil {
a.logger.Error("failed to load segments for export", "error", err)
return fmt.Errorf("failed to load segments for export: %w", err)
}
}
// Flush and error check the encoder. This is neccessary for buffered
// encoders like csv.
encoder.Flush()
if err := encoder.Error(); err != nil {
a.logger.Error("failed to flush export encoding", "error", err)
return fmt.Errorf("failed to flush export encoding: %w", err)
}
return nil
}
type encoder interface {
Encode(*activity.EntityRecord) error
Flush()
Error() error
}
var _ encoder = (*jsonEncoder)(nil)
type jsonEncoder struct {
e *json.Encoder
}
func newJSONEncoder(w io.Writer) *jsonEncoder {
return &jsonEncoder{
e: json.NewEncoder(w),
}
}
func (j *jsonEncoder) Encode(er *activity.EntityRecord) error {
return j.e.Encode(er)
}
// Flush is a no-op because json.Encoder doesn't buffer data
func (j *jsonEncoder) Flush() {}
// Error is a no-op because flushing is a no-op.
func (j *jsonEncoder) Error() error { return nil }
var _ encoder = (*csvEncoder)(nil)
type csvEncoder struct {
*csv.Writer
}
func newCSVEncoder(w io.Writer) (*csvEncoder, error) {
writer := csv.NewWriter(w)
err := writer.Write([]string{
"client_id",
"namespace_id",
"timestamp",
"non_entity",
"mount_accessor",
})
if err != nil {
return nil, err
}
return &csvEncoder{
Writer: writer,
}, nil
}
// Encode converts an export bundle into a set of strings and writes them to the
// csv writer.
func (c *csvEncoder) Encode(e *activity.EntityRecord) error {
return c.Writer.Write([]string{
e.ClientID,
e.NamespaceID,
fmt.Sprintf("%d", e.Timestamp),
fmt.Sprintf("%t", e.NonEntity),
e.MountAccessor,
})
}

View File

@ -1,10 +1,14 @@
package vault package vault
import ( import (
"bytes"
"context" "context"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"net/http"
"os"
"path/filepath"
"reflect" "reflect"
"sort" "sort"
"strconv" "strconv"
@ -1715,6 +1719,192 @@ func TestActivityLog_refreshFromStoredLogPreviousMonth(t *testing.T) {
} }
} }
func TestActivityLog_Export(t *testing.T) {
timeutil.SkipAtEndOfMonth(t)
january := time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)
august := time.Date(2020, 8, 15, 12, 0, 0, 0, time.UTC)
september := timeutil.StartOfMonth(time.Date(2020, 9, 1, 0, 0, 0, 0, time.UTC))
october := timeutil.StartOfMonth(time.Date(2020, 10, 1, 0, 0, 0, 0, time.UTC))
november := timeutil.StartOfMonth(time.Date(2020, 11, 1, 0, 0, 0, 0, time.UTC))
core, _, _, _ := TestCoreUnsealedWithMetrics(t)
a := core.activityLog
ctx := namespace.RootContext(nil)
// Generate overlapping sets of entity IDs from this list.
// january: 40-44 RRRRR
// first month: 0-19 RRRRRAAAAABBBBBRRRRR
// second month: 10-29 BBBBBRRRRRRRRRRCCCCC
// third month: 15-39 RRRRRRRRRRCCCCCRRRRRBBBBB
entityRecords := make([]*activity.EntityRecord, 45)
entityNamespaces := []string{"root", "aaaaa", "bbbbb", "root", "root", "ccccc", "root", "bbbbb", "rrrrr"}
authMethods := []string{"auth_1", "auth_2", "auth_3", "auth_4", "auth_5", "auth_6", "auth_7", "auth_8", "auth_9"}
for i := range entityRecords {
entityRecords[i] = &activity.EntityRecord{
ClientID: fmt.Sprintf("111122222-3333-4444-5555-%012v", i),
NamespaceID: entityNamespaces[i/5],
MountAccessor: authMethods[i/5],
}
}
toInsert := []struct {
StartTime int64
Segment uint64
Clients []*activity.EntityRecord
}{
// January, should not be included
{
january.Unix(),
0,
entityRecords[40:45],
},
// Artifically split August and October
{ // 1
august.Unix(),
0,
entityRecords[:13],
},
{ // 2
august.Unix(),
1,
entityRecords[13:20],
},
{ // 3
september.Unix(),
0,
entityRecords[10:30],
},
{ // 4
october.Unix(),
0,
entityRecords[15:40],
},
{
october.Unix(),
1,
entityRecords[15:40],
},
{
october.Unix(),
2,
entityRecords[17:23],
},
}
for i, segment := range toInsert {
eal := &activity.EntityActivityLog{
Clients: segment.Clients,
}
// Mimic a lower time stamp for earlier clients
for _, c := range eal.Clients {
c.Timestamp = int64(i)
}
data, err := proto.Marshal(eal)
if err != nil {
t.Fatal(err)
}
path := fmt.Sprintf("%ventity/%v/%v", ActivityLogPrefix, segment.StartTime, segment.Segment)
WriteToStorage(t, core, path, data)
}
tCases := []struct {
format string
startTime time.Time
endTime time.Time
expected string
}{
{
format: "json",
startTime: august,
endTime: timeutil.EndOfMonth(september),
expected: "aug_sep.json",
},
{
format: "csv",
startTime: august,
endTime: timeutil.EndOfMonth(september),
expected: "aug_sep.csv",
},
{
format: "json",
startTime: january,
endTime: timeutil.EndOfMonth(november),
expected: "full_history.json",
},
{
format: "csv",
startTime: january,
endTime: timeutil.EndOfMonth(november),
expected: "full_history.csv",
},
{
format: "json",
startTime: august,
endTime: timeutil.EndOfMonth(october),
expected: "aug_oct.json",
},
{
format: "csv",
startTime: august,
endTime: timeutil.EndOfMonth(october),
expected: "aug_oct.csv",
},
{
format: "json",
startTime: august,
endTime: timeutil.EndOfMonth(august),
expected: "aug.json",
},
{
format: "csv",
startTime: august,
endTime: timeutil.EndOfMonth(august),
expected: "aug.csv",
},
}
for _, tCase := range tCases {
rw := &fakeResponseWriter{
buffer: &bytes.Buffer{},
headers: http.Header{},
}
if err := a.writeExport(ctx, rw, tCase.format, tCase.startTime, tCase.endTime); err != nil {
t.Fatal(err)
}
expected, err := os.ReadFile(filepath.Join("activity", "test_fixtures", tCase.expected))
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(rw.buffer.Bytes(), expected) {
t.Fatal(rw.buffer.String())
}
}
}
type fakeResponseWriter struct {
buffer *bytes.Buffer
headers http.Header
}
func (f *fakeResponseWriter) Write(b []byte) (int, error) {
return f.buffer.Write(b)
}
func (f *fakeResponseWriter) Header() http.Header {
return f.headers
}
func (f *fakeResponseWriter) WriteHeader(statusCode int) {
panic("unimplmeneted")
}
func TestActivityLog_IncludeNamespace(t *testing.T) { func TestActivityLog_IncludeNamespace(t *testing.T) {
root := namespace.RootNamespace root := namespace.RootNamespace
a := &ActivityLog{} a := &ActivityLog{}

View File

@ -5198,6 +5198,10 @@ This path responds to the following HTTP methods.
"Query the historical count of clients.", "Query the historical count of clients.",
"Query the historical count of clients.", "Query the historical count of clients.",
}, },
"activity-export": {
"Export the historical activity of clients.",
"Export the historical activity of clients.",
},
"activity-monthly": { "activity-monthly": {
"Count of active clients so far this month.", "Count of active clients so far this month.",
"Count of active clients so far this month.", "Count of active clients so far this month.",

View File

@ -2,7 +2,9 @@ package vault
import ( import (
"context" "context"
"fmt"
"net/http" "net/http"
"os"
"path" "path"
"strings" "strings"
"time" "time"
@ -97,15 +99,37 @@ func (b *SystemBackend) rootActivityPaths() []*framework.Path {
}, },
}, },
}, },
{
Pattern: "internal/counters/activity/export$",
Fields: map[string]*framework.FieldSchema{
"start_time": {
Type: framework.TypeTime,
Description: "Start of query interval",
},
"end_time": {
Type: framework.TypeTime,
Description: "End of query interval",
},
"format": {
Type: framework.TypeString,
Description: "Format of the file. Either a CSV or a JSON file with an object per line.",
Default: "json",
},
},
HelpSynopsis: strings.TrimSpace(sysHelp["activity-export"][0]),
HelpDescription: strings.TrimSpace(sysHelp["activity-export"][1]),
Operations: map[logical.Operation]framework.OperationHandler{
logical.ReadOperation: &framework.PathOperation{
Callback: b.handleClientExport,
Summary: "Report the client count metrics, for this namespace and all child namespaces.",
},
},
},
} }
} }
func (b *SystemBackend) handleClientMetricQuery(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { func parseStartEndTimes(a *ActivityLog, d *framework.FieldData) (time.Time, time.Time, error) {
a := b.Core.activityLog
if a == nil {
return logical.ErrorResponse("no activity log present"), nil
}
startTime := d.Get("start_time").(time.Time) startTime := d.Get("start_time").(time.Time)
endTime := d.Get("end_time").(time.Time) endTime := d.Get("end_time").(time.Time)
@ -126,7 +150,52 @@ func (b *SystemBackend) handleClientMetricQuery(ctx context.Context, req *logica
startTime = startTime.UTC() startTime = startTime.UTC()
} }
if startTime.After(endTime) { if startTime.After(endTime) {
return logical.ErrorResponse("start_time is later than end_time"), nil return time.Time{}, time.Time{}, fmt.Errorf("start_time is later than end_time")
}
return startTime, endTime, nil
}
func (b *SystemBackend) handleClientExport(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
a := b.Core.activityLog
if a == nil {
return logical.ErrorResponse("no activity log present"), nil
}
startTime, endTime, err := parseStartEndTimes(a, d)
if err != nil {
return logical.ErrorResponse(err.Error()), nil
}
// This is to avoid the default 90s context timeout.
timeout := 10 * time.Minute
if durationRaw := os.Getenv("VAULT_ACTIVITY_EXPORT_DURATION"); durationRaw != "" {
d, err := time.ParseDuration(durationRaw)
if err == nil {
timeout = d
}
}
runCtx, cancelFunc := context.WithTimeout(b.Core.activeContext, timeout)
defer cancelFunc()
err = a.writeExport(runCtx, req.ResponseWriter, d.Get("format").(string), startTime, endTime)
if err != nil {
return nil, err
}
return nil, nil
}
func (b *SystemBackend) handleClientMetricQuery(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
a := b.Core.activityLog
if a == nil {
return logical.ErrorResponse("no activity log present"), nil
}
startTime, endTime, err := parseStartEndTimes(a, d)
if err != nil {
return logical.ErrorResponse(err.Error()), nil
} }
results, err := a.handleQuery(ctx, startTime, endTime) results, err := a.handleQuery(ctx, startTime, endTime)

View File

@ -848,3 +848,58 @@ $ curl \
"warnings": null "warnings": null
} }
``` ```
## Activity Export
This endpoint returns an export of the clients that had activity within the
provided start and end times. The returned set of client information will be
deduplicated over the time window and will show the earliest activity logged for
each client. The output will be ordered chronologically by month of activity.
~> **NOTE**: This endpoint is currently in tech preview status.
There are a few things to keep in mind while using this API.
- The response includes the actual time period covered, which may not exactly
match the query parameters due to the month granularity of data or missing
months in the requested time range.
- If the `end_date` supplied to the API is for the current month, the activity
information returned by this API will include activity for this month, however
it may be up to 20 minutes delayed.
This endpoint was added in Vault 1.11.
| Method | Path |
| :----- | :---------------------------------------- |
| `GET` | `/sys/internal/counters/activity/export` |
### Parameters
- `start_time` `(string, optional)` - An RFC3339 timestamp or Unix epoch time. Specifies the start of the
period for which client counts will be reported. If no start time is specified, the `default_report_months`
prior to the `end_time` will be used.
- `end_time` `(string, optional)` - An RFC3339 timestamp or Unix epoch time. Specifies the end of the period
for which client counts will be reported. If no end time is specified, the end of the previous calendar
month will be used.
- `format` `(string, optional)` - The desired format of the output file. Allowed
values are `csv` and `json`. If no format is provided a default of `json`
will be used.
### Sample Request
```shell-session
$ curl \
--header "X-Vault-Token: ..." \
--request GET \
http://127.0.0.1:8200/v1/sys/internal/counters/activity/export
```
### Sample Response
```json
{"client_id":"3f210722-7210-98e8-1f0d-e6a39ffb29c6","namespace_id":"root","timestamp":1653350457,"mount_accessor":"auth_userpass_bb52979d"}
{"client_id":"X/Yed4Oj4cqODj9tSHjKwnRy5QVSBRlX3COxjjWSXyI=","namespace_id":"root","timestamp":1653350491,"non_entity":true,"mount_accessor":"auth_token_f6f2c11c"}
{"client_id":"d93405dc-b592-b1c3-a520-14e618d359c1","namespace_id":"root","timestamp":1653350501,"mount_accessor":"auth_userpass_bb52979d"}
```