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

Populate agent.id field in .fleet-agents index #609

Merged
merged 4 commits into from
Aug 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
11 changes: 8 additions & 3 deletions cmd/fleet/handleCheckin.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,11 +152,16 @@ func (ct *CheckinT) _handleCheckin(zlog zerolog.Logger, w http.ResponseWriter, r
return err
}

err = validateUserAgent(r, ct.verCon)
ver, err := validateUserAgent(r, ct.verCon)
if err != nil {
return err
}

var newVer string
if ver != agent.Agent.Version {
newVer = ver
}

// Metrics; serenity now.
dfunc := cntCheckin.IncStart()
defer dfunc()
Expand Down Expand Up @@ -225,7 +230,7 @@ func (ct *CheckinT) _handleCheckin(zlog zerolog.Logger, w http.ResponseWriter, r
defer longPoll.Stop()

// Intial update on checkin, and any user fields that might have changed
ct.bc.CheckIn(agent.Id, req.Status, rawMeta, seqno)
ct.bc.CheckIn(agent.Id, req.Status, rawMeta, seqno, newVer)

// Initial fetch for pending actions
var (
Expand Down Expand Up @@ -262,7 +267,7 @@ func (ct *CheckinT) _handleCheckin(zlog zerolog.Logger, w http.ResponseWriter, r
zlog.Trace().Msg("fire long poll")
break LOOP
case <-tick.C:
ct.bc.CheckIn(agent.Id, req.Status, nil, nil)
ct.bc.CheckIn(agent.Id, req.Status, nil, nil, newVer)
}
}
}
Expand Down
10 changes: 7 additions & 3 deletions cmd/fleet/handleEnroll.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ func (et *EnrollerT) handleEnroll(w http.ResponseWriter, r *http.Request) (*Enro
return nil, err
}

err = validateUserAgent(r, et.verCon)
ver, err := validateUserAgent(r, et.verCon)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -167,10 +167,10 @@ func (et *EnrollerT) handleEnroll(w http.ResponseWriter, r *http.Request) (*Enro

cntEnroll.bodyIn.Add(readCounter.Count())

return _enroll(r.Context(), et.bulker, et.cache, *req, *erec)
return _enroll(r.Context(), et.bulker, et.cache, *req, *erec, ver)
}

