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

flare shipping #1352

Merged
merged 55 commits into from
Oct 12, 2023
Merged
Show file tree
Hide file tree
Changes from 42 commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
ec4139a
first pass at flare shipping, needs work
James-Pickett Sep 13, 2023
3e9fb7c
Merge branch 'main' into james/flare-shipping
James-Pickett Sep 13, 2023
1722e41
little fixes
James-Pickett Sep 13, 2023
5692db6
added tests for signature, errors, add funcs for default paths
James-Pickett Sep 14, 2023
1e404fc
Merge branch 'main' into james/flare-shipping
James-Pickett Sep 15, 2023
72be50e
more iteration, feedback
James-Pickett Sep 15, 2023
31eb6bc
continue even if host name error
James-Pickett Sep 15, 2023
e68dc60
send error when hostname fails
James-Pickett Sep 15, 2023
f12386f
update test names
James-Pickett Sep 15, 2023
47972c9
fix dir and pkg names
James-Pickett Sep 15, 2023
eb7cbc4
Merge branch 'main' into james/flare-shipping
James-Pickett Sep 15, 2023
5336396
add action for flare
James-Pickett Sep 19, 2023
84f5988
Update pkg/launcher/options.go
James-Pickett Sep 19, 2023
d6579b2
fix flag name
James-Pickett Sep 19, 2023
4a8be17
adds note to flare consumer
James-Pickett Sep 21, 2023
9d53e22
fix tests
James-Pickett Sep 21, 2023
1682d62
Merge branch 'main' into james/flare-shipping
James-Pickett Sep 25, 2023
358e81e
made shipper an io.writecloser
James-Pickett Sep 26, 2023
6f29a71
add cmdline arg for upload url, defer closing iowritecloser
James-Pickett Sep 26, 2023
98c05fd
ergonomics
James-Pickett Sep 26, 2023
a359e4d
Merge branch 'main' into james/flare-shipping
James-Pickett Sep 26, 2023
e075c92
fix shipper tests
James-Pickett Sep 26, 2023
bc6f580
add upload url to flare consumer
James-Pickett Sep 26, 2023
35d79b7
stop copying body for signing, get console users instead of current u…
James-Pickett Sep 27, 2023
e5163aa
Merge branch 'main' into james/flare-shipping
James-Pickett Sep 27, 2023
af1a307
fix current users
James-Pickett Sep 27, 2023
c581de3
rename user name to try and fool codeQL
James-Pickett Sep 27, 2023
9c18d59
Merge branch 'main' into james/flare-shipping
James-Pickett Sep 27, 2023
9361760
Merge branch 'main' into james/flare-shipping
James-Pickett Sep 28, 2023
5be0bff
updated to use io.pipes to ship flare
James-Pickett Sep 28, 2023
1c6ff56
Merge branch 'main' into james/flare-shipping
James-Pickett Sep 28, 2023
81ceb84
add hardware keys to signature if available
James-Pickett Sep 28, 2023
f161ac0
better sign func
James-Pickett Sep 28, 2023
50a25b0
now use same flare command for local and upload
James-Pickett Sep 29, 2023
5d43ac8
reduce nesting
James-Pickett Sep 29, 2023
8f45ff3
cleaner shipper
James-Pickett Sep 29, 2023
5a1b6c1
fix flare cmd
James-Pickett Sep 29, 2023
72e1e7c
Merge branch 'main' into james/flare-shipping
James-Pickett Sep 29, 2023
0bcc357
use save option, default to local
James-Pickett Sep 29, 2023
637d328
comment
James-Pickett Oct 2, 2023
453c18b
add docs for server iniitated shipping flow
James-Pickett Oct 2, 2023
839b0ac
remove note from control server flare, drop unneeded flags, fix comments
James-Pickett Oct 3, 2023
ff47a73
use flare upload url option
James-Pickett Oct 3, 2023
242bc8a
put flarerunner struct in flareconsumer file
James-Pickett Oct 3, 2023
8b9d8d1
close zip before closing flare stream, clean up
James-Pickett Oct 4, 2023
750164d
add api headers to signed url request
James-Pickett Oct 5, 2023
a7dbdd2
update tests
James-Pickett Oct 6, 2023
1621350
add upload request url to control data, fix header ordering
James-Pickett Oct 6, 2023
d540887
Merge branch 'main' into james/flare-shipping
James-Pickett Oct 6, 2023
faff0ac
feedback
James-Pickett Oct 10, 2023
4a26160
Merge branch 'main' into james/flare-shipping
James-Pickett Oct 10, 2023
9d4092c
fix tests
James-Pickett Oct 10, 2023
0334b10
maybe appease code ql
James-Pickett Oct 10, 2023
2d3972e
tweaks
James-Pickett Oct 11, 2023
18f7712
set logger in flareconsumer constructor
James-Pickett Oct 12, 2023
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
2 changes: 1 addition & 1 deletion cmd/launcher/doctor.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func runDoctor(args []string) error {
// Doctor assumes a launcher installation (at least partially) exists
// Overriding some of the default values allows options to be parsed making this assumption
launcher.DefaultAutoupdate = true
setDefaultPaths()
launcher.SetDefaultPaths()
James-Pickett marked this conversation as resolved.
Show resolved Hide resolved

opts, err := launcher.ParseOptions("doctor", os.Args[2:])
if err != nil {
Expand Down
73 changes: 55 additions & 18 deletions cmd/launcher/flare.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import (
"context"
"flag"
"fmt"
"os"
"path/filepath"
Expand All @@ -11,46 +12,82 @@
"github.com/kolide/kit/ulid"
"github.com/kolide/launcher/pkg/agent/flags"
"github.com/kolide/launcher/pkg/agent/knapsack"
"github.com/kolide/launcher/pkg/agent/storage/inmemory"
"github.com/kolide/launcher/pkg/debug/checkups"
"github.com/kolide/launcher/pkg/debug/shipper"
"github.com/kolide/launcher/pkg/launcher"
"github.com/peterbourgon/ff/v3"
)

// sudo /usr/local/kolide-k2/bin/launcher flareupload "note" --debug_upload_request_url="https://example.com"
James-Pickett marked this conversation as resolved.
Show resolved Hide resolved
func runFlare(args []string) error {
// Flare assumes a launcher installation (at least partially) exists
// Overriding some of the default values allows options to be parsed making this assumption
// TODO this stuff needs some deeper thinking
launcher.DefaultAutoupdate = true
setDefaultPaths()
_ = launcher.DefaultBinDirectoryPath
launcher.SetDefaultPaths()

opts, err := launcher.ParseOptions("flare", args)
var (
flagset = flag.NewFlagSet("flare", flag.ExitOnError)
flSave = flagset.String(
"save",
"local",
"local | upload",
)
flNote = flagset.String(
"note",
"",
"note used in URL upload request",
)
James-Pickett marked this conversation as resolved.
Show resolved Hide resolved
flUploadRequestURL = flagset.String(

Check failure on line 42 in cmd/launcher/flare.go

View workflow job for this annotation

GitHub Actions / lint (macos-latest)

flUploadRequestURL declared and not used (typecheck)

Check failure on line 42 in cmd/launcher/flare.go

View workflow job for this annotation

GitHub Actions / lint (macos-latest)

flUploadRequestURL declared and not used (typecheck)

Check failure on line 42 in cmd/launcher/flare.go

View workflow job for this annotation

GitHub Actions / launcher (ubuntu-20.04)

flUploadRequestURL declared and not used

Check failure on line 42 in cmd/launcher/flare.go

View workflow job for this annotation

GitHub Actions / launcher (macos-12)

flUploadRequestURL declared and not used

Check failure on line 42 in cmd/launcher/flare.go

View workflow job for this annotation

GitHub Actions / lint (ubuntu-latest)

flUploadRequestURL declared and not used (typecheck)

Check failure on line 42 in cmd/launcher/flare.go

View workflow job for this annotation

GitHub Actions / lint (ubuntu-latest)

flUploadRequestURL declared and not used (typecheck)

Check failure on line 42 in cmd/launcher/flare.go

View workflow job for this annotation

GitHub Actions / launcher (windows-latest)

flUploadRequestURL declared and not used
Fixed Show fixed Hide fixed
"upload_request_url",
"",
"URL to request a signed upload URL",
)
)

if err := ff.Parse(flagset, args, ff.WithEnvVarNoPrefix()); err != nil {
return fmt.Errorf("parsing flags: %w", err)
}

if *flSave != "local" && *flSave != "upload" {
return fmt.Errorf("invalid save option: %s, expected local or upload", *flSave)
}

// were passing an empty array here just to get the default options
opts, err := launcher.ParseOptions("flareupload", make([]string, 0))
if err != nil {
return err
}

logger := log.NewLogfmtLogger(os.Stdout)
fcOpts := []flags.Option{flags.WithCmdLineOpts(opts)}
flagController := flags.NewFlagController(logger, inmemory.NewStore(logger), fcOpts...)

k := knapsack.New(nil, flagController, nil)
ctx := context.Background()

if *flSave == "upload" {
shipper, err := shipper.New(k, shipper.WithNote(*flNote))
if err != nil {
return err
}
return checkups.RunFlare(ctx, k, shipper, checkups.StandaloneEnviroment)
}

// saving flare locally
var (
dirPath = env.String("KOLIDE_AGENT_FLARE_ZIP_DIR_PATH", "")
)

id := ulid.New()
reportName := fmt.Sprintf("kolide_agent_flare_report_%s", id)
reportName := fmt.Sprintf("kolide_agent_flare_report_%s", ulid.New())
reportPath := fmt.Sprintf("%s.zip", filepath.Join(dirPath, reportName))
James-Pickett marked this conversation as resolved.
Show resolved Hide resolved

flare, err := os.Create(reportPath)
flareFile, err := os.Create(reportPath)
if err != nil {
return fmt.Errorf("creating flare file (%s): %w", reportPath, err)
}
defer func() {
_ = flare.Close()
}()
James-Pickett marked this conversation as resolved.
Show resolved Hide resolved

logger := log.NewLogfmtLogger(os.Stdout)
fcOpts := []flags.Option{flags.WithCmdLineOpts(opts)}
flagController := flags.NewFlagController(logger, nil, fcOpts...)
k := knapsack.New(nil, flagController, nil)

ctx := context.Background()
checkups.RunFlare(ctx, k, flare, checkups.StandaloneEnviroment)
defer flareFile.Close()

return nil
return checkups.RunFlare(ctx, k, flareFile, checkups.StandaloneEnviroment)
}
4 changes: 4 additions & 0 deletions cmd/launcher/launcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"github.com/kolide/launcher/cmd/launcher/internal/updater"
"github.com/kolide/launcher/ee/control/actionqueue"
"github.com/kolide/launcher/ee/control/consumers/acceleratecontrolconsumer"
"github.com/kolide/launcher/ee/control/consumers/flareconsumer"
"github.com/kolide/launcher/ee/control/consumers/keyvalueconsumer"
"github.com/kolide/launcher/ee/control/consumers/notificationconsumer"
desktopRunner "github.com/kolide/launcher/ee/desktop/runner"
Expand Down Expand Up @@ -324,6 +325,9 @@ func runLauncher(ctx context.Context, cancel func(), opts *launcher.Options) err
// register accelerate control consumer
actionsQueue.RegisterActor(acceleratecontrolconsumer.AccelerateControlSubsystem, acceleratecontrolconsumer.New(k))

// register flare consumer
actionsQueue.RegisterActor(flareconsumer.FlareSubsystem, flareconsumer.New(k))

// create notification consumer
notificationConsumer, err := notificationconsumer.NewNotifyConsumer(
runner,
Expand Down
30 changes: 0 additions & 30 deletions cmd/launcher/paths.go

This file was deleted.

25 changes: 25 additions & 0 deletions ee/consoleuser/consoleuser.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package consoleuser

import (
"context"
"os/user"
)

func CurrentUsers(ctx context.Context) ([]*user.User, error) {
currentUids, err := CurrentUids(ctx)
if err != nil {
return nil, err
}

users := make([]*user.User, len(currentUids))
for i, uid := range currentUids {
u, err := user.LookupId(uid)
if err != nil {
return nil, err
}

users[i] = u
}

return users, nil
}
58 changes: 58 additions & 0 deletions ee/control/consumers/flareconsumer/flareconsumer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package flareconsumer

import (
"context"
"encoding/json"
"errors"
"fmt"
"io"

"github.com/kolide/launcher/pkg/agent/types"
"github.com/kolide/launcher/pkg/debug/shipper"
)

const (
// Identifier for this consumer.
FlareSubsystem = "flare"
)

type FlareConsumer struct {
flarer flarer
knapsack types.Knapsack
// newFlareStream is assigned to a field so it can be mocked in tests
James-Pickett marked this conversation as resolved.
Show resolved Hide resolved
newFlareStream func(uploadURL string) (io.WriteCloser, error)
}

type flarer interface {
RunFlare(ctx context.Context, k types.Knapsack, flareStream io.WriteCloser) error
}

func New(knapsack types.Knapsack) *FlareConsumer {
return &FlareConsumer{
flarer: &FlareRunner{},
knapsack: knapsack,
newFlareStream: func(uploadURL string) (io.WriteCloser, error) {
return shipper.New(knapsack, shipper.WithUploadURL(uploadURL))
},
}
}

func (fc *FlareConsumer) Do(data io.Reader) error {
if fc.flarer == nil {
return errors.New("flarer is nil")
}

flareData := struct {
UploadURL string `json:"upload_url"`
}{}

if err := json.NewDecoder(data).Decode(&flareData); err != nil {
return fmt.Errorf("failed to decode key-value json: %w", err)
}

flareStream, err := fc.newFlareStream(flareData.UploadURL)
if err != nil {
return fmt.Errorf("failed to create flare stream: %w", err)
}
return fc.flarer.RunFlare(context.Background(), fc.knapsack, flareStream)
}
48 changes: 48 additions & 0 deletions ee/control/consumers/flareconsumer/flareconsumer_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package flareconsumer

import (
"bytes"
"io"
"testing"

"github.com/kolide/launcher/ee/control/consumers/flareconsumer/mocks"
knapsackMock "github.com/kolide/launcher/pkg/agent/types/mocks"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
)

func TestFlareConsumer(t *testing.T) {
t.Parallel()

tests := []struct {
name string
flarer func(t *testing.T) flarer
errAssertion require.ErrorAssertionFunc
}{
{
name: "happy path",
flarer: func(t *testing.T) flarer {
flarer := mocks.NewFlarer(t)
flarer.On("RunFlare", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil)
return flarer
},
errAssertion: require.NoError,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()

mockSack := knapsackMock.NewKnapsack(t)
f := New(mockSack)
f.flarer = tt.flarer(t)
f.newFlareStream = func(uploadURL string) (io.WriteCloser, error) {
// whatever, it implements write closer
return &io.PipeWriter{}, nil
}

tt.errAssertion(t, f.Do(bytes.NewBuffer([]byte(`{"upload_url":"https://example.com"}`))))
})
}
}
15 changes: 15 additions & 0 deletions ee/control/consumers/flareconsumer/flarerunner.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package flareconsumer

import (
"context"
"io"

"github.com/kolide/launcher/pkg/agent/types"
"github.com/kolide/launcher/pkg/debug/checkups"
)

type FlareRunner struct{}
James-Pickett marked this conversation as resolved.
Show resolved Hide resolved

func (f *FlareRunner) RunFlare(ctx context.Context, k types.Knapsack, flareStream io.WriteCloser) error {
return checkups.RunFlare(ctx, k, flareStream, checkups.InSituEnvironment)
}
46 changes: 46 additions & 0 deletions ee/control/consumers/flareconsumer/mocks/flarer.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading