Skip to content

Commit

Permalink
stash changes for rebase with exit wrapper updates
Browse files Browse the repository at this point in the history
  • Loading branch information
zackattack01 committed Apr 30, 2024
1 parent b94f084 commit a38204e
Show file tree
Hide file tree
Showing 11 changed files with 197 additions and 22 deletions.
3 changes: 2 additions & 1 deletion cmd/launcher/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/kolide/kit/env"
"github.com/kolide/kit/logutil"
"github.com/kolide/kit/version"
"github.com/kolide/launcher/cmd/launcher/restartservice"
"github.com/kolide/launcher/ee/tuf"
"github.com/kolide/launcher/pkg/autoupdate"
"github.com/kolide/launcher/pkg/contexts/ctxlog"
Expand Down Expand Up @@ -161,7 +162,7 @@ func runSubcommands(systemMultiSlogger *multislogger.MultiSlogger) error {
case "secure-enclave":
run = runSecureEnclave
case "restart-service": // note only implemented for windows
run = runRestartService
run = restartservice.RunRestartService
default:
return fmt.Errorf("unknown subcommand %s", os.Args[1])
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//go:build !windows
// +build !windows

package main
package restartservice

import (
"errors"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//go:build windows
// +build windows

package main
package restartservice

import (
"context"
Expand All @@ -21,18 +21,19 @@ import (
)

const (
launcherRestartServiceName string = `LauncherKolideRestartSvc`
LauncherRestartServiceName string = `LauncherKolideRestartSvc`
launcherServiceName string = `LauncherKolideK2Svc`
)

type winRestartSvc struct {
systemSlogger, slogger *multislogger.MultiSlogger
opts *launcher.Options
}

func runRestartService(systemSlogger *multislogger.MultiSlogger, args []string) error {
func RunRestartService(systemSlogger *multislogger.MultiSlogger, args []string) error {
logCtx := context.TODO()
systemSlogger.Logger = systemSlogger.Logger.With(
"service", launcherRestartServiceName,
"service", LauncherRestartServiceName,
"version", version.Version().Version,
)

Expand Down Expand Up @@ -68,7 +69,7 @@ func runRestartService(systemSlogger *multislogger.MultiSlogger, args []string)
}

localSlogger.Logger = localSlogger.Logger.With(
"service", launcherRestartServiceName,
"service", LauncherRestartServiceName,
"version", version.Version().Version,
)

Expand All @@ -89,7 +90,7 @@ func runRestartService(systemSlogger *multislogger.MultiSlogger, args []string)
}
}()

if err := svc.Run(launcherRestartServiceName, &winRestartSvc{
if err := svc.Run(LauncherRestartServiceName, &winRestartSvc{
systemSlogger: systemSlogger,
slogger: localSlogger,
opts: opts,
Expand Down Expand Up @@ -154,7 +155,7 @@ func (w *winRestartSvc) Execute(args []string, r <-chan svc.ChangeRequest, chang
default:
w.slogger.Log(ctx, slog.LevelInfo,
"unexpected change request",
"service", launcherRestartServiceName,
"service", LauncherRestartServiceName,
"change_request", fmt.Sprintf("%+v", c),
)
}
Expand Down Expand Up @@ -217,3 +218,5 @@ func runLauncherRestartService(ctx context.Context, w *winRestartSvc) error {
}
}
}

// NtQuerySystemInformation - SystemProcessorPowerInformation
File renamed without changes.
15 changes: 8 additions & 7 deletions cmd/launcher/svc_config_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"os"
"time"

"github.com/kolide/launcher/cmd/launcher/restartservice"
"github.com/kolide/launcher/pkg/launcher"

"golang.org/x/sys/windows/registry"
Expand Down Expand Up @@ -244,9 +245,9 @@ func restartService(service *mgr.Service) error {

func checkRestartService(serviceManager *mgr.Mgr, slogger *slog.Logger) {
logCtx := context.TODO()
slogger = slogger.With("target_service", launcherRestartServiceName)
slogger = slogger.With("target_service", restartservice.LauncherRestartServiceName)
// first check if we've already installed the service
existingService, err := serviceManager.OpenService(launcherRestartServiceName)
existingService, err := serviceManager.OpenService(restartservice.LauncherRestartServiceName)
if err == nil {
// if the service already exists, just restart it to ensure it's running from the latest launcher update.
// If this fails, log the error but move on, this service is not worth tying up the main launcher startup.
Expand Down Expand Up @@ -274,7 +275,7 @@ func checkRestartService(serviceManager *mgr.Mgr, slogger *slog.Logger) {
}

svcMgrConf := mgr.Config{
DisplayName: launcherRestartServiceName,
DisplayName: restartservice.LauncherRestartServiceName,
Description: "The Kolide Launcher Restart Service",
StartType: mgr.StartAutomatic,
ErrorControl: mgr.ErrorNormal,
Expand All @@ -288,7 +289,7 @@ func checkRestartService(serviceManager *mgr.Mgr, slogger *slog.Logger) {
serviceArgs = append(serviceArgs, os.Args[2:]...)

restartService, err := serviceManager.CreateService(
launcherRestartServiceName,
restartservice.LauncherRestartServiceName,
currentExe,
svcMgrConf,
serviceArgs...,
Expand All @@ -315,23 +316,23 @@ func checkRestartService(serviceManager *mgr.Mgr, slogger *slog.Logger) {
if err = restartService.SetRecoveryActions(recoveryActions, 10800); err != nil {
slogger.Log(context.TODO(), slog.LevelWarn,
"unable to set recovery actions for service installation, proceeding",
"service", launcherRestartServiceName,
"service", restartservice.LauncherRestartServiceName,
"err", err,
)
}

if err = restartService.SetRecoveryActionsOnNonCrashFailures(true); err != nil {
slogger.Log(context.TODO(), slog.LevelWarn,
"unable to set RecoveryActionsOnNonCrashFailures flag, proceeding",
"service", launcherRestartServiceName,
"service", restartservice.LauncherRestartServiceName,
"err", err,
)
}

if err = restartService.Start(); err != nil {
slogger.Log(context.TODO(), slog.LevelWarn,
"unable to start launcher restart service",
"service", launcherRestartServiceName,
"service", restartservice.LauncherRestartServiceName,
"err", err,
)
}
Expand Down
1 change: 1 addition & 0 deletions cmd/launcher/svc_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"github.com/kolide/launcher/pkg/log/multislogger"
"github.com/pkg/errors"

"golang.org/x/sys/windows"
"golang.org/x/sys/windows/svc"
"golang.org/x/sys/windows/svc/debug"
)
Expand Down
106 changes: 101 additions & 5 deletions ee/agent/storage/sqlite/keyvalue_store_sqlite.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,21 @@ import (
_ "modernc.org/sqlite"
)

type storeName int
type StoreName int

const (
StartupSettingsStore storeName = iota
StartupSettingsStore StoreName = iota
RestartServiceLogStore StoreName = 1
)

// String translates the exported int constant to the actual name of the
// supported table in the sqlite database.
func (s storeName) String() string {
func (s StoreName) String() string {
switch s {
case StartupSettingsStore:
return "startup_settings"
case RestartServiceLogStore:
return "restart_service_logs"
}

return ""
Expand All @@ -44,9 +47,14 @@ type sqliteStore struct {
tableName string
}

type sqliteColumns struct {
pk string
valueColumn string
}

// OpenRO opens a connection to the database in the given root directory; it does
// not perform database creation or migration.
func OpenRO(ctx context.Context, rootDirectory string, name storeName) (*sqliteStore, error) {
func OpenRO(ctx context.Context, rootDirectory string, name StoreName) (*sqliteStore, error) {
if name.String() == "" {
return nil, fmt.Errorf("unsupported table %d", name)
}
Expand All @@ -66,7 +74,7 @@ func OpenRO(ctx context.Context, rootDirectory string, name storeName) (*sqliteS

// OpenRW creates a validated database connection to a validated database, performing
// migrations if necessary.
func OpenRW(ctx context.Context, rootDirectory string, name storeName) (*sqliteStore, error) {
func OpenRW(ctx context.Context, rootDirectory string, name StoreName) (*sqliteStore, error) {
if name.String() == "" {
return nil, fmt.Errorf("unsupported table %d", name)
}
Expand Down Expand Up @@ -309,3 +317,91 @@ ON CONFLICT (name) DO UPDATE SET value=excluded.value;`

return deletedKeys, nil
}

func (s *sqliteStore) getColumns() *sqliteColumns {
switch s.tableName {
case StartupSettingsStore.String():
return &sqliteColumns{pk: "name", valueColumn: "value"}
case RestartServiceLogStore.String():
return &sqliteColumns{pk: "timestamp", valueColumn: "log"}
}

return nil
}

func (s *sqliteStore) AppendValue(timestamp int64, value []byte) error {
colInfo := s.getColumns()
if s == nil || s.conn == nil || colInfo == nil {
return errors.New("store is nil")
}

if s.readOnly {
return errors.New("cannot perform update with RO connection")
}

insertSql := fmt.Sprintf(
`INSERT INTO %s (%s, %s) VALUES (?, ?)`,
s.tableName,
colInfo.pk,
colInfo.valueColumn,
)

if _, err := s.conn.Exec(insertSql, timestamp, value); err != nil {
return fmt.Errorf("appending row into %s: %w", s.tableName, err)
}

return nil
}

func (s *sqliteStore) ForEach(fn func(rowid, timestamp int64, v []byte) error) error {
colInfo := s.getColumns()
if s == nil || s.conn == nil || colInfo == nil {
return errors.New("store is nil")
}

query := fmt.Sprintf(
`SELECT %s, %s FROM %s;`,
colInfo.pk,
colInfo.valueColumn,
s.tableName,
)

rows, err := s.conn.Query(query)
if err != nil {
return fmt.Errorf("issuing foreach query: %w", err)
}

defer rows.Close()

for rows.Next() {
var rowid int64
var timestamp int64
var result string
if err := rows.Scan(&rowid, &timestamp, &result); err != nil {
return fmt.Errorf("scanning foreach query: %w", err)
}

if err := fn(rowid, timestamp, []byte(result)); err != nil {
return fmt.Errorf("caller error during foreach iteration: %w", err)
}
}

return nil
}

func (s *sqliteStore) Count() (int, error) {
if s == nil || s.conn == nil {
return 0, errors.New("store is nil")
}

// It's fine to interpolate the table name into the query because
// we require the table name to be in our allowlist `supportedTables`
query := fmt.Sprintf(`SELECT COUNT(*) FROM %s;`, s.tableName)

var countValue int
if err := s.conn.QueryRow(query).Scan(&countValue); err != nil {
return 0, fmt.Errorf("querying for %s table count: %w", s.tableName, err)
}

return countValue, nil
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DROP TABLE IF EXISTS restart_service_logs;
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
CREATE TABLE IF NOT EXISTS restart_service_logs (
timestamp INT NOT NULL,
log TEXT
);
31 changes: 30 additions & 1 deletion ee/agent/types/keyvalue_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,21 @@ type Iterator interface {
ForEach(fn func(k, v []byte) error) error
}

// TimestampedIterator is a read-only interface for iterating timestamped data.
type TimestampedIterator interface {
// ForEach executes a function for each timestamp/value pair in a store.
// If the provided function returns an error then the iteration is stopped and
// the error is returned to the caller. The provided function must not modify
// the store; this will result in undefined behavior.
ForEach(fn func(rowid, timestamp int64, v []byte) error) error
}

// TimestampedAppender is an interface for supporting the addition of timestamped values to a store
type TimestampedAppender interface {
// AppendValue takes the timestamp, and marshalled value for insertion as a new row
AppendValue(timestamp int64, value []byte) error
}

// Updater is an interface for bulk replacing data in a key/value store.
type Updater interface {
// Update takes a map of key-value pairs, and inserts
Expand Down Expand Up @@ -61,10 +76,14 @@ type GetterSetter interface {
Setter
}

type Closer interface {
Close() error
}

// GetterCloser extends the Getter interface with a Close method.
type GetterCloser interface {
Getter
Close() error
Closer
}

// GetterUpdaterCloser groups the Get, Update, and Close methods.
Expand Down Expand Up @@ -99,5 +118,15 @@ type GetterSetterDeleterIteratorUpdaterCounterAppender interface {
Appender
}

// TimestampedIteratorAppenderCounterCloser is an interface to support the storage and retrieval of
// sets of timestamped values. This can be used where a strict key/value interface may not suffice,
// e.g. for writing logs or historical records to sqlite
type TimestampedIteratorAppenderCounterCloser interface {
TimestampedIterator
TimestampedAppender
Counter
Closer
}

// Convenient alias for a key value store that supports all methods
type KVStore = GetterSetterDeleterIteratorUpdaterCounterAppender
Loading

0 comments on commit a38204e

Please sign in to comment.