func _enroll(ctx context.Context, bulker bulk.Bulk, c cache.Cache, req EnrollRequest, erec model.EnrollmentApiKey) (*EnrollResponse, error) {
func _enroll(ctx context.Context, bulker bulk.Bulk, c cache.Cache, req EnrollRequest, erec model.EnrollmentApiKey, ver string) (*EnrollResponse, error) {

if req.SharedId != "" {
// TODO: Support pre-existing install
Expand Down Expand Up @@ -210,6 +210,10 @@ func _enroll(ctx context.Context, bulker bulk.Bulk, c cache.Cache, req EnrollReq
LocalMetadata: localMeta,
AccessApiKeyId: accessApiKey.Id,
ActionSeqNo: []int64{sqn.UndefinedSeqNo},
Agent: &model.AgentMetadata{
Id: agentId,
Version: ver,
},
}

err = createFleetAgent(ctx, bulker, agentId, agentData)
Expand Down
25 changes: 17 additions & 8 deletions cmd/fleet/userAgent.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,22 +57,31 @@ func maximizePatch(ver *version.Version) string {

// validateUserAgent validates that the User-Agent of the connecting Elastic Agent is valid and that the version is
// supported for this Fleet Server.
func validateUserAgent(r *http.Request, verConst version.Constraints) error {
func validateUserAgent(r *http.Request, verConst version.Constraints) (string, error) {
userAgent := r.Header.Get("User-Agent")
if userAgent == "" {
return ErrInvalidUserAgent
return "", ErrInvalidUserAgent
}
userAgent = strings.ToLower(userAgent)
if !strings.HasPrefix(userAgent, userAgentPrefix) {
return ErrInvalidUserAgent
return "", ErrInvalidUserAgent
}
verSep := strings.Split(strings.TrimPrefix(userAgent, userAgentPrefix), "-")
ver, err := version.NewVersion(verSep[0])

// Trim "elastic agent " prefix
s := strings.TrimPrefix(userAgent, userAgentPrefix)

// Split the version to accommodate versions with suffixes such as v8.0.0-snapshot v8.0.0-alpha1
verSep := strings.Split(s, "-")

// Trim leading and traling spaces
verStr := strings.TrimSpace(verSep[0])

ver, err := version.NewVersion(verStr)
if err != nil {
return ErrInvalidUserAgent
return "", ErrInvalidUserAgent
}
if !verConst.Check(ver) {
return ErrUnsupportedVersion
return "", ErrUnsupportedVersion
}
return nil
return ver.String(), nil
}
2 changes: 1 addition & 1 deletion cmd/fleet/userAgent_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ func TestValidateUserAgent(t *testing.T) {
t.Run(tr.userAgent, func(t *testing.T) {
req := httptest.NewRequest("GET", "/", nil)
req.Header.Set("User-Agent", tr.userAgent)
res := validateUserAgent(req, tr.verCon)
_, res := validateUserAgent(req, tr.verCon)
if tr.err != res {
t.Fatalf("err mismatch: %v != %v", tr.err, res)
}
Expand Down
12 changes: 10 additions & 2 deletions internal/pkg/checkin/bulk.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ func WithFlushInterval(d time.Duration) Opt {
type extraT struct {
meta []byte
seqNo sqn.SeqNo
ver string
}

// Minimize the size of this structure.
Expand Down Expand Up @@ -94,16 +95,17 @@ func (bc *Bulk) timestamp() string {

// WARNING: Bulk will take ownership of fields,
// so do not use after passing in.
func (bc *Bulk) CheckIn(id string, status string, meta []byte, seqno sqn.SeqNo) error {
func (bc *Bulk) CheckIn(id string, status string, meta []byte, seqno sqn.SeqNo, newVer string) error {

// Separate out the extra data to minimize
// the memory footprint of the 90% case of just
// updating the timestamp.
var extra *extraT
if meta != nil || seqno.IsSet() {
if meta != nil || seqno.IsSet() || newVer != "" {
extra = &extraT{
meta: meta,
seqNo: seqno,
ver: newVer,
}
}

Expand Down Expand Up @@ -192,6 +194,12 @@ func (bc *Bulk) flush(ctx context.Context) error {
dl.FieldLastCheckinStatus: pendingData.status, // Set the pending status
}

// If the agent version is not empty it needs to be updated
// Assuming the agent can by upgraded keeping the same id, but incrementing the version
if pendingData.extra.ver != "" {
fields[dl.FieldAgentVersion] = pendingData.extra.ver
}

// Update local metadata if provided
if pendingData.extra.meta != nil {
// Surprise: The json encodeer compacts this raw JSON during
Expand Down
14 changes: 12 additions & 2 deletions internal/pkg/checkin/bulk_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,75 +43,85 @@ func TestBulkSimple(t *testing.T) {

bc := NewBulk(&mockBulk)

const ver = "8.0.0"
cases := []struct {
desc string
id string
status string
meta []byte
seqno sqn.SeqNo
ver string
}{
{
"Simple case",
"simpleId",
"online",
nil,
nil,
"",
},
{
"Singled field case",
"singleFieldId",
"online",
[]byte(`{"hey":"now"}`),
nil,
"",
},
{
"Multi field case",
"multiFieldId",
"online",
[]byte(`{"hey":"now","brown":"cow"}`),
nil,
ver,
},
{
"Multi field nested case",
"multiFieldNestedId",
"online",
[]byte(`{"hey":"now","wee":{"little":"doggie"}}`),
nil,
"",
},
{
"Simple case with seqNo",
"simpleseqno",
"online",
nil,
sqn.SeqNo{1, 2, 3, 4},
ver,
},
{
"Field case with seqNo",
"simpleseqno",
"online",
[]byte(`{"uncle":"fester"}`),
sqn.SeqNo{5, 6, 7, 8},
ver,
},
{
"Unusual status",
"singleFieldId",
"unusual",
nil,
nil,
"",
},
{
"Empty status",
"singleFieldId",
"",
nil,
nil,
"",
},
}

for _, c := range cases {
t.Run(c.desc, func(t *testing.T) {

if err := bc.CheckIn(c.id, c.status, c.meta, c.seqno); err != nil {
if err := bc.CheckIn(c.id, c.status, c.meta, c.seqno, c.ver); err != nil {
t.Fatal(err)
}

Expand Down Expand Up @@ -205,7 +215,7 @@ func benchmarkBulk(n int, flush bool, b *testing.B) {
for i := 0; i < b.N; i++ {

for _, id := range ids {
err := bc.CheckIn(id, "", nil, nil)
err := bc.CheckIn(id, "", nil, nil, "")
if err != nil {
b.Fatal(err)
}
Expand Down
1 change: 1 addition & 0 deletions internal/pkg/dl/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ const (
FieldDefaultApiKeyId = "default_api_key_id"
FieldPolicyOutputPermissionsHash = "policy_output_permissions_hash"
FieldUnenrolledReason = "unenrolled_reason"
FieldAgentVersion = "agent.version"

FieldActive = "active"
FieldUpdatedAt = "updated_at"
Expand Down