mirror of
https://github.com/fleetdm/fleet
synced 2026-05-23 00:49:03 +00:00
Retrieve and store host checkin intervals (#1473)
We now track the `config_tls_refresh`, `distributed_interval` and `logger_tls_period` flag values for each host. Each value is updated by a detail query agains the `osquery_flags` table, because they may be specified outside of Kolide. The flags that can be specified within Kolide are also updated when a config is returned to the host that changes their value. This will enable us to do a more accurate per-host online status calculation as discussed in #1419.
This commit is contained in:
parent
6a3ea3fc8c
commit
d7cd91c0e4
12 changed files with 701 additions and 116 deletions
6
glide.lock
generated
6
glide.lock
generated
|
|
@ -1,5 +1,5 @@
|
|||
hash: 08220902abb9783f0474c20495d92f407f4028b56ab95879b867c0dec4aab7cc
|
||||
updated: 2017-03-29T10:16:52.853564516-07:00
|
||||
hash: 1baa8047c7c6da3ca484e0bfebd881a17181a76ccccbddb2cff087c3f6de97c9
|
||||
updated: 2017-04-05T15:21:30.066640809-07:00
|
||||
imports:
|
||||
- name: github.com/alecthomas/template
|
||||
version: a0175ee3bccc567396460bf5acd36800cb10c49c
|
||||
|
|
@ -128,7 +128,7 @@ imports:
|
|||
subpackages:
|
||||
- mem
|
||||
- name: github.com/spf13/cast
|
||||
version: e31f36ffc91a2ba9ddb72a4b6a607ff9b3d3cb63
|
||||
version: ce135a4ebeee6cfe9a26c93ee0d37825f26113c7
|
||||
- name: github.com/spf13/cobra
|
||||
version: 37c3f8060359192150945916cbc2d72bce804b4d
|
||||
- name: github.com/spf13/jwalterweatherman
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@ import:
|
|||
version: fd703108daeb23d77c124d12978e9b6c4f28f034
|
||||
- package: github.com/spf13/cobra
|
||||
- package: github.com/spf13/viper
|
||||
- package: github.com/spf13/cast
|
||||
- package: gopkg.in/natefinch/lumberjack.v2
|
||||
version: v2.0
|
||||
- package: github.com/golang/mock
|
||||
|
|
@ -69,3 +68,5 @@ import:
|
|||
- package: github.com/ryanuber/go-license
|
||||
- package: github.com/igm/sockjs-go
|
||||
- package: github.com/e-dard/netbug
|
||||
- package: github.com/spf13/cast
|
||||
version: ~1.0.0
|
||||
|
|
|
|||
|
|
@ -173,7 +173,10 @@ func (d *Datastore) SaveHost(host *kolide.Host) error {
|
|||
platform_like = ?,
|
||||
code_name = ?,
|
||||
cpu_logical_cores = ?,
|
||||
seen_time = ?
|
||||
seen_time = ?,
|
||||
distributed_interval = ?,
|
||||
config_tls_refresh = ?,
|
||||
logger_tls_period = ?
|
||||
WHERE id = ?
|
||||
`
|
||||
|
||||
|
|
@ -207,6 +210,9 @@ func (d *Datastore) SaveHost(host *kolide.Host) error {
|
|||
host.CodeName,
|
||||
host.CPULogicalCores,
|
||||
host.SeenTime,
|
||||
host.DistributedInterval,
|
||||
host.ConfigTLSRefresh,
|
||||
host.LoggerTLSPeriod,
|
||||
host.ID)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
package tables
|
||||
|
||||
import "database/sql"
|
||||
|
||||
func init() {
|
||||
MigrationClient.AddMigration(Up_20170331111922, Down_20170331111922)
|
||||
}
|
||||
|
||||
func Up_20170331111922(tx *sql.Tx) error {
|
||||
_, err := tx.Exec(
|
||||
"ALTER TABLE `hosts` " +
|
||||
"ADD COLUMN `distributed_interval` int DEFAULT 0, " +
|
||||
"ADD COLUMN `logger_tls_period` int DEFAULT 0, " +
|
||||
"ADD COLUMN `config_tls_refresh` int DEFAULT 0;",
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func Down_20170331111922(tx *sql.Tx) error {
|
||||
_, err := tx.Exec(
|
||||
"ALTER TABLE `hosts` " +
|
||||
"DROP COLUMN `distributed_interval`, " +
|
||||
"DROP COLUMN `logger_tls_period`, " +
|
||||
"DROP COLUMN `config_tls_refresh`;",
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
|
@ -86,6 +86,9 @@ type Host struct {
|
|||
// can be found in the NetworkInterfaces element with the same ip_address.
|
||||
PrimaryNetworkInterfaceID *uint `json:"primary_ip_id,omitempty" db:"primary_ip_id"`
|
||||
NetworkInterfaces []*NetworkInterface `json:"network_interfaces" db:"-"`
|
||||
DistributedInterval uint `json:"distributed_interval" db:"distributed_interval"`
|
||||
ConfigTLSRefresh uint `json:"config_tls_refresh" db:"config_tls_refresh"`
|
||||
LoggerTLSPeriod uint `json:"logger_tls_period" db:"logger_tls_period"`
|
||||
}
|
||||
|
||||
// HostSummary is a structure which represents a data summary about the total
|
||||
|
|
|
|||
|
|
@ -5,30 +5,33 @@ package mock
|
|||
//go:generate mockimpl -o datastore_appconfig.go "s *AppConfigStore" "kolide.AppConfigStore"
|
||||
//go:generate mockimpl -o datastore_licenses.go "s *LicenseStore" "kolide.LicenseStore"
|
||||
//go:generate mockimpl -o datastore_labels.go "s *LabelStore" "kolide.LabelStore"
|
||||
//go:generate mockimpl -o dateastore_decorators.go "s *DecoratorStore" "kolide.DecoratorStore"
|
||||
//go:generate mockimpl -o datastore_decorators.go "s *DecoratorStore" "kolide.DecoratorStore"
|
||||
//go:generate mockimpl -o datastore_options.go "s *OptionStore" "kolide.OptionStore"
|
||||
//go:generate mockimpl -o datastore_packs.go "s *PackStore" "kolide.PackStore"
|
||||
//go:generate mockimpl -o datastore_hosts.go "s *HostStore" "kolide.HostStore"
|
||||
|
||||
import "github.com/kolide/kolide/server/kolide"
|
||||
|
||||
var _ kolide.Datastore = (*Store)(nil)
|
||||
|
||||
type Store struct {
|
||||
kolide.HostStore
|
||||
kolide.PackStore
|
||||
kolide.CampaignStore
|
||||
kolide.SessionStore
|
||||
kolide.PasswordResetStore
|
||||
kolide.QueryStore
|
||||
kolide.OptionStore
|
||||
kolide.ScheduledQueryStore
|
||||
kolide.FileIntegrityMonitoringStore
|
||||
kolide.YARAStore
|
||||
kolide.TargetStore
|
||||
LicenseStore
|
||||
InviteStore
|
||||
UserStore
|
||||
AppConfigStore
|
||||
LabelStore
|
||||
DecoratorStore
|
||||
HostStore
|
||||
InviteStore
|
||||
LabelStore
|
||||
LicenseStore
|
||||
OptionStore
|
||||
PackStore
|
||||
UserStore
|
||||
}
|
||||
|
||||
func (m *Store) Drop() error {
|
||||
|
|
|
|||
123
server/mock/datastore_hosts.go
Normal file
123
server/mock/datastore_hosts.go
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
// Automatically generated by mockimpl. DO NOT EDIT!
|
||||
|
||||
package mock
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/kolide/kolide/server/kolide"
|
||||
)
|
||||
|
||||
var _ kolide.HostStore = (*HostStore)(nil)
|
||||
|
||||
type NewHostFunc func(host *kolide.Host) (*kolide.Host, error)
|
||||
|
||||
type SaveHostFunc func(host *kolide.Host) error
|
||||
|
||||
type DeleteHostFunc func(hid uint) error
|
||||
|
||||
type HostFunc func(id uint) (*kolide.Host, error)
|
||||
|
||||
type ListHostsFunc func(opt kolide.ListOptions) ([]*kolide.Host, error)
|
||||
|
||||
type EnrollHostFunc func(osqueryHostId string, nodeKeySize int) (*kolide.Host, error)
|
||||
|
||||
type AuthenticateHostFunc func(nodeKey string) (*kolide.Host, error)
|
||||
|
||||
type MarkHostSeenFunc func(host *kolide.Host, t time.Time) error
|
||||
|
||||
type GenerateHostStatusStatisticsFunc func(now time.Time, onlineInterval time.Duration) (online uint, offline uint, mia uint, new uint, err error)
|
||||
|
||||
type SearchHostsFunc func(query string, omit ...uint) ([]*kolide.Host, error)
|
||||
|
||||
type DistributedQueriesForHostFunc func(host *kolide.Host) (map[uint]string, error)
|
||||
|
||||
type HostStore struct {
|
||||
NewHostFunc NewHostFunc
|
||||
NewHostFuncInvoked bool
|
||||
|
||||
SaveHostFunc SaveHostFunc
|
||||
SaveHostFuncInvoked bool
|
||||
|
||||
DeleteHostFunc DeleteHostFunc
|
||||
DeleteHostFuncInvoked bool
|
||||
|
||||
HostFunc HostFunc
|
||||
HostFuncInvoked bool
|
||||
|
||||
ListHostsFunc ListHostsFunc
|
||||
ListHostsFuncInvoked bool
|
||||
|
||||
EnrollHostFunc EnrollHostFunc
|
||||
EnrollHostFuncInvoked bool
|
||||
|
||||
AuthenticateHostFunc AuthenticateHostFunc
|
||||
AuthenticateHostFuncInvoked bool
|
||||
|
||||
MarkHostSeenFunc MarkHostSeenFunc
|
||||
MarkHostSeenFuncInvoked bool
|
||||
|
||||
GenerateHostStatusStatisticsFunc GenerateHostStatusStatisticsFunc
|
||||
GenerateHostStatusStatisticsFuncInvoked bool
|
||||
|
||||
SearchHostsFunc SearchHostsFunc
|
||||
SearchHostsFuncInvoked bool
|
||||
|
||||
DistributedQueriesForHostFunc DistributedQueriesForHostFunc
|
||||
DistributedQueriesForHostFuncInvoked bool
|
||||
}
|
||||
|
||||
func (s *HostStore) NewHost(host *kolide.Host) (*kolide.Host, error) {
|
||||
s.NewHostFuncInvoked = true
|
||||
return s.NewHostFunc(host)
|
||||
}
|
||||
|
||||
func (s *HostStore) SaveHost(host *kolide.Host) error {
|
||||
s.SaveHostFuncInvoked = true
|
||||
return s.SaveHostFunc(host)
|
||||
}
|
||||
|
||||
func (s *HostStore) DeleteHost(hid uint) error {
|
||||
s.DeleteHostFuncInvoked = true
|
||||
return s.DeleteHostFunc(hid)
|
||||
}
|
||||
|
||||
func (s *HostStore) Host(id uint) (*kolide.Host, error) {
|
||||
s.HostFuncInvoked = true
|
||||
return s.HostFunc(id)
|
||||
}
|
||||
|
||||
func (s *HostStore) ListHosts(opt kolide.ListOptions) ([]*kolide.Host, error) {
|
||||
s.ListHostsFuncInvoked = true
|
||||
return s.ListHostsFunc(opt)
|
||||
}
|
||||
|
||||
func (s *HostStore) EnrollHost(osqueryHostId string, nodeKeySize int) (*kolide.Host, error) {
|
||||
s.EnrollHostFuncInvoked = true
|
||||
return s.EnrollHostFunc(osqueryHostId, nodeKeySize)
|
||||
}
|
||||
|
||||
func (s *HostStore) AuthenticateHost(nodeKey string) (*kolide.Host, error) {
|
||||
s.AuthenticateHostFuncInvoked = true
|
||||
return s.AuthenticateHostFunc(nodeKey)
|
||||
}
|
||||
|
||||
func (s *HostStore) MarkHostSeen(host *kolide.Host, t time.Time) error {
|
||||
s.MarkHostSeenFuncInvoked = true
|
||||
return s.MarkHostSeenFunc(host, t)
|
||||
}
|
||||
|
||||
func (s *HostStore) GenerateHostStatusStatistics(now time.Time, onlineInterval time.Duration) (online uint, offline uint, mia uint, new uint, err error) {
|
||||
s.GenerateHostStatusStatisticsFuncInvoked = true
|
||||
return s.GenerateHostStatusStatisticsFunc(now, onlineInterval)
|
||||
}
|
||||
|
||||
func (s *HostStore) SearchHosts(query string, omit ...uint) ([]*kolide.Host, error) {
|
||||
s.SearchHostsFuncInvoked = true
|
||||
return s.SearchHostsFunc(query, omit...)
|
||||
}
|
||||
|
||||
func (s *HostStore) DistributedQueriesForHost(host *kolide.Host) (map[uint]string, error) {
|
||||
s.DistributedQueriesForHostFuncInvoked = true
|
||||
return s.DistributedQueriesForHostFunc(host)
|
||||
}
|
||||
69
server/mock/datastore_options.go
Normal file
69
server/mock/datastore_options.go
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
// Automatically generated by mockimpl. DO NOT EDIT!
|
||||
|
||||
package mock
|
||||
|
||||
import "github.com/kolide/kolide/server/kolide"
|
||||
|
||||
var _ kolide.OptionStore = (*OptionStore)(nil)
|
||||
|
||||
type SaveOptionsFunc func(opts []kolide.Option) error
|
||||
|
||||
type ListOptionsFunc func() ([]kolide.Option, error)
|
||||
|
||||
type OptionFunc func(id uint) (*kolide.Option, error)
|
||||
|
||||
type OptionByNameFunc func(name string) (*kolide.Option, error)
|
||||
|
||||
type GetOsqueryConfigOptionsFunc func() (map[string]interface{}, error)
|
||||
|
||||
type ResetOptionsFunc func() ([]kolide.Option, error)
|
||||
|
||||
type OptionStore struct {
|
||||
SaveOptionsFunc SaveOptionsFunc
|
||||
SaveOptionsFuncInvoked bool
|
||||
|
||||
ListOptionsFunc ListOptionsFunc
|
||||
ListOptionsFuncInvoked bool
|
||||
|
||||
OptionFunc OptionFunc
|
||||
OptionFuncInvoked bool
|
||||
|
||||
OptionByNameFunc OptionByNameFunc
|
||||
OptionByNameFuncInvoked bool
|
||||
|
||||
GetOsqueryConfigOptionsFunc GetOsqueryConfigOptionsFunc
|
||||
GetOsqueryConfigOptionsFuncInvoked bool
|
||||
|
||||
ResetOptionsFunc ResetOptionsFunc
|
||||
ResetOptionsFuncInvoked bool
|
||||
}
|
||||
|
||||
func (s *OptionStore) SaveOptions(opts []kolide.Option) error {
|
||||
s.SaveOptionsFuncInvoked = true
|
||||
return s.SaveOptionsFunc(opts)
|
||||
}
|
||||
|
||||
func (s *OptionStore) ListOptions() ([]kolide.Option, error) {
|
||||
s.ListOptionsFuncInvoked = true
|
||||
return s.ListOptionsFunc()
|
||||
}
|
||||
|
||||
func (s *OptionStore) Option(id uint) (*kolide.Option, error) {
|
||||
s.OptionFuncInvoked = true
|
||||
return s.OptionFunc(id)
|
||||
}
|
||||
|
||||
func (s *OptionStore) OptionByName(name string) (*kolide.Option, error) {
|
||||
s.OptionByNameFuncInvoked = true
|
||||
return s.OptionByNameFunc(name)
|
||||
}
|
||||
|
||||
func (s *OptionStore) GetOsqueryConfigOptions() (map[string]interface{}, error) {
|
||||
s.GetOsqueryConfigOptionsFuncInvoked = true
|
||||
return s.GetOsqueryConfigOptionsFunc()
|
||||
}
|
||||
|
||||
func (s *OptionStore) ResetOptions() ([]kolide.Option, error) {
|
||||
s.ResetOptionsFuncInvoked = true
|
||||
return s.ResetOptionsFunc()
|
||||
}
|
||||
139
server/mock/datastore_packs.go
Normal file
139
server/mock/datastore_packs.go
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
// Automatically generated by mockimpl. DO NOT EDIT!
|
||||
|
||||
package mock
|
||||
|
||||
import "github.com/kolide/kolide/server/kolide"
|
||||
|
||||
var _ kolide.PackStore = (*PackStore)(nil)
|
||||
|
||||
type NewPackFunc func(pack *kolide.Pack) (*kolide.Pack, error)
|
||||
|
||||
type SavePackFunc func(pack *kolide.Pack) error
|
||||
|
||||
type DeletePackFunc func(pid uint) error
|
||||
|
||||
type PackFunc func(pid uint) (*kolide.Pack, error)
|
||||
|
||||
type ListPacksFunc func(opt kolide.ListOptions) ([]*kolide.Pack, error)
|
||||
|
||||
type PackByNameFunc func(name string) (*kolide.Pack, bool, error)
|
||||
|
||||
type AddLabelToPackFunc func(lid uint, pid uint) error
|
||||
|
||||
type RemoveLabelFromPackFunc func(lid uint, pid uint) error
|
||||
|
||||
type ListLabelsForPackFunc func(pid uint) ([]*kolide.Label, error)
|
||||
|
||||
type AddHostToPackFunc func(hid uint, pid uint) error
|
||||
|
||||
type RemoveHostFromPackFunc func(hid uint, pid uint) error
|
||||
|
||||
type ListHostsInPackFunc func(pid uint, opt kolide.ListOptions) ([]uint, error)
|
||||
|
||||
type ListExplicitHostsInPackFunc func(pid uint, opt kolide.ListOptions) ([]uint, error)
|
||||
|
||||
type PackStore struct {
|
||||
NewPackFunc NewPackFunc
|
||||
NewPackFuncInvoked bool
|
||||
|
||||
SavePackFunc SavePackFunc
|
||||
SavePackFuncInvoked bool
|
||||
|
||||
DeletePackFunc DeletePackFunc
|
||||
DeletePackFuncInvoked bool
|
||||
|
||||
PackFunc PackFunc
|
||||
PackFuncInvoked bool
|
||||
|
||||
ListPacksFunc ListPacksFunc
|
||||
ListPacksFuncInvoked bool
|
||||
|
||||
PackByNameFunc PackByNameFunc
|
||||
PackByNameFuncInvoked bool
|
||||
|
||||
AddLabelToPackFunc AddLabelToPackFunc
|
||||
AddLabelToPackFuncInvoked bool
|
||||
|
||||
RemoveLabelFromPackFunc RemoveLabelFromPackFunc
|
||||
RemoveLabelFromPackFuncInvoked bool
|
||||
|
||||
ListLabelsForPackFunc ListLabelsForPackFunc
|
||||
ListLabelsForPackFuncInvoked bool
|
||||
|
||||
AddHostToPackFunc AddHostToPackFunc
|
||||
AddHostToPackFuncInvoked bool
|
||||
|
||||
RemoveHostFromPackFunc RemoveHostFromPackFunc
|
||||
RemoveHostFromPackFuncInvoked bool
|
||||
|
||||
ListHostsInPackFunc ListHostsInPackFunc
|
||||
ListHostsInPackFuncInvoked bool
|
||||
|
||||
ListExplicitHostsInPackFunc ListExplicitHostsInPackFunc
|
||||
ListExplicitHostsInPackFuncInvoked bool
|
||||
}
|
||||
|
||||
func (s *PackStore) NewPack(pack *kolide.Pack) (*kolide.Pack, error) {
|
||||
s.NewPackFuncInvoked = true
|
||||
return s.NewPackFunc(pack)
|
||||
}
|
||||
|
||||
func (s *PackStore) SavePack(pack *kolide.Pack) error {
|
||||
s.SavePackFuncInvoked = true
|
||||
return s.SavePackFunc(pack)
|
||||
}
|
||||
|
||||
func (s *PackStore) DeletePack(pid uint) error {
|
||||
s.DeletePackFuncInvoked = true
|
||||
return s.DeletePackFunc(pid)
|
||||
}
|
||||
|
||||
func (s *PackStore) Pack(pid uint) (*kolide.Pack, error) {
|
||||
s.PackFuncInvoked = true
|
||||
return s.PackFunc(pid)
|
||||
}
|
||||
|
||||
func (s *PackStore) ListPacks(opt kolide.ListOptions) ([]*kolide.Pack, error) {
|
||||
s.ListPacksFuncInvoked = true
|
||||
return s.ListPacksFunc(opt)
|
||||
}
|
||||
|
||||
func (s *PackStore) PackByName(name string) (*kolide.Pack, bool, error) {
|
||||
s.PackByNameFuncInvoked = true
|
||||
return s.PackByNameFunc(name)
|
||||
}
|
||||
|
||||
func (s *PackStore) AddLabelToPack(lid uint, pid uint) error {
|
||||
s.AddLabelToPackFuncInvoked = true
|
||||
return s.AddLabelToPackFunc(lid, pid)
|
||||
}
|
||||
|
||||
func (s *PackStore) RemoveLabelFromPack(lid uint, pid uint) error {
|
||||
s.RemoveLabelFromPackFuncInvoked = true
|
||||
return s.RemoveLabelFromPackFunc(lid, pid)
|
||||
}
|
||||
|
||||
func (s *PackStore) ListLabelsForPack(pid uint) ([]*kolide.Label, error) {
|
||||
s.ListLabelsForPackFuncInvoked = true
|
||||
return s.ListLabelsForPackFunc(pid)
|
||||
}
|
||||
|
||||
func (s *PackStore) AddHostToPack(hid uint, pid uint) error {
|
||||
s.AddHostToPackFuncInvoked = true
|
||||
return s.AddHostToPackFunc(hid, pid)
|
||||
}
|
||||
|
||||
func (s *PackStore) RemoveHostFromPack(hid uint, pid uint) error {
|
||||
s.RemoveHostFromPackFuncInvoked = true
|
||||
return s.RemoveHostFromPackFunc(hid, pid)
|
||||
}
|
||||
|
||||
func (s *PackStore) ListHostsInPack(pid uint, opt kolide.ListOptions) ([]uint, error) {
|
||||
s.ListHostsInPackFuncInvoked = true
|
||||
return s.ListHostsInPackFunc(pid, opt)
|
||||
}
|
||||
|
||||
func (s *PackStore) ListExplicitHostsInPack(pid uint, opt kolide.ListOptions) ([]uint, error) {
|
||||
s.ListExplicitHostsInPackFuncInvoked = true
|
||||
return s.ListExplicitHostsInPackFunc(pid, opt)
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/kolide/kolide/server/kolide"
|
||||
"github.com/kolide/kolide/server/pubsub"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cast"
|
||||
)
|
||||
|
||||
type osqueryError struct {
|
||||
|
|
@ -148,6 +149,32 @@ func (svc service) GetClientConfig(ctx context.Context) (*kolide.OsqueryConfig,
|
|||
}
|
||||
}
|
||||
|
||||
// Save interval values if they have been updated. Note
|
||||
// config_tls_refresh can only be set in the osquery flags so is
|
||||
// ignored here.
|
||||
saveHost := false
|
||||
|
||||
distributedIntervalVal, ok := config.Options["distributed_interval"]
|
||||
distributedInterval, err := cast.ToUintE(distributedIntervalVal)
|
||||
if ok && err == nil && host.DistributedInterval != distributedInterval {
|
||||
host.DistributedInterval = distributedInterval
|
||||
saveHost = true
|
||||
}
|
||||
|
||||
loggerTLSPeriodVal, ok := config.Options["logger_tls_period"]
|
||||
loggerTLSPeriod, err := cast.ToUintE(loggerTLSPeriodVal)
|
||||
if ok && err == nil && host.LoggerTLSPeriod != loggerTLSPeriod {
|
||||
host.LoggerTLSPeriod = loggerTLSPeriod
|
||||
saveHost = true
|
||||
}
|
||||
|
||||
if saveHost {
|
||||
err := svc.ds.SaveHost(&host)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return config, nil
|
||||
}
|
||||
|
||||
|
|
@ -209,109 +236,6 @@ var detailQueries = map[string]struct {
|
|||
Query string
|
||||
IngestFunc func(logger log.Logger, host *kolide.Host, rows []map[string]string) error
|
||||
}{
|
||||
"osquery_info": {
|
||||
Query: "select * from osquery_info limit 1",
|
||||
IngestFunc: func(logger log.Logger, host *kolide.Host, rows []map[string]string) error {
|
||||
if len(rows) != 1 {
|
||||
logger.Log("component", "service", "method", "IngestFunc", "err",
|
||||
fmt.Sprintf("detail_query_osquery_info expected single result got %d", len(rows)))
|
||||
return nil
|
||||
}
|
||||
|
||||
host.OsqueryVersion = rows[0]["version"]
|
||||
|
||||
return nil
|
||||
},
|
||||
},
|
||||
"system_info": {
|
||||
Query: "select * from system_info limit 1",
|
||||
IngestFunc: func(logger log.Logger, host *kolide.Host, rows []map[string]string) error {
|
||||
if len(rows) != 1 {
|
||||
logger.Log("component", "service", "method", "IngestFunc", "err",
|
||||
fmt.Sprintf("detail_query_system_info expected single result got %d", len(rows)))
|
||||
return nil
|
||||
}
|
||||
|
||||
var err error
|
||||
host.PhysicalMemory, err = strconv.Atoi(rows[0]["physical_memory"])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
host.HostName = rows[0]["hostname"]
|
||||
host.UUID = rows[0]["uuid"]
|
||||
host.CPUType = rows[0]["cpu_type"]
|
||||
host.CPUSubtype = rows[0]["cpu_subtype"]
|
||||
host.CPUBrand = rows[0]["cpu_brand"]
|
||||
host.CPUPhysicalCores, err = strconv.Atoi(rows[0]["cpu_physical_cores"])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
host.CPULogicalCores, err = strconv.Atoi(rows[0]["cpu_logical_cores"])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
host.HardwareVendor = rows[0]["hardware_vendor"]
|
||||
host.HardwareModel = rows[0]["hardware_model"]
|
||||
host.HardwareVersion = rows[0]["hardware_version"]
|
||||
host.HardwareSerial = rows[0]["hardware_serial"]
|
||||
host.ComputerName = rows[0]["computer_name"]
|
||||
return nil
|
||||
},
|
||||
},
|
||||
"os_version": {
|
||||
Query: "select * from os_version limit 1",
|
||||
IngestFunc: func(logger log.Logger, host *kolide.Host, rows []map[string]string) error {
|
||||
if len(rows) != 1 {
|
||||
logger.Log("component", "service", "method", "IngestFunc", "err",
|
||||
fmt.Sprintf("detail_query_os_version expected single result got %d", len(rows)))
|
||||
return nil
|
||||
}
|
||||
|
||||
host.OSVersion = fmt.Sprintf(
|
||||
"%s %s.%s.%s",
|
||||
rows[0]["name"],
|
||||
rows[0]["major"],
|
||||
rows[0]["minor"],
|
||||
rows[0]["patch"],
|
||||
)
|
||||
host.OSVersion = strings.Trim(host.OSVersion, ".")
|
||||
|
||||
if build, ok := rows[0]["build"]; ok {
|
||||
host.Build = build
|
||||
}
|
||||
|
||||
host.Platform = rows[0]["platform"]
|
||||
host.PlatformLike = rows[0]["platform_like"]
|
||||
host.CodeName = rows[0]["code_name"]
|
||||
|
||||
// On centos6 there is an osquery bug that leaves
|
||||
// platform empty. Here we workaround.
|
||||
if host.Platform == "" &&
|
||||
strings.Contains(strings.ToLower(rows[0]["name"]), "centos") {
|
||||
host.Platform = "centos"
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
},
|
||||
"uptime": {
|
||||
Query: "select * from uptime limit 1",
|
||||
IngestFunc: func(logger log.Logger, host *kolide.Host, rows []map[string]string) error {
|
||||
if len(rows) != 1 {
|
||||
logger.Log("component", "service", "method", "IngestFunc", "err",
|
||||
fmt.Sprintf("detail_query_uptime expected single result got %d", len(rows)))
|
||||
return nil
|
||||
}
|
||||
|
||||
uptimeSeconds, err := strconv.Atoi(rows[0]["total_seconds"])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
host.Uptime = time.Duration(uptimeSeconds) * time.Second
|
||||
|
||||
return nil
|
||||
},
|
||||
},
|
||||
"network_interface": {
|
||||
Query: `select * from interface_details id join interface_addresses ia
|
||||
on ia.interface = id.interface where broadcast != ""
|
||||
|
|
@ -371,6 +295,144 @@ var detailQueries = map[string]struct {
|
|||
|
||||
host.NetworkInterfaces = networkInterfaces
|
||||
|
||||
return nil
|
||||
},
|
||||
},
|
||||
"os_version": {
|
||||
Query: "select * from os_version limit 1",
|
||||
IngestFunc: func(logger log.Logger, host *kolide.Host, rows []map[string]string) error {
|
||||
if len(rows) != 1 {
|
||||
logger.Log("component", "service", "method", "IngestFunc", "err",
|
||||
fmt.Sprintf("detail_query_os_version expected single result got %d", len(rows)))
|
||||
return nil
|
||||
}
|
||||
|
||||
host.OSVersion = fmt.Sprintf(
|
||||
"%s %s.%s.%s",
|
||||
rows[0]["name"],
|
||||
rows[0]["major"],
|
||||
rows[0]["minor"],
|
||||
rows[0]["patch"],
|
||||
)
|
||||
host.OSVersion = strings.Trim(host.OSVersion, ".")
|
||||
|
||||
if build, ok := rows[0]["build"]; ok {
|
||||
host.Build = build
|
||||
}
|
||||
|
||||
host.Platform = rows[0]["platform"]
|
||||
host.PlatformLike = rows[0]["platform_like"]
|
||||
host.CodeName = rows[0]["code_name"]
|
||||
|
||||
// On centos6 there is an osquery bug that leaves
|
||||
// platform empty. Here we workaround.
|
||||
if host.Platform == "" &&
|
||||
strings.Contains(strings.ToLower(rows[0]["name"]), "centos") {
|
||||
host.Platform = "centos"
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
},
|
||||
"osquery_flags": {
|
||||
// Collect the interval info (used for online status
|
||||
// calculation) from the osquery flags. We typically control
|
||||
// distributed_interval (but it's not required), and typically
|
||||
// do not control config_tls_refresh.
|
||||
Query: `select name, value from osquery_flags where name in ("distributed_interval", "config_tls_refresh", "logger_tls_period")`,
|
||||
IngestFunc: func(logger log.Logger, host *kolide.Host, rows []map[string]string) error {
|
||||
for _, row := range rows {
|
||||
switch row["name"] {
|
||||
|
||||
case "distributed_interval":
|
||||
interval, err := strconv.Atoi(row["value"])
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "parsing distributed_interval")
|
||||
}
|
||||
host.DistributedInterval = uint(interval)
|
||||
|
||||
case "config_tls_refresh":
|
||||
interval, err := strconv.Atoi(row["value"])
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "parsing config_tls_refresh")
|
||||
}
|
||||
host.ConfigTLSRefresh = uint(interval)
|
||||
|
||||
case "logger_tls_period":
|
||||
interval, err := strconv.Atoi(row["value"])
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "parsing logger_tls_period")
|
||||
}
|
||||
host.LoggerTLSPeriod = uint(interval)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
},
|
||||
},
|
||||
"osquery_info": {
|
||||
Query: "select * from osquery_info limit 1",
|
||||
IngestFunc: func(logger log.Logger, host *kolide.Host, rows []map[string]string) error {
|
||||
if len(rows) != 1 {
|
||||
logger.Log("component", "service", "method", "IngestFunc", "err",
|
||||
fmt.Sprintf("detail_query_osquery_info expected single result got %d", len(rows)))
|
||||
return nil
|
||||
}
|
||||
|
||||
host.OsqueryVersion = rows[0]["version"]
|
||||
|
||||
return nil
|
||||
},
|
||||
},
|
||||
"system_info": {
|
||||
Query: "select * from system_info limit 1",
|
||||
IngestFunc: func(logger log.Logger, host *kolide.Host, rows []map[string]string) error {
|
||||
if len(rows) != 1 {
|
||||
logger.Log("component", "service", "method", "IngestFunc", "err",
|
||||
fmt.Sprintf("detail_query_system_info expected single result got %d", len(rows)))
|
||||
return nil
|
||||
}
|
||||
|
||||
var err error
|
||||
host.PhysicalMemory, err = strconv.Atoi(rows[0]["physical_memory"])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
host.HostName = rows[0]["hostname"]
|
||||
host.UUID = rows[0]["uuid"]
|
||||
host.CPUType = rows[0]["cpu_type"]
|
||||
host.CPUSubtype = rows[0]["cpu_subtype"]
|
||||
host.CPUBrand = rows[0]["cpu_brand"]
|
||||
host.CPUPhysicalCores, err = strconv.Atoi(rows[0]["cpu_physical_cores"])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
host.CPULogicalCores, err = strconv.Atoi(rows[0]["cpu_logical_cores"])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
host.HardwareVendor = rows[0]["hardware_vendor"]
|
||||
host.HardwareModel = rows[0]["hardware_model"]
|
||||
host.HardwareVersion = rows[0]["hardware_version"]
|
||||
host.HardwareSerial = rows[0]["hardware_serial"]
|
||||
host.ComputerName = rows[0]["computer_name"]
|
||||
return nil
|
||||
},
|
||||
},
|
||||
"uptime": {
|
||||
Query: "select * from uptime limit 1",
|
||||
IngestFunc: func(logger log.Logger, host *kolide.Host, rows []map[string]string) error {
|
||||
if len(rows) != 1 {
|
||||
logger.Log("component", "service", "method", "IngestFunc", "err",
|
||||
fmt.Sprintf("detail_query_uptime expected single result got %d", len(rows)))
|
||||
return nil
|
||||
}
|
||||
|
||||
uptimeSeconds, err := strconv.Atoi(rows[0]["total_seconds"])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
host.Uptime = time.Duration(uptimeSeconds) * time.Second
|
||||
|
||||
return nil
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import (
|
|||
"github.com/kolide/kolide/server/contexts/viewer"
|
||||
"github.com/kolide/kolide/server/datastore/inmem"
|
||||
"github.com/kolide/kolide/server/kolide"
|
||||
"github.com/kolide/kolide/server/mock"
|
||||
"github.com/kolide/kolide/server/pubsub"
|
||||
"github.com/kolide/kolide/server/test"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
|
@ -523,6 +524,20 @@ func TestDetailQueries(t *testing.T) {
|
|||
"seconds": "13",
|
||||
"total_seconds": "1730893"
|
||||
}
|
||||
],
|
||||
"kolide_detail_query_osquery_flags": [
|
||||
{
|
||||
"name":"config_tls_refresh",
|
||||
"value":"10"
|
||||
},
|
||||
{
|
||||
"name":"distributed_interval",
|
||||
"value":"5"
|
||||
},
|
||||
{
|
||||
"name":"logger_tls_period",
|
||||
"value":"60"
|
||||
}
|
||||
]
|
||||
}
|
||||
`
|
||||
|
|
@ -553,6 +568,11 @@ func TestDetailQueries(t *testing.T) {
|
|||
// uptime
|
||||
assert.Equal(t, 1730893*time.Second, host.Uptime)
|
||||
|
||||
// osquery_flags
|
||||
assert.Equal(t, uint(10), host.ConfigTLSRefresh)
|
||||
assert.Equal(t, uint(5), host.DistributedInterval)
|
||||
assert.Equal(t, uint(60), host.LoggerTLSPeriod)
|
||||
|
||||
mockClock.AddTime(1 * time.Minute)
|
||||
|
||||
// Now no detail queries should be required
|
||||
|
|
@ -768,6 +788,138 @@ func TestOrphanedQueryCampaign(t *testing.T) {
|
|||
assert.Equal(t, kolide.QueryComplete, campaign.Status)
|
||||
}
|
||||
|
||||
func TestUpdateHostIntervals(t *testing.T) {
|
||||
ds := new(mock.Store)
|
||||
|
||||
svc, err := newTestService(ds, nil)
|
||||
require.Nil(t, err)
|
||||
|
||||
ds.ListDecoratorsFunc = func() ([]*kolide.Decorator, error) {
|
||||
return []*kolide.Decorator{}, nil
|
||||
}
|
||||
ds.ListPacksFunc = func(opt kolide.ListOptions) ([]*kolide.Pack, error) {
|
||||
return []*kolide.Pack{}, nil
|
||||
}
|
||||
ds.ListLabelsForHostFunc = func(hid uint) ([]kolide.Label, error) {
|
||||
return []kolide.Label{}, nil
|
||||
}
|
||||
|
||||
var testCases = []struct {
|
||||
initHost kolide.Host
|
||||
finalHost kolide.Host
|
||||
configOptions map[string]interface{}
|
||||
saveHostCalled bool
|
||||
}{
|
||||
// Both updated
|
||||
{
|
||||
kolide.Host{
|
||||
ConfigTLSRefresh: 60,
|
||||
},
|
||||
kolide.Host{
|
||||
DistributedInterval: 11,
|
||||
LoggerTLSPeriod: 33,
|
||||
ConfigTLSRefresh: 60,
|
||||
},
|
||||
map[string]interface{}{
|
||||
"distributed_interval": 11,
|
||||
"logger_tls_period": 33,
|
||||
"logger_plugin": "tls",
|
||||
},
|
||||
true,
|
||||
},
|
||||
// Only logger_tls_period updated
|
||||
{
|
||||
kolide.Host{
|
||||
DistributedInterval: 11,
|
||||
ConfigTLSRefresh: 60,
|
||||
},
|
||||
kolide.Host{
|
||||
DistributedInterval: 11,
|
||||
LoggerTLSPeriod: 33,
|
||||
ConfigTLSRefresh: 60,
|
||||
},
|
||||
map[string]interface{}{
|
||||
"distributed_interval": 11,
|
||||
"logger_tls_period": 33,
|
||||
},
|
||||
true,
|
||||
},
|
||||
// Only distributed_interval updated
|
||||
{
|
||||
kolide.Host{
|
||||
ConfigTLSRefresh: 60,
|
||||
LoggerTLSPeriod: 33,
|
||||
},
|
||||
kolide.Host{
|
||||
DistributedInterval: 11,
|
||||
LoggerTLSPeriod: 33,
|
||||
ConfigTLSRefresh: 60,
|
||||
},
|
||||
map[string]interface{}{
|
||||
"distributed_interval": 11,
|
||||
"logger_tls_period": 33,
|
||||
},
|
||||
true,
|
||||
},
|
||||
// Kolide not managing distributed_interval
|
||||
{
|
||||
kolide.Host{
|
||||
ConfigTLSRefresh: 60,
|
||||
DistributedInterval: 11,
|
||||
},
|
||||
kolide.Host{
|
||||
DistributedInterval: 11,
|
||||
LoggerTLSPeriod: 33,
|
||||
ConfigTLSRefresh: 60,
|
||||
},
|
||||
map[string]interface{}{
|
||||
"logger_tls_period": 33,
|
||||
},
|
||||
true,
|
||||
},
|
||||
// SaveHost should not be called with no changes
|
||||
{
|
||||
kolide.Host{
|
||||
DistributedInterval: 11,
|
||||
LoggerTLSPeriod: 33,
|
||||
ConfigTLSRefresh: 60,
|
||||
},
|
||||
kolide.Host{
|
||||
DistributedInterval: 11,
|
||||
LoggerTLSPeriod: 33,
|
||||
ConfigTLSRefresh: 60,
|
||||
},
|
||||
map[string]interface{}{
|
||||
"distributed_interval": 11,
|
||||
"logger_tls_period": 33,
|
||||
},
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range testCases[4:] {
|
||||
t.Run("", func(t *testing.T) {
|
||||
ctx := hostctx.NewContext(context.Background(), tt.initHost)
|
||||
|
||||
ds.GetOsqueryConfigOptionsFunc = func() (map[string]interface{}, error) {
|
||||
return tt.configOptions, nil
|
||||
}
|
||||
|
||||
saveHostCalled := false
|
||||
ds.SaveHostFunc = func(host *kolide.Host) error {
|
||||
saveHostCalled = true
|
||||
assert.Equal(t, tt.finalHost, *host)
|
||||
return nil
|
||||
}
|
||||
|
||||
_, err = svc.GetClientConfig(ctx)
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, tt.saveHostCalled, saveHostCalled)
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func setupOsqueryTests(t *testing.T) (kolide.Datastore, kolide.Service, *clock.MockClock) {
|
||||
ds, err := inmem.New(config.TestConfig())
|
||||
require.Nil(t, err)
|
||||
|
|
|
|||
Loading…
Reference in a new issue