Skip to content
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

Allow multiple ES outputs as long as they are the same ES #1684

Merged
merged 101 commits into from
Sep 7, 2022
Merged
Changes from all commits
Commits
Show all changes
101 commits
Select commit Hold shift + click to select a range
129eefe
[Automation] Update elastic stack version to 8.3.0-4644f7c7 for testi…
apmmachine Jun 1, 2022
0d99f4b
[Automation] Update elastic stack version to 8.3.0-17c7e5c0 for testi…
apmmachine Jun 2, 2022
03a9134
[Automation] Update elastic stack version to 8.3.0-378ebcca for testi…
apmmachine Jun 3, 2022
7fcb743
[Automation] Update elastic stack version to 8.3.0-9596ee28 for testi…
apmmachine Jun 6, 2022
7192db9
[Automation] Update elastic stack version to 8.3.0-f530a93f for testi…
apmmachine Jun 7, 2022
96976f8
[Automation] Update elastic stack version to 8.3.0-f13a89b4 for testi…
apmmachine Jun 8, 2022
26f08df
[Automation] Update elastic stack version to 8.3.0-3c22a7f7 for testi…
apmmachine Jun 9, 2022
b9f7464
[Automation] Update elastic stack version to 8.3.0-158b3cba for testi…
apmmachine Jun 10, 2022
7d372c6
[Automation] Update elastic stack version to 8.3.0-db012561 for testi…
apmmachine Jun 13, 2022
37d116d
[Automation] Update elastic stack version to 8.3.0-e4e76686 for testi…
apmmachine Jun 14, 2022
6c80253
[Automation] Update elastic stack version to 8.3.0-460dc667 for testi…
apmmachine Jun 15, 2022
91518f3
[Automation] Update elastic stack version to 8.3.0-fe62331f for testi…
apmmachine Jun 16, 2022
282fb10
[Automation] Update elastic stack version to 8.3.0-75d7500e for testi…
apmmachine Jun 20, 2022
a322ddc
[Automation] Update elastic stack version to 8.3.0-6d4bb852 for testi…
apmmachine Jun 21, 2022
5fa764e
[Automation] Update elastic stack version to 8.3.0-e0057e17 for testi…
apmmachine Jun 21, 2022
ce387fa
[Automation] Update elastic stack version to 8.3.0-47d97929 for testi…
apmmachine Jun 23, 2022
d14e71e
ci: enable build notifications as GitHub issues (#1582) (#1587)
mergify[bot] Jun 23, 2022
211e9b9
[Automation] Update elastic stack version to 8.3.0-3b390c7b for testi…
apmmachine Jun 24, 2022
d7928b4
[Automation] Update elastic stack version to 8.3.0-fdf97a2e for testi…
apmmachine Jun 27, 2022
88dd2b6
Bugfix: Avoid panic when check-in setup duration is longer than poll …
mergify[bot] Jun 27, 2022
6059b03
ci: enable flaky test detector (#1589) (#1602)
mergify[bot] Jun 27, 2022
cddd9d7
Update to 8.3.1
ph Jun 28, 2022
152c1d9
Udpate doc
ph Jun 28, 2022
77f0fd6
Merge pull request #1610 from ph/8.3.1-update
ph Jun 28, 2022
a487054
[Automation] Update elastic stack version to 8.3.0-729c5564 for testi…
apmmachine Jun 29, 2022
1bbad27
debug api key creation
AndersonQ Jul 14, 2022
d61c8ee
merge dev-vagrant-how-to
AndersonQ Jul 14, 2022
1404587
allow to compile a binary for debug (#1559)
AndersonQ Jul 6, 2022
eb58160
wip
AndersonQ Jul 14, 2022
d2ec527
add affected versions
AndersonQ Jul 14, 2022
b463a77
evidence of the problem
AndersonQ Jul 14, 2022
91c78f2
better reading layout
AndersonQ Jul 18, 2022
008f273
add elasticsearchOutputs to agent schema
AndersonQ Jul 21, 2022
e311321
no real change, tests are still passing
AndersonQ Jul 21, 2022
68e6bf2
notes
AndersonQ Jul 21, 2022
58a7eab
no real change
AndersonQ Jul 21, 2022
495ea7d
naming convention
AndersonQ Jul 21, 2022
52b8aa0
TODO
AndersonQ Jul 21, 2022
35c05f0
adjust DefaultAPIKeyHistoryItems definition
AndersonQ Jul 21, 2022
a7e3217
adjust Prepare to use new model.Agent
AndersonQ Jul 21, 2022
be82596
adjust find Agent functions
AndersonQ Jul 21, 2022
7b5e4aa
do todo
AndersonQ Jul 21, 2022
faa3ead
Merge branch 'main' into 2148-api-key
AndersonQ Jul 21, 2022
40490c6
wip
AndersonQ Jul 22, 2022
d492cfd
remove pre allocated agent.ElasticsearchOutputs
AndersonQ Jul 25, 2022
35d11ec
better errors, minor improvements
AndersonQ Jul 27, 2022
311e6b0
removed leftover test
AndersonQ Jul 27, 2022
fc460ac
add root cause to ErrElastic
AndersonQ Jul 27, 2022
87a411a
more notes
AndersonQ Jul 28, 2022
e266c20
adjust painless script and add integration tests
AndersonQ Jul 28, 2022
c865859
Merge branch 'main' into 2148-api-key
AndersonQ Jul 28, 2022
eba4f71
fix typo
AndersonQ Jul 28, 2022
135ddcb
tidy up
AndersonQ Jul 28, 2022
89c920b
add output name to API key metadata
AndersonQ Jul 28, 2022
c4cc70e
add migration to migration.go
AndersonQ Jul 29, 2022
21b3984
add migration docs and improve logging
AndersonQ Aug 1, 2022
935706a
remove migration code from policy_output
AndersonQ Aug 1, 2022
1fa74ec
rename ElasticSearchOutputs to Outputs and add a 'type' field to it
AndersonQ Aug 1, 2022
17787e1
.
AndersonQ Aug 1, 2022
f2e70c5
fix import cycle
AndersonQ Aug 1, 2022
056d3f0
adjust handleAck invalidate API keys
AndersonQ Aug 1, 2022
7847924
migrate policy coordinator idx working
AndersonQ Aug 2, 2022
5f2ff23
adjust migrations: group in migration fn per version
AndersonQ Aug 2, 2022
ebc2131
add APIKeyIDs to model.Agent
AndersonQ Aug 2, 2022
130b979
adjust handleAck and monitor to use new agent model
AndersonQ Aug 2, 2022
c39e365
.
AndersonQ Aug 2, 2022
cd02061
ops
AndersonQ Aug 2, 2022
9a156b5
add/fix file license headers
AndersonQ Aug 2, 2022
77b9541
wee adjustments
AndersonQ Aug 2, 2022
2fc804b
Merge branch 'main' into 2148-api-key
AndersonQ Aug 2, 2022
959431c
fix flaky test
AndersonQ Aug 2, 2022
7c2e881
Merge branch '2148-api-key' of github.com:AndersonQ/fleet-server into…
AndersonQ Aug 2, 2022
f522d01
try to fix tests
AndersonQ Aug 2, 2022
9d8ea7d
try to fix tests
AndersonQ Aug 2, 2022
1eb7bd7
fixing linter issues
AndersonQ Aug 2, 2022
4250ad6
try to fix tests
AndersonQ Aug 2, 2022
8fd7b62
fix and adjust tests
AndersonQ Aug 3, 2022
e5f4b74
linter and PR fixes
AndersonQ Aug 3, 2022
0fb8c56
change field name
AndersonQ Aug 3, 2022
7a79d4c
fix after renaming
AndersonQ Aug 3, 2022
8ea0ede
fix linting issue
AndersonQ Aug 3, 2022
31d0537
.
AndersonQ Aug 3, 2022
6e5c500
.
AndersonQ Aug 3, 2022
3124b02
delete 0.notes.md, using a gist instead
AndersonQ Aug 4, 2022
b87920f
address PR comments
AndersonQ Aug 10, 2022
6f0c0db
make migration to run
AndersonQ Aug 12, 2022
9bbd267
.
AndersonQ Aug 12, 2022
cdac944
small fixes and PR changes
AndersonQ Aug 25, 2022
d0af9ea
Merge branch 'main' into 2148-api-key
AndersonQ Aug 25, 2022
2966e63
.
AndersonQ Aug 26, 2022
7090f88
Merge branch 'main' into 2148-api-key
AndersonQ Aug 26, 2022
ed3f8d4
.
AndersonQ Aug 26, 2022
2a7ffaf
Merge branch '2148-api-key' of github.com:AndersonQ/fleet-server into…
AndersonQ Aug 26, 2022
aa4ad32
fix typo
AndersonQ Sep 6, 2022
a64a820
fix linter issues
AndersonQ Sep 6, 2022
a3c36d6
fix linter issues
AndersonQ Sep 6, 2022
bd4b7af
Merge branch 'main' into 2148-api-key
AndersonQ Sep 6, 2022
1269b68
adjust migration name
AndersonQ Sep 6, 2022
96b3b87
Merge branch '2148-api-key' of github.com:AndersonQ/fleet-server into…
AndersonQ Sep 6, 2022
b42d5f8
adjust migration log
AndersonQ Sep 6, 2022
d78e50a
Merge branch 'main' into 2148-api-key
AndersonQ Sep 7, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions cmd/fleet/main.go
Original file line number Diff line number Diff line change
@@ -821,17 +821,21 @@ func (f *FleetServer) runSubsystems(ctx context.Context, cfg *config.Config, g *
remoteVersion, err := ver.CheckCompatibility(ctx, esCli, f.bi.Version)
if err != nil {
if len(remoteVersion) != 0 {
return fmt.Errorf("failed version compatibility check with elasticsearch (Agent: %s, Elasticsearch: %s): %w", f.bi.Version, remoteVersion, err)
return fmt.Errorf("failed version compatibility check with elasticsearch (Agent: %s, Elasticsearch: %s): %w",
f.bi.Version, remoteVersion, err)
}
return fmt.Errorf("failed version compatibility check with elasticsearch: %w", err)
}

// Run migrations; current safe to do in background. That may change in the future.
g.Go(loggedRunFunc(ctx, "Migrations", func(ctx context.Context) error {
// Run migrations
loggedMigration := loggedRunFunc(ctx, "Migrations", func(ctx context.Context) error {
return dl.Migrate(ctx, bulker)
}))
})
if err = loggedMigration(); err != nil {
return fmt.Errorf("failed to run subsystems: %w", err)
}

// Run schduler for periodic GC/cleanup
// Run scheduler for periodic GC/cleanup
gcCfg := cfg.Inputs[0].Server.GC
sched, err := scheduler.New(gc.Schedules(bulker, gcCfg.ScheduleInterval, gcCfg.CleanupAfterExpiredInterval))
if err != nil {
49 changes: 23 additions & 26 deletions internal/pkg/api/handleAck.go
Original file line number Diff line number Diff line change
@@ -15,6 +15,8 @@ import (
"strings"
"time"

"github.com/pkg/errors"

"github.com/elastic/fleet-server/v7/internal/pkg/bulk"
"github.com/elastic/fleet-server/v7/internal/pkg/cache"
"github.com/elastic/fleet-server/v7/internal/pkg/config"
@@ -24,7 +26,6 @@ import (
"github.com/elastic/fleet-server/v7/internal/pkg/logger"
"github.com/elastic/fleet-server/v7/internal/pkg/model"
"github.com/elastic/fleet-server/v7/internal/pkg/policy"
"github.com/pkg/errors"

"github.com/julienschmidt/httprouter"
"github.com/rs/zerolog"
@@ -337,8 +338,9 @@ func (ack *AckT) handlePolicyChange(ctx context.Context, zlog zerolog.Logger, ag
Int64("rev.coordinatorIdx", rev.CoordinatorIdx).
Msg("ack policy revision")

if ok && rev.PolicyID == agent.PolicyID && (rev.RevisionIdx > currRev ||
(rev.RevisionIdx == currRev && rev.CoordinatorIdx > currCoord)) {
if ok && rev.PolicyID == agent.PolicyID &&
(rev.RevisionIdx > currRev ||
(rev.RevisionIdx == currRev && rev.CoordinatorIdx > currCoord)) {
found = true
currRev = rev.RevisionIdx
currCoord = rev.CoordinatorIdx
@@ -349,17 +351,7 @@ func (ack *AckT) handlePolicyChange(ctx context.Context, zlog zerolog.Logger, ag
return nil
}

sz := len(agent.DefaultAPIKeyHistory)
if sz > 0 {
ids := make([]string, sz)
for i := 0; i < sz; i++ {
ids[i] = agent.DefaultAPIKeyHistory[i].ID
}
log.Info().Strs("ids", ids).Msg("Invalidate old API keys")
if err := ack.bulk.APIKeyInvalidate(ctx, ids...); err != nil {
log.Info().Err(err).Strs("ids", ids).Msg("Failed to invalidate API keys")
}
}
ack.invalidateAPIKeys(ctx, agent)

body := makeUpdatePolicyBody(
agent.PolicyID,
@@ -385,8 +377,24 @@ func (ack *AckT) handlePolicyChange(ctx context.Context, zlog zerolog.Logger, ag
return errors.Wrap(err, "handlePolicyChange update")
}

func (ack *AckT) invalidateAPIKeys(ctx context.Context, agent *model.Agent) {
var ids []string
for _, out := range agent.Outputs {
Copy link
Contributor

@michalpristas michalpristas Aug 9, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

more of a question: is Outputs new outputs or old outputs?
what happens in case you change output (replace output A with output B so output A is no longer part of the policy) in policy to different ES? will this contain old output so we can invalidate apikeys?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these are the outputs in the agent document. the current ones, there isn't really new or old output here.

what happens in case you change output in policy to different ES

it all breaks as currently fleet-server cannot support any other ES besides it own ES. Also the UI does not let the user input any credentials to access ES

for _, k := range out.ToRetireAPIKeyIds {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q: when this is cleared?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

below, within the if

ids = append(ids, k.ID)
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doesn't look like toRetire slice is used anywhere besides collecting the ids from it in the next loop. maybe can collect the IDs in one pass right away?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the problem is that ToRetireAPIKeyIds is another slice. Thus I'd need to iterate over each out.ToRetireAPIKeyIds anyway. But you do have a point, I can simplify the code.


if len(ids) > 0 {
log.Info().Strs("fleet.policy.apiKeyIDsToRetire", ids).Msg("Invalidate old API keys")
if err := ack.bulk.APIKeyInvalidate(ctx, ids...); err != nil {
log.Info().Err(err).Strs("ids", ids).Msg("Failed to invalidate API keys")
}
}
}

func (ack *AckT) handleUnenroll(ctx context.Context, zlog zerolog.Logger, agent *model.Agent) error {
apiKeys := _getAPIKeyIDs(agent)
apiKeys := agent.APIKeyIDs()
if len(apiKeys) > 0 {
zlog = zlog.With().Strs(LogAPIKeyID, apiKeys).Logger()

@@ -440,17 +448,6 @@ func (ack *AckT) handleUpgrade(ctx context.Context, zlog zerolog.Logger, agent *
return nil
}

func _getAPIKeyIDs(agent *model.Agent) []string {
keys := make([]string, 0, 1)
if agent.AccessAPIKeyID != "" {
keys = append(keys, agent.AccessAPIKeyID)
}
if agent.DefaultAPIKeyID != "" {
keys = append(keys, agent.DefaultAPIKeyID)
}
return keys
}

// Generate an update script that validates that the policy_id
// has not changed underneath us by an upstream process (Kibana or otherwise).
// We have a race condition where a user could have assigned a new policy to
39 changes: 38 additions & 1 deletion internal/pkg/api/handleAck_test.go
Original file line number Diff line number Diff line change
@@ -15,13 +15,14 @@ import (
"net/http"
"testing"

"github.com/google/go-cmp/cmp"

"github.com/elastic/fleet-server/v7/internal/pkg/cache"
"github.com/elastic/fleet-server/v7/internal/pkg/config"
"github.com/elastic/fleet-server/v7/internal/pkg/es"
"github.com/elastic/fleet-server/v7/internal/pkg/model"
ftesting "github.com/elastic/fleet-server/v7/internal/pkg/testing"
testlog "github.com/elastic/fleet-server/v7/internal/pkg/testing/log"
"github.com/google/go-cmp/cmp"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
@@ -439,3 +440,39 @@ func TestHandleAckEvents(t *testing.T) {
})
}
}

func TestInvalidateAPIKeys(t *testing.T) {
toRetire1 := []model.ToRetireAPIKeyIdsItems{{
ID: "toRetire1",
}}
toRetire2 := []model.ToRetireAPIKeyIdsItems{{
ID: "toRetire2_0",
}, {
ID: "toRetire2_1",
}}
var toRetire3 []model.ToRetireAPIKeyIdsItems

want := []string{"toRetire1", "toRetire2_0", "toRetire2_1"}

agent := model.Agent{
Outputs: map[string]*model.PolicyOutput{
"1": {ToRetireAPIKeyIds: toRetire1},
"2": {ToRetireAPIKeyIds: toRetire2},
"3": {ToRetireAPIKeyIds: toRetire3},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: any handling for the same ids in the different outputs? probably not possible in real life scenario.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

any handling for the same ids in the different outputs?

no, it should not happen. If it happens, it's either another bug, or the same I'm trying to fix. Anyway, here we're invalidating them, so it'd be fine, we'd try to invalidate the same key twice

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One thing, that error would be bubbled up in the call would that be a problem for other execution, how idempotent the call is?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idempotent part on on ES side. Because of this bug, there were calls to the invalidate API with the same API key listed twice. As far as I could see, there was no problem.

},
}

bulker := ftesting.NewMockBulk()
bulker.On("APIKeyInvalidate",
context.Background(), mock.MatchedBy(func(ids []string) bool {
// if A contains B and B contains A => A = B
return assert.Subset(t, ids, want) &&
assert.Subset(t, want, ids)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TIL, never use subset before.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Neither had I :)

})).
Return(nil)

ack := &AckT{bulk: bulker}
ack.invalidateAPIKeys(context.Background(), &agent)

bulker.AssertExpectations(t)
}
15 changes: 7 additions & 8 deletions internal/pkg/api/handleCheckin.go
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@ import (
"compress/gzip"
"context"
"encoding/json"
"fmt"
"math/rand"
"net/http"
"reflect"
@@ -60,7 +61,6 @@ func (rt Router) handleCheckin(w http.ResponseWriter, r *http.Request, ps httpro
Logger()

err := rt.ct.handleCheckin(&zlog, w, r, id)

if err != nil {
cntCheckin.IncError(err)
resp := NewHTTPErrResp(err)
@@ -430,13 +430,13 @@ func convertActions(agentID string, actions []model.Action) ([]ActionResp, strin
//
func processPolicy(ctx context.Context, zlog zerolog.Logger, bulker bulk.Bulk, agentID string, pp *policy.ParsedPolicy) (*ActionResp, error) {
zlog = zlog.With().
Str("ctx", "processPolicy").
Int64("policyRevision", pp.Policy.RevisionIdx).
Int64("policyCoordinator", pp.Policy.CoordinatorIdx).
Str("fleet.ctx", "processPolicy").
Int64("fleet.policyRevision", pp.Policy.RevisionIdx).
Int64("fleet.policyCoordinator", pp.Policy.CoordinatorIdx).
Str(LogPolicyID, pp.Policy.PolicyID).
Logger()

// Repull and decode the agent object. Do not trust the cache.
// Repull and decode the agent object. Do not trust the cache.
agent, err := dl.FindAgent(ctx, bulker, dl.QueryAgentByID, dl.FieldID, agentID)
if err != nil {
zlog.Error().Err(err).Msg("fail find agent record")
@@ -446,7 +446,6 @@ func processPolicy(ctx context.Context, zlog zerolog.Logger, bulker bulk.Bulk, a
// Parse the outputs maps in order to prepare the outputs
const outputsProperty = "outputs"
outputs, err := smap.Parse(pp.Fields[outputsProperty])

if err != nil {
return nil, err
}
@@ -458,9 +457,9 @@ func processPolicy(ctx context.Context, zlog zerolog.Logger, bulker bulk.Bulk, a
// Iterate through the policy outputs and prepare them
for _, policyOutput := range pp.Outputs {
err = policyOutput.Prepare(ctx, zlog, bulker, &agent, outputs)

if err != nil {
return nil, err
return nil, fmt.Errorf("failed to prepare output %q: %w",
policyOutput.Name, err)
}
}

11 changes: 8 additions & 3 deletions internal/pkg/api/handleEnroll.go
Original file line number Diff line number Diff line change
@@ -53,7 +53,6 @@ type EnrollerT struct {
}

func NewEnrollerT(verCon version.Constraints, cfg *config.Server, bulker bulk.Bulk, c cache.Cache) (*EnrollerT, error) {

log.Info().
Interface("limits", cfg.Limits.EnrollLimit).
Msg("Setting config enroll_limit")
@@ -187,7 +186,13 @@ func (et *EnrollerT) processRequest(rb *rollback.Rollback, zlog zerolog.Logger,
return et._enroll(r.Context(), rb, zlog, req, erec.PolicyID, ver)
}

func (et *EnrollerT) _enroll(ctx context.Context, rb *rollback.Rollback, zlog zerolog.Logger, req *EnrollRequest, policyID, ver string) (*EnrollResponse, error) {
func (et *EnrollerT) _enroll(
ctx context.Context,
rb *rollback.Rollback,
zlog zerolog.Logger,
req *EnrollRequest,
policyID,
ver string) (*EnrollResponse, error) {

if req.SharedID != "" {
// TODO: Support pre-existing install
@@ -427,7 +432,7 @@ func generateAccessAPIKey(ctx context.Context, bulk bulk.Bulk, agentID string) (
agentID,
"",
[]byte(kFleetAccessRolesJSON),
apikey.NewMetadata(agentID, apikey.TypeAccess),
apikey.NewMetadata(agentID, "", apikey.TypeAccess),
)
}

61 changes: 61 additions & 0 deletions internal/pkg/apikey/apikey.go
Original file line number Diff line number Diff line change
@@ -6,12 +6,18 @@
package apikey

import (
"bytes"
"context"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"net/http"
"strings"
"unicode/utf8"

"github.com/elastic/go-elasticsearch/v7"
"github.com/elastic/go-elasticsearch/v7/esapi"
)

const (
@@ -28,6 +34,61 @@ var (

var AuthKey = http.CanonicalHeaderKey("Authorization")

// APIKeyMetadata tracks Metadata associated with an APIKey.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you give an example of what would be tracker and why we are tracking it?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just moves it from another file. But it's the metadata on the ES document for an API key

type APIKeyMetadata struct {
ID string
Metadata Metadata
}

// Read gathers APIKeyMetadata from Elasticsearch using the given client.
func Read(ctx context.Context, client *elasticsearch.Client, id string) (*APIKeyMetadata, error) {
opts := []func(*esapi.SecurityGetAPIKeyRequest){
client.Security.GetAPIKey.WithContext(ctx),
client.Security.GetAPIKey.WithID(id),
}

res, err := client.Security.GetAPIKey(
opts...,
)
if err != nil {
return nil, fmt.Errorf("request to elasticsearch failed: %w", err)
}
defer res.Body.Close()

if res.IsError() {
return nil, fmt.Errorf("%s: %w", res.String(), ErrAPIKeyNotFound)
}

type APIKeyResponse struct {
ID string `json:"id"`
Metadata Metadata `json:"metadata"`
}
type GetAPIKeyResponse struct {
APIKeys []APIKeyResponse `json:"api_keys"`
}

var buff bytes.Buffer
if _, err := buff.ReadFrom(res.Body); err != nil {
return nil, fmt.Errorf("could not read from response body: %w", err)
}

var resp GetAPIKeyResponse
if err = json.Unmarshal(buff.Bytes(), &resp); err != nil {
aleksmaus marked this conversation as resolved.
Show resolved Hide resolved
return nil, fmt.Errorf(
"could not Unmarshal elasticsearch GetAPIKeyResponse: %w", err)
}

if len(resp.APIKeys) == 0 {
return nil, ErrAPIKeyNotFound
}

first := resp.APIKeys[0]
return &APIKeyMetadata{
ID: first.ID,
Metadata: first.Metadata,
}, nil
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is only used for testing AFAIK? Right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, it's used to invalidate API keys as well

// APIKey is used to represent an Elasticsearch API Key.
type APIKey struct {
ID string
Loading