Moving query attributes from the query object to the pack-query relationship (#559)

* Moving query attributes from the query object to the pack-query relationship

* some additional tests

* http request parsing test

* QueryOptions in new test_util code

* initial scaffolding of new request structures

* service and datastore

* test outline

* l2 merge conflict scrub

* service tests for scheduled query service

* service and datastore tests

* most endpoints and transports

* order of values are not deterministic with inmem

* transport tests

* rename PackQuery to ScheduledQuery

* removing existing implementation of adding queries to packs

* accounting for the new argument to NewQuery

* fix alignment in sql query

* removing underscore

* add removed to the datastore

* removed differential from the schema
This commit is contained in:
Mike Arpaia 2016-12-13 14:22:05 -08:00 committed by GitHub
parent 7f7bcd177d
commit f109b14f9d
37 changed files with 1084 additions and 718 deletions

View file

@ -6,6 +6,7 @@ import (
"github.com/WatchBeam/clock"
"github.com/kolide/kolide-ose/server/kolide"
"github.com/kolide/kolide-ose/server/test"
"github.com/patrickmn/sortutil"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@ -25,13 +26,13 @@ func checkTargets(t *testing.T, ds kolide.Datastore, campaignID uint, expectedHo
}
func testDistributedQueryCampaign(t *testing.T, ds kolide.Datastore) {
user := newUser(t, ds, "Zach", "zwass", "zwass@kolide.co", true)
user := test.NewUser(t, ds, "Zach", "zwass", "zwass@kolide.co", true)
mockClock := clock.NewMockClock()
query := newQuery(t, ds, "test", "select * from time", user.ID, false)
query := test.NewQuery(t, ds, "test", "select * from time", user.ID, false)
campaign := newCampaign(t, ds, query.ID, kolide.QueryRunning, mockClock.Now())
campaign := test.NewCampaign(t, ds, query.ID, kolide.QueryRunning, mockClock.Now())
{
retrieved, err := ds.DistributedQueryCampaign(campaign.ID)
@ -40,44 +41,44 @@ func testDistributedQueryCampaign(t *testing.T, ds kolide.Datastore) {
assert.Equal(t, campaign.Status, retrieved.Status)
}
h1 := newHost(t, ds, "foo.local", "192.168.1.10", "1", "1", mockClock.Now())
h2 := newHost(t, ds, "bar.local", "192.168.1.11", "2", "2", mockClock.Now().Add(-1*time.Hour))
h3 := newHost(t, ds, "baz.local", "192.168.1.12", "3", "3", mockClock.Now().Add(-13*time.Minute))
h1 := test.NewHost(t, ds, "foo.local", "192.168.1.10", "1", "1", mockClock.Now())
h2 := test.NewHost(t, ds, "bar.local", "192.168.1.11", "2", "2", mockClock.Now().Add(-1*time.Hour))
h3 := test.NewHost(t, ds, "baz.local", "192.168.1.12", "3", "3", mockClock.Now().Add(-13*time.Minute))
l1 := newLabel(t, ds, "label foo", "query foo")
l2 := newLabel(t, ds, "label bar", "query foo")
l1 := test.NewLabel(t, ds, "label foo", "query foo")
l2 := test.NewLabel(t, ds, "label bar", "query foo")
checkTargets(t, ds, campaign.ID, []uint{}, []uint{})
addHostToCampaign(t, ds, campaign.ID, h1.ID)
test.AddHostToCampaign(t, ds, campaign.ID, h1.ID)
checkTargets(t, ds, campaign.ID, []uint{h1.ID}, []uint{})
addLabelToCampaign(t, ds, campaign.ID, l1.ID)
test.AddLabelToCampaign(t, ds, campaign.ID, l1.ID)
checkTargets(t, ds, campaign.ID, []uint{h1.ID}, []uint{l1.ID})
addLabelToCampaign(t, ds, campaign.ID, l2.ID)
test.AddLabelToCampaign(t, ds, campaign.ID, l2.ID)
checkTargets(t, ds, campaign.ID, []uint{h1.ID}, []uint{l1.ID, l2.ID})
addHostToCampaign(t, ds, campaign.ID, h2.ID)
addHostToCampaign(t, ds, campaign.ID, h3.ID)
test.AddHostToCampaign(t, ds, campaign.ID, h2.ID)
test.AddHostToCampaign(t, ds, campaign.ID, h3.ID)
checkTargets(t, ds, campaign.ID, []uint{h1.ID, h2.ID, h3.ID}, []uint{l1.ID, l2.ID})
}
func testCleanupDistributedQueryCampaigns(t *testing.T, ds kolide.Datastore) {
user := newUser(t, ds, "Zach", "zwass", "zwass@kolide.co", true)
user := test.NewUser(t, ds, "Zach", "zwass", "zwass@kolide.co", true)
mockClock := clock.NewMockClock()
query := newQuery(t, ds, "test", "select * from time", user.ID, false)
query := test.NewQuery(t, ds, "test", "select * from time", user.ID, false)
c1 := newCampaign(t, ds, query.ID, kolide.QueryWaiting, mockClock.Now())
c2 := newCampaign(t, ds, query.ID, kolide.QueryRunning, mockClock.Now())
c1 := test.NewCampaign(t, ds, query.ID, kolide.QueryWaiting, mockClock.Now())
c2 := test.NewCampaign(t, ds, query.ID, kolide.QueryRunning, mockClock.Now())
h1 := newHost(t, ds, "1", "", "1", "1", mockClock.Now())
h2 := newHost(t, ds, "2", "", "2", "2", mockClock.Now())
h3 := newHost(t, ds, "3", "", "3", "3", mockClock.Now())
h1 := test.NewHost(t, ds, "1", "", "1", "1", mockClock.Now())
h2 := test.NewHost(t, ds, "2", "", "2", "2", mockClock.Now())
h3 := test.NewHost(t, ds, "3", "", "3", "3", mockClock.Now())
// Cleanup and verify that nothing changed (because time has not
// advanced)
@ -100,11 +101,11 @@ func testCleanupDistributedQueryCampaigns(t *testing.T, ds kolide.Datastore) {
}
// Add some executions
newExecution(t, ds, c1.ID, h1.ID)
newExecution(t, ds, c1.ID, h2.ID)
newExecution(t, ds, c2.ID, h1.ID)
newExecution(t, ds, c2.ID, h2.ID)
newExecution(t, ds, c2.ID, h3.ID)
test.NewExecution(t, ds, c1.ID, h1.ID)
test.NewExecution(t, ds, c1.ID, h2.ID)
test.NewExecution(t, ds, c2.ID, h1.ID)
test.NewExecution(t, ds, c2.ID, h2.ID)
test.NewExecution(t, ds, c2.ID, h3.ID)
mockClock.AddTime(1*time.Minute + 1*time.Second)

View file

@ -7,6 +7,7 @@ import (
"time"
"github.com/kolide/kolide-ose/server/kolide"
"github.com/kolide/kolide-ose/server/test"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@ -327,8 +328,6 @@ func testSearchHosts(t *testing.T, ds kolide.Datastore) {
hits, err = ds.SearchHosts("99.100.101")
require.Nil(t, err)
assert.Equal(t, 2, len(hits))
assert.Equal(t, 2, len(hits[0].NetworkInterfaces))
assert.Equal(t, "en0", hits[0].NetworkInterfaces[0].Interface)
hits, err = ds.SearchHosts("99.100.101", h3.ID)
require.Nil(t, err)
@ -354,7 +353,7 @@ func testSearchHostsLimit(t *testing.T, ds kolide.Datastore) {
}
func testDistributedQueriesForHost(t *testing.T, ds kolide.Datastore) {
user := newUser(t, ds, "Zach", "zwass", "zwass@kolide.co", true)
user := test.NewUser(t, ds, "Zach", "zwass", "zwass@kolide.co", true)
h1, err := ds.NewHost(&kolide.Host{
OsqueryHostID: "1",

View file

@ -6,6 +6,7 @@ import (
"github.com/WatchBeam/clock"
"github.com/kolide/kolide-ose/server/kolide"
"github.com/kolide/kolide-ose/server/test"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@ -29,56 +30,8 @@ func testDeletePack(t *testing.T, ds kolide.Datastore) {
assert.NotNil(t, err)
}
func testAddAndRemoveQueryFromPack(t *testing.T, ds kolide.Datastore) {
user := newUser(t, ds, "Zach", "zwass", "zwass@kolide.co", false)
pack := &kolide.Pack{
Name: "foo",
}
_, err := ds.NewPack(pack)
assert.Nil(t, err)
assert.NotEqual(t, uint(0), pack.ID)
q1 := &kolide.Query{
Name: "bar",
Query: "bar",
AuthorID: user.ID,
}
q1, err = ds.NewQuery(q1)
require.Nil(t, err)
assert.NotEqual(t, uint(0), q1.ID)
err = ds.AddQueryToPack(q1.ID, pack.ID)
require.Nil(t, err)
q2 := &kolide.Query{
Name: "baz",
Query: "baz",
AuthorID: user.ID,
}
q2, err = ds.NewQuery(q2)
require.Nil(t, err)
assert.NotEqual(t, uint(0), q2.ID)
assert.NotEqual(t, q1.ID, q2.ID)
err = ds.AddQueryToPack(q2.ID, pack.ID)
require.Nil(t, err)
queries, err := ds.ListQueriesInPack(pack)
require.Nil(t, err)
assert.Len(t, queries, 2)
err = ds.RemoveQueryFromPack(q1, pack)
require.Nil(t, err)
queries, err = ds.ListQueriesInPack(pack)
require.Nil(t, err)
assert.Len(t, queries, 1)
}
func testGetHostsInPack(t *testing.T, ds kolide.Datastore) {
user := newUser(t, ds, "Zach", "zwass", "zwass@kolide.co", true)
user := test.NewUser(t, ds, "Zach", "zwass", "zwass@kolide.co", true)
mockClock := clock.NewMockClock()
@ -101,11 +54,8 @@ func testGetHostsInPack(t *testing.T, ds kolide.Datastore) {
})
require.Nil(t, err)
err = ds.AddQueryToPack(q1.ID, p1.ID)
require.Nil(t, err)
err = ds.AddQueryToPack(q2.ID, p1.ID)
require.Nil(t, err)
test.NewScheduledQuery(t, ds, p1.ID, q1.ID, 60, false, false)
test.NewScheduledQuery(t, ds, p1.ID, q2.ID, 60, false, false)
l1, err := ds.NewLabel(&kolide.Label{
Name: "foo",

View file

@ -5,22 +5,23 @@ import (
"testing"
"github.com/kolide/kolide-ose/server/kolide"
"github.com/kolide/kolide-ose/server/test"
"github.com/patrickmn/sortutil"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func testDeleteQuery(t *testing.T, ds kolide.Datastore) {
user := newUser(t, ds, "Zach", "zwass", "zwass@kolide.co", true)
user := test.NewUser(t, ds, "Zach", "zwass", "zwass@kolide.co", true)
query := &kolide.Query{
Name: "foo",
Query: "bar",
Interval: 123,
AuthorID: user.ID,
}
query, err := ds.NewQuery(query)
require.Nil(t, err)
require.NotNil(t, query)
assert.NotEqual(t, query.ID, 0)
err = ds.DeleteQuery(query)
@ -32,12 +33,12 @@ func testDeleteQuery(t *testing.T, ds kolide.Datastore) {
}
func testDeleteQueries(t *testing.T, ds kolide.Datastore) {
user := newUser(t, ds, "Zach", "zwass", "zwass@kolide.co", true)
user := test.NewUser(t, ds, "Zach", "zwass", "zwass@kolide.co", true)
q1 := newQuery(t, ds, "q1", "select * from time", user.ID, true)
q2 := newQuery(t, ds, "q2", "select * from processes", user.ID, true)
q3 := newQuery(t, ds, "q3", "select 1", user.ID, true)
q4 := newQuery(t, ds, "q4", "select * from osquery_info", user.ID, true)
q1 := test.NewQuery(t, ds, "q1", "select * from time", user.ID, true)
q2 := test.NewQuery(t, ds, "q2", "select * from processes", user.ID, true)
q3 := test.NewQuery(t, ds, "q3", "select 1", user.ID, true)
q4 := test.NewQuery(t, ds, "q4", "select * from osquery_info", user.ID, true)
queries, err := ds.ListQueries(kolide.ListOptions{})
require.Nil(t, err)
@ -70,7 +71,7 @@ func testDeleteQueries(t *testing.T, ds kolide.Datastore) {
}
func testSaveQuery(t *testing.T, ds kolide.Datastore) {
user := newUser(t, ds, "Zach", "zwass", "zwass@kolide.co", true)
user := test.NewUser(t, ds, "Zach", "zwass", "zwass@kolide.co", true)
query := &kolide.Query{
Name: "foo",
@ -79,6 +80,7 @@ func testSaveQuery(t *testing.T, ds kolide.Datastore) {
}
query, err := ds.NewQuery(query)
require.Nil(t, err)
require.NotNil(t, query)
assert.NotEqual(t, 0, query.ID)
query.Query = "baz"
@ -88,12 +90,13 @@ func testSaveQuery(t *testing.T, ds kolide.Datastore) {
queryVerify, err := ds.Query(query.ID)
require.Nil(t, err)
require.NotNil(t, queryVerify)
assert.Equal(t, "baz", queryVerify.Query)
assert.Equal(t, "Zach", queryVerify.AuthorName)
}
func testListQuery(t *testing.T, ds kolide.Datastore) {
user := newUser(t, ds, "Zach", "zwass", "zwass@kolide.co", true)
user := test.NewUser(t, ds, "Zach", "zwass", "zwass@kolide.co", true)
for i := 0; i < 10; i++ {
_, err := ds.NewQuery(&kolide.Query{
@ -127,18 +130,18 @@ func checkPacks(t *testing.T, expected []kolide.Pack, actual []kolide.Pack) {
}
func testLoadPacksForQueries(t *testing.T, ds kolide.Datastore) {
user := newUser(t, ds, "Zach", "zwass", "zwass@kolide.co", true)
user := test.NewUser(t, ds, "Zach", "zwass", "zwass@kolide.co", true)
q1 := newQuery(t, ds, "q1", "select * from time", user.ID, true)
q2 := newQuery(t, ds, "q2", "select * from osquery_info", user.ID, true)
q1 := test.NewQuery(t, ds, "q1", "select * from time", user.ID, true)
q2 := test.NewQuery(t, ds, "q2", "select * from osquery_info", user.ID, true)
p1 := newPack(t, ds, "p1")
p2 := newPack(t, ds, "p2")
p3 := newPack(t, ds, "p3")
p1 := test.NewPack(t, ds, "p1")
p2 := test.NewPack(t, ds, "p2")
p3 := test.NewPack(t, ds, "p3")
var err error
addQueryToPack(t, ds, q1.ID, p2.ID)
test.NewScheduledQuery(t, ds, p2.ID, q1.ID, 60, false, false)
q1, err = ds.Query(q1.ID)
require.Nil(t, err)
@ -147,8 +150,8 @@ func testLoadPacksForQueries(t *testing.T, ds kolide.Datastore) {
checkPacks(t, []kolide.Pack{*p2}, q1.Packs)
checkPacks(t, []kolide.Pack{}, q2.Packs)
addQueryToPack(t, ds, q2.ID, p1.ID)
addQueryToPack(t, ds, q2.ID, p3.ID)
test.NewScheduledQuery(t, ds, p1.ID, q2.ID, 60, false, false)
test.NewScheduledQuery(t, ds, p3.ID, q2.ID, 60, false, false)
q1, err = ds.Query(q1.ID)
require.Nil(t, err)
@ -157,7 +160,7 @@ func testLoadPacksForQueries(t *testing.T, ds kolide.Datastore) {
checkPacks(t, []kolide.Pack{*p2}, q1.Packs)
checkPacks(t, []kolide.Pack{*p1, *p3}, q2.Packs)
addQueryToPack(t, ds, q1.ID, p3.ID)
test.NewScheduledQuery(t, ds, p3.ID, q1.ID, 60, false, false)
q1, err = ds.Query(q1.ID)
require.Nil(t, err)

View file

@ -0,0 +1,79 @@
package datastore
import (
"testing"
"github.com/kolide/kolide-ose/server/kolide"
"github.com/kolide/kolide-ose/server/test"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func testScheduledQuery(t *testing.T, ds kolide.Datastore) {
u1 := test.NewUser(t, ds, "Admin", "admin", "admin@kolide.co", true)
q1 := test.NewQuery(t, ds, "foo", "select * from time;", u1.ID, true)
p1 := test.NewPack(t, ds, "baz")
sq1 := test.NewScheduledQuery(t, ds, p1.ID, q1.ID, 60, false, false)
query, err := ds.ScheduledQuery(sq1.ID)
require.Nil(t, err)
assert.Equal(t, uint(60), query.Interval)
}
func testDeleteScheduledQuery(t *testing.T, ds kolide.Datastore) {
u1 := test.NewUser(t, ds, "Admin", "admin", "admin@kolide.co", true)
q1 := test.NewQuery(t, ds, "foo", "select * from time;", u1.ID, true)
p1 := test.NewPack(t, ds, "baz")
sq1 := test.NewScheduledQuery(t, ds, p1.ID, q1.ID, 60, false, false)
query, err := ds.ScheduledQuery(sq1.ID)
require.Nil(t, err)
assert.Equal(t, uint(60), query.Interval)
err = ds.DeleteScheduledQuery(sq1.ID)
require.Nil(t, err)
_, err = ds.ScheduledQuery(sq1.ID)
require.NotNil(t, err)
}
func testListScheduledQueriesInPack(t *testing.T, ds kolide.Datastore) {
u1 := test.NewUser(t, ds, "Admin", "admin", "admin@kolide.co", true)
q1 := test.NewQuery(t, ds, "foo", "select * from time;", u1.ID, true)
q2 := test.NewQuery(t, ds, "bar", "select * from time;", u1.ID, true)
p1 := test.NewPack(t, ds, "baz")
test.NewScheduledQuery(t, ds, p1.ID, q1.ID, 60, false, false)
queries, err := ds.ListScheduledQueriesInPack(p1.ID, kolide.ListOptions{})
require.Nil(t, err)
require.Len(t, queries, 1)
assert.Equal(t, uint(60), queries[0].Interval)
test.NewScheduledQuery(t, ds, p1.ID, q2.ID, 60, false, false)
test.NewScheduledQuery(t, ds, p1.ID, q2.ID, 60, true, false)
queries, err = ds.ListScheduledQueriesInPack(p1.ID, kolide.ListOptions{})
require.Nil(t, err)
require.Len(t, queries, 3)
}
func testSaveScheduledQuery(t *testing.T, ds kolide.Datastore) {
u1 := test.NewUser(t, ds, "Admin", "admin", "admin@kolide.co", true)
q1 := test.NewQuery(t, ds, "foo", "select * from time;", u1.ID, true)
p1 := test.NewPack(t, ds, "baz")
sq1 := test.NewScheduledQuery(t, ds, p1.ID, q1.ID, 60, false, false)
query, err := ds.ScheduledQuery(sq1.ID)
require.Nil(t, err)
assert.Equal(t, uint(60), query.Interval)
query.Interval = uint(120)
query, err = ds.SaveScheduledQuery(query)
require.Nil(t, err)
assert.Equal(t, uint(120), query.Interval)
queryVerify, err := ds.ScheduledQuery(sq1.ID)
require.Nil(t, err)
assert.Equal(t, uint(120), queryVerify.Interval)
}

View file

@ -26,7 +26,6 @@ var testFunctions = [...]func(*testing.T, kolide.Datastore){
testSaveQuery,
testListQuery,
testDeletePack,
testAddAndRemoveQueryFromPack,
testEnrollHost,
testAuthenticateHost,
testLabels,
@ -51,4 +50,8 @@ var testFunctions = [...]func(*testing.T, kolide.Datastore){
testCleanupDistributedQueryCampaigns,
testBuiltInLabels,
testLoadPacksForQueries,
testScheduledQuery,
testDeleteScheduledQuery,
testListScheduledQueriesInPack,
testSaveScheduledQuery,
}

View file

@ -26,7 +26,7 @@ type Datastore struct {
queries map[uint]*kolide.Query
packs map[uint]*kolide.Pack
hosts map[uint]*kolide.Host
packQueries map[uint]*kolide.PackQuery
scheduledQueries map[uint]*kolide.ScheduledQuery
packTargets map[uint]*kolide.PackTarget
distributedQueryExecutions map[uint]kolide.DistributedQueryExecution
distributedQueryCampaigns map[uint]kolide.DistributedQueryCampaign
@ -81,7 +81,7 @@ func (orm *Datastore) Migrate() error {
orm.queries = make(map[uint]*kolide.Query)
orm.packs = make(map[uint]*kolide.Pack)
orm.hosts = make(map[uint]*kolide.Host)
orm.packQueries = make(map[uint]*kolide.PackQuery)
orm.scheduledQueries = make(map[uint]*kolide.ScheduledQuery)
orm.packTargets = make(map[uint]*kolide.PackTarget)
orm.distributedQueryExecutions = make(map[uint]kolide.DistributedQueryExecution)
orm.distributedQueryCampaigns = make(map[uint]kolide.DistributedQueryCampaign)
@ -164,9 +164,8 @@ func (orm *Datastore) createDevPacksAndQueries() error {
}
query2 := &kolide.Query{
Name: "Launchd",
Query: "select * from launchd",
Platform: "darwin",
Name: "Launchd",
Query: "select * from launchd",
}
query2, err = orm.NewQuery(query2)
if err != nil {
@ -198,17 +197,31 @@ func (orm *Datastore) createDevPacksAndQueries() error {
return err
}
err = orm.AddQueryToPack(query1.ID, pack1.ID)
_, err = orm.NewScheduledQuery(&kolide.ScheduledQuery{
QueryID: query1.ID,
PackID: pack1.ID,
Interval: 60,
})
if err != nil {
return err
}
err = orm.AddQueryToPack(query3.ID, pack1.ID)
t := true
_, err = orm.NewScheduledQuery(&kolide.ScheduledQuery{
QueryID: query3.ID,
PackID: pack1.ID,
Interval: 60,
Snapshot: &t,
})
if err != nil {
return err
}
err = orm.AddQueryToPack(query2.ID, pack2.ID)
_, err = orm.NewScheduledQuery(&kolide.ScheduledQuery{
QueryID: query2.ID,
PackID: pack2.ID,
Interval: 60,
})
if err != nil {
return err
}

View file

@ -97,50 +97,6 @@ func (orm *Datastore) ListPacks(opt kolide.ListOptions) ([]*kolide.Pack, error)
return packs, nil
}
func (orm *Datastore) AddQueryToPack(qid uint, pid uint) error {
packQuery := &kolide.PackQuery{
PackID: pid,
QueryID: qid,
}
orm.mtx.Lock()
packQuery.ID = orm.nextID(packQuery)
orm.packQueries[packQuery.ID] = packQuery
orm.mtx.Unlock()
return nil
}
func (orm *Datastore) ListQueriesInPack(pack *kolide.Pack) ([]*kolide.Query, error) {
var queries []*kolide.Query
orm.mtx.Lock()
for _, packQuery := range orm.packQueries {
queries = append(queries, orm.queries[packQuery.QueryID])
}
orm.mtx.Unlock()
return queries, nil
}
func (orm *Datastore) RemoveQueryFromPack(query *kolide.Query, pack *kolide.Pack) error {
var packQueriesToDelete []uint
orm.mtx.Lock()
for _, packQuery := range orm.packQueries {
if packQuery.QueryID == query.ID && packQuery.PackID == pack.ID {
packQueriesToDelete = append(packQueriesToDelete, packQuery.ID)
}
}
for _, packQueryToDelete := range packQueriesToDelete {
delete(orm.packQueries, packQueryToDelete)
}
orm.mtx.Unlock()
return nil
}
func (orm *Datastore) AddLabelToPack(lid uint, pid uint) error {
pt := &kolide.PackTarget{
PackID: pid,

View file

@ -145,9 +145,9 @@ func (orm *Datastore) ListQueries(opt kolide.ListOptions) ([]*kolide.Query, erro
func (orm *Datastore) loadPacksForQueries(queries []*kolide.Query) error {
for _, q := range queries {
q.Packs = make([]kolide.Pack, 0)
for _, pq := range orm.packQueries {
if pq.QueryID == q.ID {
q.Packs = append(q.Packs, *orm.packs[pq.PackID])
for _, sq := range orm.scheduledQueries {
if sq.QueryID == q.ID {
q.Packs = append(q.Packs, *orm.packs[sq.PackID])
}
}
}

View file

@ -0,0 +1,111 @@
package inmem
import (
"sort"
"github.com/kolide/kolide-ose/server/errors"
"github.com/kolide/kolide-ose/server/kolide"
)
func (orm *Datastore) NewScheduledQuery(sq *kolide.ScheduledQuery) (*kolide.ScheduledQuery, error) {
orm.mtx.Lock()
defer orm.mtx.Unlock()
newScheduledQuery := *sq
newScheduledQuery.ID = orm.nextID(newScheduledQuery)
orm.scheduledQueries[newScheduledQuery.ID] = &newScheduledQuery
return &newScheduledQuery, nil
}
func (orm *Datastore) SaveScheduledQuery(sq *kolide.ScheduledQuery) (*kolide.ScheduledQuery, error) {
orm.mtx.Lock()
defer orm.mtx.Unlock()
if _, ok := orm.scheduledQueries[sq.ID]; !ok {
return nil, errors.ErrNotFound
}
orm.scheduledQueries[sq.ID] = sq
return sq, nil
}
func (orm *Datastore) DeleteScheduledQuery(id uint) error {
orm.mtx.Lock()
defer orm.mtx.Unlock()
if _, ok := orm.scheduledQueries[id]; !ok {
return errors.ErrNotFound
}
delete(orm.scheduledQueries, id)
return nil
}
func (orm *Datastore) ScheduledQuery(id uint) (*kolide.ScheduledQuery, error) {
orm.mtx.Lock()
defer orm.mtx.Unlock()
sq, ok := orm.scheduledQueries[id]
if !ok {
return nil, errors.ErrNotFound
}
sq.Name = orm.queries[sq.QueryID].Name
sq.Query = orm.queries[sq.QueryID].Query
return sq, nil
}
func (orm *Datastore) ListScheduledQueriesInPack(id uint, opt kolide.ListOptions) ([]*kolide.ScheduledQuery, error) {
orm.mtx.Lock()
defer orm.mtx.Unlock()
// We need to sort by keys to provide reliable ordering
keys := []int{}
for k, sq := range orm.scheduledQueries {
if sq.PackID == id {
keys = append(keys, int(k))
}
}
if len(keys) == 0 {
return []*kolide.ScheduledQuery{}, nil
}
sort.Ints(keys)
scheduledQueries := []*kolide.ScheduledQuery{}
for _, k := range keys {
q := orm.scheduledQueries[uint(k)]
q.Name = orm.queries[q.QueryID].Name
q.Query = orm.queries[q.QueryID].Query
scheduledQueries = append(scheduledQueries, q)
}
// Apply ordering
if opt.OrderKey != "" {
var fields = map[string]string{
"id": "ID",
"created_at": "CreatedAt",
"updated_at": "UpdatedAt",
"name": "Name",
"query": "Query",
"interval": "Interval",
"snapshot": "Snapshot",
"removed": "Removed",
"platform": "Platform",
"version": "Version",
}
if err := sortResults(scheduledQueries, opt, fields); err != nil {
return nil, err
}
}
// Apply limit/offset
low, high := orm.getLimitOffsetSliceBounds(opt, len(scheduledQueries))
scheduledQueries = scheduledQueries[low:high]
return scheduledQueries, nil
}

View file

@ -12,12 +12,20 @@ func init() {
func Up_20161118212613(tx *sql.Tx) error {
_, err := tx.Exec(
"CREATE TABLE `pack_queries` (" +
"CREATE TABLE `scheduled_queries` (" +
"`id` int(10) unsigned NOT NULL AUTO_INCREMENT," +
"`created_at` timestamp DEFAULT CURRENT_TIMESTAMP," +
"`updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP," +
"`deleted_at` timestamp NULL DEFAULT NULL," +
"`deleted` tinyint(1) NOT NULL DEFAULT FALSE," +
"`pack_id` int(10) unsigned DEFAULT NULL," +
"`query_id` int(10) unsigned DEFAULT NULL," +
"`interval` int(10) unsigned DEFAULT NULL," +
"`snapshot` tinyint(1) DEFAULT NULL," +
"`removed` tinyint(1) DEFAULT NULL," +
"`platform` varchar(255) DEFAULT NULL," +
"`version` varchar(255) DEFAULT NULL," +
"`shard` int(10) unsigned DEFAULT NULL," +
"PRIMARY KEY (`id`)" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8;",
)
@ -25,6 +33,6 @@ func Up_20161118212613(tx *sql.Tx) error {
}
func Down_20161118212613(tx *sql.Tx) error {
_, err := tx.Exec("DROP TABLE IF EXISTS `pack_queries`;")
_, err := tx.Exec("DROP TABLE IF EXISTS `scheduled_queries`;")
return err
}

View file

@ -22,11 +22,6 @@ func Up_20161118212758(tx *sql.Tx) error {
"`name` varchar(255) NOT NULL," +
"`description` varchar(255) DEFAULT NULL," +
"`query` varchar(255) NOT NULL," +
"`interval` int(10) unsigned DEFAULT NULL," +
"`snapshot` tinyint(1) NOT NULL DEFAULT FALSE," +
"`differential` tinyint(1) NOT NULL DEFAULT FALSE," +
"`platform` varchar(255) DEFAULT NULL," +
"`version` varchar(255) DEFAULT NULL," +
"`author_id` int(10) unsigned DEFAULT NULL," +
"PRIMARY KEY (`id`)," +
"FOREIGN KEY (`author_id`) REFERENCES `users`(`id`) ON DELETE SET NULL" +

View file

@ -27,7 +27,7 @@ func (d *Datastore) NewPack(pack *kolide.Pack) (*kolide.Pack, error) {
func (d *Datastore) SavePack(pack *kolide.Pack) error {
sql := `
UPDATE packs
UPDATE packs
SET name = ?, platform = ?, disabled = ?, description = ?,
WHERE id = ? AND NOT deleted
`
@ -57,10 +57,7 @@ func (d *Datastore) DeletePack(pid uint) error {
// Pack fetch kolide.Pack with matching ID
func (d *Datastore) Pack(pid uint) (*kolide.Pack, error) {
sql := `
SELECT * FROM packs
WHERE id = ? AND NOT deleted
`
sql := `SELECT * FROM packs WHERE id = ? AND NOT deleted`
pack := &kolide.Pack{}
if err := d.db.Get(pack, sql, pid); err != nil {
return nil, errors.DatabaseError(err)
@ -71,10 +68,7 @@ func (d *Datastore) Pack(pid uint) (*kolide.Pack, error) {
// ListPacks returns all kolide.Pack records limited and sorted by kolide.ListOptions
func (d *Datastore) ListPacks(opt kolide.ListOptions) ([]*kolide.Pack, error) {
sql := `
SELECT * FROM packs
WHERE NOT deleted
`
sql := `SELECT * FROM packs WHERE NOT deleted`
sql = appendListOptionsToSQL(sql, opt)
packs := []*kolide.Pack{}
if err := d.db.Select(&packs, sql); err != nil {
@ -83,68 +77,10 @@ func (d *Datastore) ListPacks(opt kolide.ListOptions) ([]*kolide.Pack, error) {
return packs, nil
}
// AddQueryToPack associates a kolide.Query with a kolide.Pack
func (d *Datastore) AddQueryToPack(qid uint, pid uint) error {
sql := `
INSERT INTO pack_queries (query_id, pack_id)
VALUES (?, ?)
`
if _, err := d.db.Exec(sql, qid, pid); err != nil {
return errors.DatabaseError(err)
}
return nil
}
// ListQueriesInPack gets all kolide.Query records associated with a kolide.Pack
func (d *Datastore) ListQueriesInPack(pack *kolide.Pack) ([]*kolide.Query, error) {
sql := `
SELECT
q.id,
q.created_at,
q.updated_at,
q.name,
q.query,
q.interval,
q.snapshot,
q.differential,
q.platform,
q.version
FROM
queries q
JOIN
pack_queries pq
ON
pq.query_id = q.id
AND
pq.pack_id = ?
AND NOT q.deleted
`
queries := []*kolide.Query{}
if err := d.db.Select(&queries, sql, pack.ID); err != nil {
return nil, errors.DatabaseError(err)
}
return queries, nil
}
// RemoveQueryFromPack disassociated a kolide.Query from a kolide.Pack
func (d *Datastore) RemoveQueryFromPack(query *kolide.Query, pack *kolide.Pack) error {
sql := `
DELETE FROM pack_queries
WHERE pack_id = ? AND query_id = ?
`
if _, err := d.db.Exec(sql, pack.ID, query.ID); err != nil {
return errors.DatabaseError(err)
}
return nil
}
// AddLabelToPack associates a kolide.Label with a kolide.Pack
func (d *Datastore) AddLabelToPack(lid uint, pid uint) error {
sql := `
INSERT INTO pack_targets ( pack_id, type, target_id )
INSERT INTO pack_targets ( pack_id, type, target_id )
VALUES ( ?, ?, ? )
`
_, err := d.db.Exec(sql, pid, kolide.TargetLabel, lid)

View file

@ -10,15 +10,15 @@ import (
func (d *Datastore) NewQuery(query *kolide.Query) (*kolide.Query, error) {
sql := `
INSERT INTO queries (name, description, query,
saved, snapshot, differential, platform, version,
` + "`interval`" + `, author_id)
VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )
INSERT INTO queries (
name,
description,
query,
saved,
author_id
) VALUES ( ?, ?, ?, ?, ? )
`
result, err := d.db.Exec(sql, query.Name, query.Description, query.Query,
query.Saved, query.Snapshot, query.Differential, query.Platform, query.Version,
query.Interval, query.AuthorID)
result, err := d.db.Exec(sql, query.Name, query.Description, query.Query, query.Saved, query.AuthorID)
if err != nil {
return nil, errors.DatabaseError(err)
}
@ -32,15 +32,10 @@ func (d *Datastore) NewQuery(query *kolide.Query) (*kolide.Query, error) {
func (d *Datastore) SaveQuery(q *kolide.Query) error {
sql := `
UPDATE queries
SET name = ?, description = ?, query = ?, ` + "`interval`" + ` = ?,
saved = ?, snapshot = ?, differential = ?, platform = ?, version = ?,
author_id = ?
SET name = ?, description = ?, query = ?, author_id = ?, saved = ?
WHERE id = ? AND NOT deleted
`
_, err := d.db.Exec(sql, q.Name, q.Description, q.Query, q.Interval,
q.Saved, q.Snapshot, q.Differential, q.Platform, q.Version,
q.AuthorID,
q.ID)
_, err := d.db.Exec(sql, q.Name, q.Description, q.Query, q.AuthorID, q.Saved, q.ID)
if err != nil {
return errors.DatabaseError(err)
}
@ -146,10 +141,10 @@ func (d *Datastore) loadPacksForQueries(queries []*kolide.Query) error {
}
sql := `
SELECT p.*, pq.query_id AS query_id
SELECT p.*, sq.query_id AS query_id
FROM packs p
JOIN pack_queries pq
ON p.id = pq.pack_id
JOIN scheduled_queries sq
ON p.id = sq.pack_id
WHERE query_id IN (?)
`

View file

@ -0,0 +1,93 @@
package mysql
import (
"github.com/kolide/kolide-ose/server/errors"
"github.com/kolide/kolide-ose/server/kolide"
)
func (d *Datastore) NewScheduledQuery(sq *kolide.ScheduledQuery) (*kolide.ScheduledQuery, error) {
sql := `
INSERT INTO scheduled_queries (
pack_id,
query_id,
snapshot,
removed,
` + "`interval`" + `,
platform,
version,
shard
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
`
result, err := d.db.Exec(sql, sq.PackID, sq.QueryID, sq.Snapshot, sq.Removed, sq.Interval, sq.Platform, sq.Version, sq.Shard)
if err != nil {
return nil, errors.DatabaseError(err)
}
id, _ := result.LastInsertId()
sq.ID = uint(id)
return sq, nil
}
func (d *Datastore) SaveScheduledQuery(sq *kolide.ScheduledQuery) (*kolide.ScheduledQuery, error) {
sql := `
UPDATE scheduled_queries
SET pack_id = ?, query_id = ?, ` + "`interval`" + ` = ?, snapshot = ?, removed = ?, platform = ?, version = ?, shard = ?
WHERE id = ? AND NOT deleted
`
_, err := d.db.Exec(sql, sq.PackID, sq.QueryID, sq.Interval, sq.Snapshot, sq.Removed, sq.Platform, sq.Version, sq.Shard, sq.ID)
if err != nil {
return nil, errors.DatabaseError(err)
}
return sq, nil
}
func (d *Datastore) DeleteScheduledQuery(id uint) error {
sql := `
UPDATE scheduled_queries
SET deleted_at = ?, deleted = ?
WHERE id = ?
`
_, err := d.db.Exec(sql, d.clock.Now(), true, id)
if err != nil {
return errors.DatabaseError(err)
}
return nil
}
func (d *Datastore) ScheduledQuery(id uint) (*kolide.ScheduledQuery, error) {
sql := `
SELECT sq.*, q.query, q.name
FROM scheduled_queries sq
JOIN queries q
ON sq.query_id = q.id
WHERE sq.id = ?
AND NOT sq.deleted
`
sq := &kolide.ScheduledQuery{}
if err := d.db.Get(sq, sql, id); err != nil {
return nil, errors.DatabaseError(err)
}
return sq, nil
}
func (d *Datastore) ListScheduledQueriesInPack(id uint, opts kolide.ListOptions) ([]*kolide.ScheduledQuery, error) {
sql := `
SELECT sq.*, q.query, q.name
FROM scheduled_queries sq
JOIN queries q
ON sq.query_id = q.id
WHERE sq.pack_id = ?
AND NOT sq.deleted
`
sql = appendListOptionsToSQL(sql, opts)
results := []*kolide.ScheduledQuery{}
if err := d.db.Select(&results, sql, id); err != nil {
return nil, errors.DatabaseError(err)
}
return results, nil
}

View file

@ -12,6 +12,7 @@ type Datastore interface {
SessionStore
AppConfigStore
InviteStore
ScheduledQueryStore
Name() string
Drop() error
Migrate() error

View file

@ -17,14 +17,14 @@ type OsqueryService interface {
type OsqueryDistributedQueryResults map[string][]map[string]string
type QueryContent struct {
Query string `json:"query"`
Description string `json:"description,omitempty"`
Interval uint `json:"interval"`
Platform string `json:"platform,omitempty"`
Version string `json:"version,omitempty"`
Snapshot bool `json:"snapshot,omitempty"`
Removed bool `json:"removed,omitempty"`
Shard uint `json:"shard,omitempty"`
Query string `json:"query"`
Description string `json:"description,omitempty"`
Interval uint `json:"interval"`
Platform *string `json:"platform,omitempty"`
Version *string `json:"version,omitempty"`
Snapshot *bool `json:"snapshot,omitempty"`
Removed *bool `json:"removed,omitempty"`
Shard *uint `json:"shard,omitempty"`
}
type Queries map[string]QueryContent

View file

@ -1,8 +1,6 @@
package kolide
import (
"time"
"golang.org/x/net/context"
)
@ -14,11 +12,6 @@ type PackStore interface {
Pack(pid uint) (*Pack, error)
ListPacks(opt ListOptions) ([]*Pack, error)
// Modifying the queries in packs
AddQueryToPack(qid uint, pid uint) error
ListQueriesInPack(pack *Pack) ([]*Query, error)
RemoveQueryFromPack(query *Query, pack *Pack) error
// Modifying the labels for packs
AddLabelToPack(lid uint, pid uint) error
ListLabelsForPack(pid uint) ([]*Label, error)
@ -34,10 +27,6 @@ type PackService interface {
ModifyPack(ctx context.Context, id uint, p PackPayload) (*Pack, error)
DeletePack(ctx context.Context, id uint) error
AddQueryToPack(ctx context.Context, qid, pid uint) error
ListQueriesInPack(ctx context.Context, id uint) ([]*Query, error)
RemoveQueryFromPack(ctx context.Context, qid, pid uint) error
AddLabelToPack(ctx context.Context, lid, pid uint) error
ListLabelsForPack(ctx context.Context, pid uint) ([]*Label, error)
RemoveLabelFromPack(ctx context.Context, lid, pid uint) error
@ -64,14 +53,6 @@ type PackPayload struct {
Disabled *bool
}
type PackQuery struct {
ID uint
CreatedAt time.Time
UpdatedAt time.Time
PackID uint
QueryID uint
}
type PackTarget struct {
ID uint
PackID uint

View file

@ -42,30 +42,20 @@ type QueryService interface {
}
type QueryPayload struct {
Name *string `json:"name"`
Description *string `json:"description"`
Query *string `json:"query"`
Interval *uint `json:"interval"`
Snapshot *bool `json:"snapshot"`
Differential *bool `json:"differential"`
Platform *string `json:"platform"`
Version *string `json:"version"`
Name *string
Description *string
Query *string
}
type Query struct {
UpdateCreateTimestamps
DeleteFields
ID uint `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
Query string `json:"query"`
Interval uint `json:"interval"`
Saved bool `json:"saved"`
Snapshot bool `json:"snapshot"`
Differential bool `json:"differential"`
Platform string `json:"platform"`
Version string `json:"version"`
AuthorID uint `json:"author_id" db:"author_id"`
ID uint `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
Query string `json:"query"`
Saved bool `json:"saved"`
AuthorID uint `json:"author_id" db:"author_id"`
// AuthorName is retrieved with a join to the users table in the MySQL
// backend (using AuthorID)
AuthorName string `json:"author_name" db:"author_name"`

View file

@ -0,0 +1,37 @@
package kolide
import (
"golang.org/x/net/context"
)
type ScheduledQueryStore interface {
NewScheduledQuery(sq *ScheduledQuery) (*ScheduledQuery, error)
SaveScheduledQuery(sq *ScheduledQuery) (*ScheduledQuery, error)
DeleteScheduledQuery(id uint) error
ScheduledQuery(id uint) (*ScheduledQuery, error)
ListScheduledQueriesInPack(id uint, opts ListOptions) ([]*ScheduledQuery, error)
}
type ScheduledQueryService interface {
GetScheduledQuery(ctx context.Context, id uint) (*ScheduledQuery, error)
GetScheduledQueriesInPack(ctx context.Context, id uint, opts ListOptions) ([]*ScheduledQuery, error)
ScheduleQuery(ctx context.Context, sq *ScheduledQuery) (*ScheduledQuery, error)
DeleteScheduledQuery(ctx context.Context, id uint) error
ModifyScheduledQuery(ctx context.Context, sq *ScheduledQuery) (*ScheduledQuery, error)
}
type ScheduledQuery struct {
UpdateCreateTimestamps
DeleteFields
ID uint
PackID uint `json:"pack_id" db:"pack_id"`
QueryID uint `json:"query_id" db:"query_id"`
Query string `json:"query"` // populated via a join on queries
Name string `json:"name"` // populated via a join on queries
Interval uint `json:"interval"`
Snapshot *bool `json:"snapshot"`
Removed *bool `json:"removed"`
Platform *string `json:"platform"`
Version *string `json:"version"`
Shard *uint `json:"shard"`
}

View file

@ -13,4 +13,5 @@ type Service interface {
AppConfigService
InviteService
TargetService
ScheduledQueryService
}

View file

@ -36,7 +36,7 @@ func makeGetPackEndpoint(svc kolide.Service) endpoint.Endpoint {
return getPackResponse{Err: err}, nil
}
queries, err := svc.ListQueriesInPack(ctx, pack.ID)
queries, err := svc.GetScheduledQueriesInPack(ctx, pack.ID, kolide.ListOptions{})
if err != nil {
return getPackResponse{Err: err}, nil
}
@ -81,7 +81,7 @@ func makeListPacksEndpoint(svc kolide.Service) endpoint.Endpoint {
resp := listPacksResponse{Packs: []packResponse{}}
for _, pack := range packs {
queries, err := svc.ListQueriesInPack(ctx, pack.ID)
queries, err := svc.GetScheduledQueriesInPack(ctx, pack.ID, kolide.ListOptions{})
if err != nil {
return getPackResponse{Err: err}, nil
}
@ -177,89 +177,6 @@ func makeDeletePackEndpoint(svc kolide.Service) endpoint.Endpoint {
}
}
////////////////////////////////////////////////////////////////////////////////
// Add Query To Pack
////////////////////////////////////////////////////////////////////////////////
type addQueryToPackRequest struct {
QueryID uint
PackID uint
}
type addQueryToPackResponse struct {
Err error `json:"error,omitempty"`
}
func (r addQueryToPackResponse) error() error { return r.Err }
func makeAddQueryToPackEndpoint(svc kolide.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
req := request.(addQueryToPackRequest)
err := svc.AddQueryToPack(ctx, req.QueryID, req.PackID)
if err != nil {
return addQueryToPackResponse{Err: err}, nil
}
return addQueryToPackResponse{}, nil
}
}
////////////////////////////////////////////////////////////////////////////////
// Get Queries In Pack
////////////////////////////////////////////////////////////////////////////////
type getQueriesInPackRequest struct {
ID uint
}
type getQueriesInPackResponse struct {
Queries []kolide.Query `json:"queries"`
Err error `json:"error,omitempty"`
}
func (r getQueriesInPackResponse) error() error { return r.Err }
func makeGetQueriesInPackEndpoint(svc kolide.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
req := request.(getQueriesInPackRequest)
queries, err := svc.ListQueriesInPack(ctx, req.ID)
if err != nil {
return getQueriesInPackResponse{Err: err}, nil
}
var resp getQueriesInPackResponse
for _, query := range queries {
resp.Queries = append(resp.Queries, *query)
}
return resp, nil
}
}
////////////////////////////////////////////////////////////////////////////////
// Delete Query From Pack
////////////////////////////////////////////////////////////////////////////////
type deleteQueryFromPackRequest struct {
QueryID uint
PackID uint
}
type deleteQueryFromPackResponse struct {
Err error `json:"error,omitempty"`
}
func (r deleteQueryFromPackResponse) error() error { return r.Err }
func makeDeleteQueryFromPackEndpoint(svc kolide.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
req := request.(deleteQueryFromPackRequest)
err := svc.RemoveQueryFromPack(ctx, req.QueryID, req.PackID)
if err != nil {
return deleteQueryFromPackResponse{Err: err}, nil
}
return deleteQueryFromPackResponse{}, nil
}
}
////////////////////////////////////////////////////////////////////////////////
// Add Label To Pack
////////////////////////////////////////////////////////////////////////////////

View file

@ -0,0 +1,198 @@
package service
import (
"github.com/go-kit/kit/endpoint"
"github.com/kolide/kolide-ose/server/kolide"
"golang.org/x/net/context"
)
////////////////////////////////////////////////////////////////////////////////
// Get Scheduled Query
////////////////////////////////////////////////////////////////////////////////
type getScheduledQueryRequest struct {
ID uint
}
type scheduledQueryResponse struct {
kolide.ScheduledQuery
}
type getScheduledQueryResponse struct {
Scheduled scheduledQueryResponse `json:"scheduled,omitempty"`
Err error `json:"error,omitempty"`
}
func (r getScheduledQueryResponse) error() error { return r.Err }
func makeGetScheduledQueryEndpoint(svc kolide.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
req := request.(getScheduledQueryRequest)
sq, err := svc.GetScheduledQuery(ctx, req.ID)
if err != nil {
return getScheduledQueryResponse{Err: err}, nil
}
return getScheduledQueryResponse{
Scheduled: scheduledQueryResponse{
ScheduledQuery: *sq,
},
}, nil
}
}
////////////////////////////////////////////////////////////////////////////////
// Get Scheduled Queries In Pack
////////////////////////////////////////////////////////////////////////////////
type getScheduledQueriesInPackRequest struct {
ID uint
ListOptions kolide.ListOptions
}
type getScheduledQueriesInPackResponse struct {
Scheduled []scheduledQueryResponse `json:"scheduled"`
Err error `json:"error,omitempty"`
}
func (r getScheduledQueriesInPackResponse) error() error { return r.Err }
func makeGetScheduledQueriesInPackEndpoint(svc kolide.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
req := request.(getScheduledQueriesInPackRequest)
resp := getScheduledQueriesInPackResponse{Scheduled: []scheduledQueryResponse{}}
queries, err := svc.GetScheduledQueriesInPack(ctx, req.ID, req.ListOptions)
if err != nil {
return getScheduledQueriesInPackResponse{Err: err}, nil
}
for _, q := range queries {
resp.Scheduled = append(resp.Scheduled, scheduledQueryResponse{
ScheduledQuery: *q,
})
}
return resp, nil
}
}
////////////////////////////////////////////////////////////////////////////////
// Schedule Queries
////////////////////////////////////////////////////////////////////////////////
type scheduleQuerySubmission struct {
PackID uint `json:"pack_id"`
QueryIDs []uint `json:"query_ids"`
Interval uint `json:"interval"`
Snapshot *bool `json:"snapshot"`
Removed *bool `json:"removed"`
Platform *string `json:"platform"`
Version *string `json:"version"`
Shard *uint `json:"shard"`
}
type scheduleQueriesRequest struct {
Options []scheduleQuerySubmission `json:"options"`
}
type scheduleQueriesResponse struct {
Scheduled []scheduledQueryResponse `json:"scheduled"`
Err error `json:"error,omitempty"`
}
func (r scheduleQueriesResponse) error() error { return r.Err }
func makeScheduleQueriesEndpoint(svc kolide.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
req := request.(scheduleQueriesRequest)
resp := getScheduledQueriesInPackResponse{Scheduled: []scheduledQueryResponse{}}
for _, submission := range req.Options {
for _, queryID := range submission.QueryIDs {
scheduled, err := svc.ScheduleQuery(ctx, &kolide.ScheduledQuery{
PackID: submission.PackID,
QueryID: queryID,
Interval: submission.Interval,
Snapshot: submission.Snapshot,
Removed: submission.Removed,
Platform: submission.Platform,
Version: submission.Version,
Shard: submission.Shard,
})
if err != nil {
return scheduleQueriesResponse{Err: err}, nil
}
resp.Scheduled = append(resp.Scheduled, scheduledQueryResponse{
ScheduledQuery: *scheduled,
})
}
}
return resp, nil
}
}
////////////////////////////////////////////////////////////////////////////////
// Modify Scheduled Query
////////////////////////////////////////////////////////////////////////////////
type modifyScheduledQueryRequest struct {
ID uint
payload *kolide.ScheduledQuery
}
type modifyScheduledQueryResponse struct {
Scheduled scheduledQueryResponse `json:"scheduled,omitempty"`
Err error `json:"error,omitempty"`
}
func (r modifyScheduledQueryResponse) error() error { return r.Err }
func makeModifyScheduledQueryEndpoint(svc kolide.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
req := request.(modifyScheduledQueryRequest)
sq := req.payload
sq.ID = req.ID
sq, err := svc.ModifyScheduledQuery(ctx, sq)
if err != nil {
return modifyScheduledQueryResponse{Err: err}, nil
}
return modifyScheduledQueryResponse{
Scheduled: scheduledQueryResponse{
ScheduledQuery: *sq,
},
}, nil
}
}
////////////////////////////////////////////////////////////////////////////////
// Delete Scheduled Query
////////////////////////////////////////////////////////////////////////////////
type deleteScheduledQueryRequest struct {
ID uint
}
type deleteScheduledQueryResponse struct {
Err error `json:"error,omitempty"`
}
func (r deleteScheduledQueryResponse) error() error { return r.Err }
func makeDeleteScheduledQueryEndpoint(svc kolide.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
req := request.(deleteScheduledQueryRequest)
err := svc.DeleteScheduledQuery(ctx, req.ID)
if err != nil {
return deleteScheduledQueryResponse{Err: err}, nil
}
return deleteScheduledQueryResponse{}, nil
}
}

View file

@ -44,9 +44,11 @@ type KolideEndpoints struct {
CreatePack endpoint.Endpoint
ModifyPack endpoint.Endpoint
DeletePack endpoint.Endpoint
AddQueryToPack endpoint.Endpoint
GetQueriesInPack endpoint.Endpoint
DeleteQueryFromPack endpoint.Endpoint
ScheduleQueries endpoint.Endpoint
GetScheduledQueriesInPack endpoint.Endpoint
GetScheduledQuery endpoint.Endpoint
ModifyScheduledQuery endpoint.Endpoint
DeleteScheduledQuery endpoint.Endpoint
EnrollAgent endpoint.Endpoint
GetClientConfig endpoint.Endpoint
GetDistributedQueries endpoint.Endpoint
@ -94,32 +96,34 @@ func MakeKolideServerEndpoints(svc kolide.Service, jwtKey string) KolideEndpoint
CreateInvite: authenticatedUser(jwtKey, svc, mustBeAdmin(makeCreateInviteEndpoint(svc))),
ListInvites: authenticatedUser(jwtKey, svc, mustBeAdmin(makeListInvitesEndpoint(svc))),
DeleteInvite: authenticatedUser(jwtKey, svc, mustBeAdmin(makeDeleteInviteEndpoint(svc))),
GetQuery: authenticatedUser(jwtKey, svc, canPerformActions(makeGetQueryEndpoint(svc))),
ListQueries: authenticatedUser(jwtKey, svc, canPerformActions(makeListQueriesEndpoint(svc))),
CreateQuery: authenticatedUser(jwtKey, svc, canPerformActions(makeCreateQueryEndpoint(svc))),
ModifyQuery: authenticatedUser(jwtKey, svc, canPerformActions(makeModifyQueryEndpoint(svc))),
DeleteQuery: authenticatedUser(jwtKey, svc, canPerformActions(makeDeleteQueryEndpoint(svc))),
DeleteQueries: authenticatedUser(jwtKey, svc, canPerformActions(makeDeleteQueriesEndpoint(svc))),
CreateDistributedQueryCampaign: authenticatedUser(jwtKey, svc, canPerformActions(makeCreateDistributedQueryCampaignEndpoint(svc))),
GetPack: authenticatedUser(jwtKey, svc, canPerformActions(makeGetPackEndpoint(svc))),
ListPacks: authenticatedUser(jwtKey, svc, canPerformActions(makeListPacksEndpoint(svc))),
CreatePack: authenticatedUser(jwtKey, svc, canPerformActions(makeCreatePackEndpoint(svc))),
ModifyPack: authenticatedUser(jwtKey, svc, canPerformActions(makeModifyPackEndpoint(svc))),
DeletePack: authenticatedUser(jwtKey, svc, canPerformActions(makeDeletePackEndpoint(svc))),
AddQueryToPack: authenticatedUser(jwtKey, svc, canPerformActions(makeAddQueryToPackEndpoint(svc))),
GetQueriesInPack: authenticatedUser(jwtKey, svc, canPerformActions(makeGetQueriesInPackEndpoint(svc))),
DeleteQueryFromPack: authenticatedUser(jwtKey, svc, canPerformActions(makeDeleteQueryFromPackEndpoint(svc))),
GetHost: authenticatedUser(jwtKey, svc, canPerformActions(makeGetHostEndpoint(svc))),
ListHosts: authenticatedUser(jwtKey, svc, canPerformActions(makeListHostsEndpoint(svc))),
DeleteHost: authenticatedUser(jwtKey, svc, canPerformActions(makeDeleteHostEndpoint(svc))),
GetLabel: authenticatedUser(jwtKey, svc, canPerformActions(makeGetLabelEndpoint(svc))),
ListLabels: authenticatedUser(jwtKey, svc, canPerformActions(makeListLabelsEndpoint(svc))),
CreateLabel: authenticatedUser(jwtKey, svc, canPerformActions(makeCreateLabelEndpoint(svc))),
DeleteLabel: authenticatedUser(jwtKey, svc, canPerformActions(makeDeleteLabelEndpoint(svc))),
AddLabelToPack: authenticatedUser(jwtKey, svc, canPerformActions(makeAddLabelToPackEndpoint(svc))),
GetLabelsForPack: authenticatedUser(jwtKey, svc, canPerformActions(makeGetLabelsForPackEndpoint(svc))),
DeleteLabelFromPack: authenticatedUser(jwtKey, svc, canPerformActions(makeDeleteLabelFromPackEndpoint(svc))),
SearchTargets: authenticatedUser(jwtKey, svc, canPerformActions(makeSearchTargetsEndpoint(svc))),
GetQuery: authenticatedUser(jwtKey, svc, makeGetQueryEndpoint(svc)),
ListQueries: authenticatedUser(jwtKey, svc, makeListQueriesEndpoint(svc)),
CreateQuery: authenticatedUser(jwtKey, svc, makeCreateQueryEndpoint(svc)),
ModifyQuery: authenticatedUser(jwtKey, svc, makeModifyQueryEndpoint(svc)),
DeleteQuery: authenticatedUser(jwtKey, svc, makeDeleteQueryEndpoint(svc)),
DeleteQueries: authenticatedUser(jwtKey, svc, makeDeleteQueriesEndpoint(svc)),
CreateDistributedQueryCampaign: authenticatedUser(jwtKey, svc, makeCreateDistributedQueryCampaignEndpoint(svc)),
GetPack: authenticatedUser(jwtKey, svc, makeGetPackEndpoint(svc)),
ListPacks: authenticatedUser(jwtKey, svc, makeListPacksEndpoint(svc)),
CreatePack: authenticatedUser(jwtKey, svc, makeCreatePackEndpoint(svc)),
ModifyPack: authenticatedUser(jwtKey, svc, makeModifyPackEndpoint(svc)),
DeletePack: authenticatedUser(jwtKey, svc, makeDeletePackEndpoint(svc)),
ScheduleQueries: authenticatedUser(jwtKey, svc, makeScheduleQueriesEndpoint(svc)),
GetScheduledQueriesInPack: authenticatedUser(jwtKey, svc, makeGetScheduledQueriesInPackEndpoint(svc)),
GetScheduledQuery: authenticatedUser(jwtKey, svc, makeGetScheduledQueryEndpoint(svc)),
ModifyScheduledQuery: authenticatedUser(jwtKey, svc, makeModifyScheduledQueryEndpoint(svc)),
DeleteScheduledQuery: authenticatedUser(jwtKey, svc, makeDeleteScheduledQueryEndpoint(svc)),
GetHost: authenticatedUser(jwtKey, svc, makeGetHostEndpoint(svc)),
ListHosts: authenticatedUser(jwtKey, svc, makeListHostsEndpoint(svc)),
DeleteHost: authenticatedUser(jwtKey, svc, makeDeleteHostEndpoint(svc)),
GetLabel: authenticatedUser(jwtKey, svc, makeGetLabelEndpoint(svc)),
ListLabels: authenticatedUser(jwtKey, svc, makeListLabelsEndpoint(svc)),
CreateLabel: authenticatedUser(jwtKey, svc, makeCreateLabelEndpoint(svc)),
DeleteLabel: authenticatedUser(jwtKey, svc, makeDeleteLabelEndpoint(svc)),
AddLabelToPack: authenticatedUser(jwtKey, svc, makeAddLabelToPackEndpoint(svc)),
GetLabelsForPack: authenticatedUser(jwtKey, svc, makeGetLabelsForPackEndpoint(svc)),
DeleteLabelFromPack: authenticatedUser(jwtKey, svc, makeDeleteLabelFromPackEndpoint(svc)),
SearchTargets: authenticatedUser(jwtKey, svc, makeSearchTargetsEndpoint(svc)),
// Osquery endpoints
EnrollAgent: makeEnrollAgentEndpoint(svc),
@ -161,9 +165,11 @@ type kolideHandlers struct {
CreatePack *kithttp.Server
ModifyPack *kithttp.Server
DeletePack *kithttp.Server
AddQueryToPack *kithttp.Server
GetQueriesInPack *kithttp.Server
DeleteQueryFromPack *kithttp.Server
ScheduleQueries *kithttp.Server
GetScheduledQueriesInPack *kithttp.Server
GetScheduledQuery *kithttp.Server
ModifyScheduledQuery *kithttp.Server
DeleteScheduledQuery *kithttp.Server
EnrollAgent *kithttp.Server
GetClientConfig *kithttp.Server
GetDistributedQueries *kithttp.Server
@ -217,9 +223,11 @@ func makeKolideKitHandlers(ctx context.Context, e KolideEndpoints, opts []kithtt
CreatePack: newServer(e.CreatePack, decodeCreatePackRequest),
ModifyPack: newServer(e.ModifyPack, decodeModifyPackRequest),
DeletePack: newServer(e.DeletePack, decodeDeletePackRequest),
AddQueryToPack: newServer(e.AddQueryToPack, decodeAddQueryToPackRequest),
GetQueriesInPack: newServer(e.GetQueriesInPack, decodeGetQueriesInPackRequest),
DeleteQueryFromPack: newServer(e.DeleteQueryFromPack, decodeDeleteQueryFromPackRequest),
ScheduleQueries: newServer(e.ScheduleQueries, decodeScheduleQueriesRequest),
GetScheduledQueriesInPack: newServer(e.GetScheduledQueriesInPack, decodeGetScheduledQueriesInPackRequest),
GetScheduledQuery: newServer(e.GetScheduledQuery, decodeGetScheduledQueryRequest),
ModifyScheduledQuery: newServer(e.ModifyScheduledQuery, decodeModifyScheduledQueryRequest),
DeleteScheduledQuery: newServer(e.DeleteScheduledQuery, decodeDeleteScheduledQueryRequest),
EnrollAgent: newServer(e.EnrollAgent, decodeEnrollAgentRequest),
GetClientConfig: newServer(e.GetClientConfig, decodeGetClientConfigRequest),
GetDistributedQueries: newServer(e.GetDistributedQueries, decodeGetDistributedQueriesRequest),
@ -300,9 +308,11 @@ func attachKolideAPIRoutes(r *mux.Router, h kolideHandlers) {
r.Handle("/api/v1/kolide/packs", h.CreatePack).Methods("POST")
r.Handle("/api/v1/kolide/packs/{id}", h.ModifyPack).Methods("PATCH")
r.Handle("/api/v1/kolide/packs/{id}", h.DeletePack).Methods("DELETE")
r.Handle("/api/v1/kolide/packs/{pid}/queries/{qid}", h.AddQueryToPack).Methods("POST")
r.Handle("/api/v1/kolide/packs/{id}/queries", h.GetQueriesInPack).Methods("GET")
r.Handle("/api/v1/kolide/packs/{pid}/queries/{qid}", h.DeleteQueryFromPack).Methods("DELETE")
r.Handle("/api/v1/kolide/packs/{id}/scheduled", h.GetScheduledQueriesInPack).Methods("GET")
r.Handle("/api/v1/kolide/schedule", h.ScheduleQueries).Methods("POST")
r.Handle("/api/v1/kolide/schedule/{id}", h.GetScheduledQuery).Methods("GET")
r.Handle("/api/v1/kolide/schedule/{id}", h.ModifyScheduledQuery).Methods("PATCH")
r.Handle("/api/v1/kolide/schedule/{id}", h.DeleteScheduledQuery).Methods("DELETE")
r.Handle("/api/v1/kolide/labels/{id}", h.GetLabel).Methods("GET")
r.Handle("/api/v1/kolide/labels", h.ListLabels).Methods("GET")
r.Handle("/api/v1/kolide/labels", h.CreateLabel).Methods("POST")

View file

@ -133,16 +133,20 @@ func TestAPIRoutes(t *testing.T) {
uri: "/api/v1/kolide/packs/1",
},
{
verb: "POST",
uri: "/api/v1/kolide/packs/1/queries/2",
verb: "GET",
uri: "/api/v1/kolide/packs/1/scheduled",
},
{
verb: "GET",
uri: "/api/v1/kolide/packs/1/queries",
verb: "POST",
uri: "/api/v1/kolide/schedule",
},
{
verb: "DELETE",
uri: "/api/v1/kolide/packs/1/queries/2",
uri: "/api/v1/kolide/schedule/1",
},
{
verb: "PATCH",
uri: "/api/v1/kolide/schedule/1",
},
{
verb: "POST",

View file

@ -78,7 +78,7 @@ func (svc service) GetClientConfig(ctx context.Context) (*kolide.OsqueryConfig,
for _, pack := range packs {
// first, we must figure out what queries are in this pack
queries, err := svc.ds.ListQueriesInPack(pack)
queries, err := svc.ds.ListScheduledQueriesInPack(pack.ID, kolide.ListOptions{})
if err != nil {
return nil, osqueryError{message: "database error: " + err.Error()}
}

View file

@ -19,6 +19,7 @@ import (
"github.com/kolide/kolide-ose/server/datastore/inmem"
"github.com/kolide/kolide-ose/server/kolide"
"github.com/kolide/kolide-ose/server/pubsub"
"github.com/kolide/kolide-ose/server/test"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@ -414,10 +415,10 @@ func TestGetClientConfig(t *testing.T) {
// let's populate the database with some info
infoQuery := &kolide.Query{
Name: "Info",
Query: "select * from osquery_info;",
Interval: 60,
Name: "Info",
Query: "select * from osquery_info;",
}
infoQueryInterval := uint(60)
infoQuery, err = ds.NewQuery(infoQuery)
assert.Nil(t, err)
@ -427,8 +428,7 @@ func TestGetClientConfig(t *testing.T) {
_, err = ds.NewPack(monitoringPack)
assert.Nil(t, err)
err = ds.AddQueryToPack(infoQuery.ID, monitoringPack.ID)
assert.Nil(t, err)
test.NewScheduledQuery(t, ds, monitoringPack.ID, infoQuery.ID, infoQueryInterval, false, false)
mysqlLabel := &kolide.Label{
Name: "MySQL Monitoring",

View file

@ -81,42 +81,6 @@ func (svc service) DeletePack(ctx context.Context, id uint) error {
return svc.ds.DeletePack(id)
}
func (svc service) AddQueryToPack(ctx context.Context, qid, pid uint) error {
return svc.ds.AddQueryToPack(qid, pid)
}
func (svc service) ListQueriesInPack(ctx context.Context, id uint) ([]*kolide.Query, error) {
pack, err := svc.ds.Pack(id)
if err != nil {
return nil, err
}
queries, err := svc.ds.ListQueriesInPack(pack)
if err != nil {
return nil, err
}
return queries, nil
}
func (svc service) RemoveQueryFromPack(ctx context.Context, qid, pid uint) error {
pack, err := svc.ds.Pack(pid)
if err != nil {
return err
}
query, err := svc.ds.Query(qid)
if err != nil {
return err
}
err = svc.ds.RemoveQueryFromPack(query, pack)
if err != nil {
return err
}
return nil
}
func (svc service) AddLabelToPack(ctx context.Context, lid, pid uint) error {
return svc.ds.AddLabelToPack(lid, pid)
}

View file

@ -126,110 +126,3 @@ func TestDeletePack(t *testing.T) {
assert.Len(t, queries, 0)
}
func TestAddQueryToPack(t *testing.T) {
ds, err := inmem.New(config.TestConfig())
assert.Nil(t, err)
svc, err := newTestService(ds, nil)
assert.Nil(t, err)
ctx := context.Background()
pack := &kolide.Pack{
Name: "foo",
}
_, err = ds.NewPack(pack)
assert.Nil(t, err)
assert.NotZero(t, pack.ID)
query := &kolide.Query{
Name: "bar",
Query: "select * from time;",
}
query, err = ds.NewQuery(query)
assert.Nil(t, err)
assert.NotZero(t, query.ID)
queries, err := ds.ListQueriesInPack(pack)
assert.Nil(t, err)
assert.Len(t, queries, 0)
err = svc.AddQueryToPack(ctx, query.ID, pack.ID)
assert.Nil(t, err)
queries, err = ds.ListQueriesInPack(pack)
assert.Nil(t, err)
assert.Len(t, queries, 1)
}
func TestGetQueriesInPack(t *testing.T) {
ds, err := inmem.New(config.TestConfig())
assert.Nil(t, err)
svc, err := newTestService(ds, nil)
assert.Nil(t, err)
ctx := context.Background()
pack := &kolide.Pack{
Name: "foo",
}
_, err = ds.NewPack(pack)
assert.Nil(t, err)
assert.NotZero(t, pack.ID)
query := &kolide.Query{
Name: "bar",
Query: "select * from time;",
}
query, err = ds.NewQuery(query)
assert.Nil(t, err)
assert.NotZero(t, query.ID)
err = ds.AddQueryToPack(query.ID, pack.ID)
assert.Nil(t, err)
queries, err := svc.ListQueriesInPack(ctx, pack.ID)
assert.Nil(t, err)
assert.Len(t, queries, 1)
}
func TestRemoveQueryFromPack(t *testing.T) {
ds, err := inmem.New(config.TestConfig())
assert.Nil(t, err)
svc, err := newTestService(ds, nil)
assert.Nil(t, err)
ctx := context.Background()
pack := &kolide.Pack{
Name: "foo",
}
_, err = ds.NewPack(pack)
assert.Nil(t, err)
assert.NotZero(t, pack.ID)
query := &kolide.Query{
Name: "bar",
Query: "select * from time;",
}
query, err = ds.NewQuery(query)
assert.Nil(t, err)
assert.NotZero(t, query.ID)
err = ds.AddQueryToPack(query.ID, pack.ID)
assert.Nil(t, err)
queries, err := ds.ListQueriesInPack(pack)
assert.Nil(t, err)
assert.Len(t, queries, 1)
err = svc.RemoveQueryFromPack(ctx, query.ID, pack.ID)
assert.Nil(t, err)
queries, err = ds.ListQueriesInPack(pack)
assert.Nil(t, err)
assert.Len(t, queries, 0)
}

View file

@ -29,26 +29,6 @@ func (svc service) NewQuery(ctx context.Context, p kolide.QueryPayload) (*kolide
query.Query = *p.Query
}
if p.Interval != nil {
query.Interval = *p.Interval
}
if p.Snapshot != nil {
query.Snapshot = *p.Snapshot
}
if p.Differential != nil {
query.Differential = *p.Differential
}
if p.Platform != nil {
query.Platform = *p.Platform
}
if p.Version != nil {
query.Version = *p.Version
}
vc, ok := viewer.FromContext(ctx)
if ok {
query.AuthorID = vc.UserID()
@ -79,26 +59,6 @@ func (svc service) ModifyQuery(ctx context.Context, id uint, p kolide.QueryPaylo
query.Query = *p.Query
}
if p.Interval != nil {
query.Interval = *p.Interval
}
if p.Snapshot != nil {
query.Snapshot = *p.Snapshot
}
if p.Differential != nil {
query.Differential = *p.Differential
}
if p.Platform != nil {
query.Platform = *p.Platform
}
if p.Version != nil {
query.Version = *p.Version
}
err = svc.ds.SaveQuery(query)
if err != nil {
return nil, err

View file

@ -0,0 +1,26 @@
package service
import (
"github.com/kolide/kolide-ose/server/kolide"
"golang.org/x/net/context"
)
func (svc service) GetScheduledQuery(ctx context.Context, id uint) (*kolide.ScheduledQuery, error) {
return svc.ds.ScheduledQuery(id)
}
func (svc service) GetScheduledQueriesInPack(ctx context.Context, id uint, opts kolide.ListOptions) ([]*kolide.ScheduledQuery, error) {
return svc.ds.ListScheduledQueriesInPack(id, opts)
}
func (svc service) ScheduleQuery(ctx context.Context, sq *kolide.ScheduledQuery) (*kolide.ScheduledQuery, error) {
return svc.ds.NewScheduledQuery(sq)
}
func (svc service) ModifyScheduledQuery(ctx context.Context, sq *kolide.ScheduledQuery) (*kolide.ScheduledQuery, error) {
return svc.ds.SaveScheduledQuery(sq)
}
func (svc service) DeleteScheduledQuery(ctx context.Context, id uint) error {
return svc.ds.DeleteScheduledQuery(id)
}

View file

@ -0,0 +1,104 @@
package service
import (
"testing"
"github.com/kolide/kolide-ose/server/config"
"github.com/kolide/kolide-ose/server/datastore/inmem"
"github.com/kolide/kolide-ose/server/kolide"
"github.com/kolide/kolide-ose/server/test"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"golang.org/x/net/context"
)
func TestGetScheduledQueriesInPack(t *testing.T) {
ds, err := inmem.New(config.TestConfig())
assert.Nil(t, err)
svc, err := newTestService(ds, nil)
assert.Nil(t, err)
ctx := context.Background()
u1 := test.NewUser(t, ds, "Admin", "admin", "admin@kolide.co", true)
q1 := test.NewQuery(t, ds, "foo", "select * from time;", u1.ID, true)
q2 := test.NewQuery(t, ds, "bar", "select * from time;", u1.ID, true)
p1 := test.NewPack(t, ds, "baz")
sq1 := test.NewScheduledQuery(t, ds, p1.ID, q1.ID, 60, false, false)
queries, err := svc.GetScheduledQueriesInPack(ctx, p1.ID, kolide.ListOptions{})
require.Nil(t, err)
require.Len(t, queries, 1)
assert.Equal(t, sq1.ID, queries[0].ID)
test.NewScheduledQuery(t, ds, p1.ID, q2.ID, 60, false, false)
test.NewScheduledQuery(t, ds, p1.ID, q2.ID, 60, true, false)
queries, err = svc.GetScheduledQueriesInPack(ctx, p1.ID, kolide.ListOptions{})
require.Nil(t, err)
require.Len(t, queries, 3)
}
func TestGetScheduledQuery(t *testing.T) {
ds, err := inmem.New(config.TestConfig())
assert.Nil(t, err)
svc, err := newTestService(ds, nil)
assert.Nil(t, err)
ctx := context.Background()
u1 := test.NewUser(t, ds, "Admin", "admin", "admin@kolide.co", true)
q1 := test.NewQuery(t, ds, "foo", "select * from time;", u1.ID, true)
p1 := test.NewPack(t, ds, "baz")
sq1 := test.NewScheduledQuery(t, ds, p1.ID, q1.ID, 60, false, false)
query, err := svc.GetScheduledQuery(ctx, sq1.ID)
require.Nil(t, err)
assert.Equal(t, uint(60), query.Interval)
}
func TestModifyScheduledQuery(t *testing.T) {
ds, err := inmem.New(config.TestConfig())
assert.Nil(t, err)
svc, err := newTestService(ds, nil)
assert.Nil(t, err)
ctx := context.Background()
u1 := test.NewUser(t, ds, "Admin", "admin", "admin@kolide.co", true)
q1 := test.NewQuery(t, ds, "foo", "select * from time;", u1.ID, true)
p1 := test.NewPack(t, ds, "baz")
sq1 := test.NewScheduledQuery(t, ds, p1.ID, q1.ID, 60, false, false)
query, err := svc.GetScheduledQuery(ctx, sq1.ID)
require.Nil(t, err)
assert.Equal(t, uint(60), query.Interval)
query.Interval = uint(120)
query, err = svc.ModifyScheduledQuery(ctx, query)
assert.Equal(t, uint(120), query.Interval)
queryVerify, err := svc.GetScheduledQuery(ctx, sq1.ID)
require.Nil(t, err)
assert.Equal(t, uint(120), queryVerify.Interval)
}
func TestDeleteScheduledQuery(t *testing.T) {
ds, err := inmem.New(config.TestConfig())
assert.Nil(t, err)
svc, err := newTestService(ds, nil)
assert.Nil(t, err)
ctx := context.Background()
u1 := test.NewUser(t, ds, "Admin", "admin", "admin@kolide.co", true)
q1 := test.NewQuery(t, ds, "foo", "select * from time;", u1.ID, true)
p1 := test.NewPack(t, ds, "baz")
sq1 := test.NewScheduledQuery(t, ds, p1.ID, q1.ID, 60, false, false)
query, err := svc.GetScheduledQuery(ctx, sq1.ID)
require.Nil(t, err)
assert.Equal(t, uint(60), query.Interval)
err = svc.DeleteScheduledQuery(ctx, sq1.ID)
require.Nil(t, err)
_, err = svc.GetScheduledQuery(ctx, sq1.ID)
require.NotNil(t, err)
}

View file

@ -57,46 +57,6 @@ func decodeListPacksRequest(ctx context.Context, r *http.Request) (interface{},
return listPacksRequest{ListOptions: opt}, nil
}
func decodeAddQueryToPackRequest(ctx context.Context, r *http.Request) (interface{}, error) {
qid, err := idFromRequest(r, "qid")
if err != nil {
return nil, err
}
pid, err := idFromRequest(r, "pid")
if err != nil {
return nil, err
}
var req addQueryToPackRequest
req.PackID = pid
req.QueryID = qid
return req, nil
}
func decodeGetQueriesInPackRequest(ctx context.Context, r *http.Request) (interface{}, error) {
id, err := idFromRequest(r, "id")
if err != nil {
return nil, err
}
var req getQueriesInPackRequest
req.ID = id
return req, nil
}
func decodeDeleteQueryFromPackRequest(ctx context.Context, r *http.Request) (interface{}, error) {
qid, err := idFromRequest(r, "qid")
if err != nil {
return nil, err
}
pid, err := idFromRequest(r, "pid")
if err != nil {
return nil, err
}
var req deleteQueryFromPackRequest
req.PackID = pid
req.QueryID = qid
return req, nil
}
func decodeAddLabelToPackRequest(ctx context.Context, r *http.Request) (interface{}, error) {
lid, err := idFromRequest(r, "lid")
if err != nil {

View file

@ -89,53 +89,3 @@ func TestDecodeGetPackRequest(t *testing.T) {
httptest.NewRequest("GET", "/api/v1/kolide/packs/1", nil),
)
}
func TestDecodeAddQueryToPackRequest(t *testing.T) {
router := mux.NewRouter()
router.HandleFunc("/api/v1/kolide/packs/{pid}/queries/{qid}", func(writer http.ResponseWriter, request *http.Request) {
r, err := decodeAddQueryToPackRequest(context.Background(), request)
assert.Nil(t, err)
params := r.(addQueryToPackRequest)
assert.Equal(t, uint(1), params.PackID)
assert.Equal(t, uint(2), params.QueryID)
}).Methods("GET")
router.ServeHTTP(
httptest.NewRecorder(),
httptest.NewRequest("GET", "/api/v1/kolide/packs/1/queries/2", nil),
)
}
func TestDecodeGetQueriesInPackRequest(t *testing.T) {
router := mux.NewRouter()
router.HandleFunc("/api/v1/kolide/packs/{id}/queries", func(writer http.ResponseWriter, request *http.Request) {
r, err := decodeGetQueriesInPackRequest(context.Background(), request)
assert.Nil(t, err)
params := r.(getQueriesInPackRequest)
assert.Equal(t, uint(1), params.ID)
}).Methods("GET")
router.ServeHTTP(
httptest.NewRecorder(),
httptest.NewRequest("GET", "/api/v1/kolide/packs/1/queries", nil),
)
}
func TestDecodeDeleteQueryFromPackRequest(t *testing.T) {
router := mux.NewRouter()
router.HandleFunc("/api/v1/kolide/packs/{pid}/queries/{qid}", func(writer http.ResponseWriter, request *http.Request) {
r, err := decodeDeleteQueryFromPackRequest(context.Background(), request)
assert.Nil(t, err)
params := r.(deleteQueryFromPackRequest)
assert.Equal(t, uint(1), params.PackID)
assert.Equal(t, uint(2), params.QueryID)
}).Methods("DELETE")
router.ServeHTTP(
httptest.NewRecorder(),
httptest.NewRequest("DELETE", "/api/v1/kolide/packs/1/queries/2", nil),
)
}

View file

@ -0,0 +1,63 @@
package service
import (
"encoding/json"
"net/http"
"golang.org/x/net/context"
)
func decodeScheduleQueriesRequest(ctx context.Context, r *http.Request) (interface{}, error) {
var req scheduleQueriesRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
return nil, err
}
return req, nil
}
func decodeModifyScheduledQueryRequest(ctx context.Context, r *http.Request) (interface{}, error) {
id, err := idFromRequest(r, "id")
if err != nil {
return nil, err
}
var req modifyScheduledQueryRequest
if err := json.NewDecoder(r.Body).Decode(&req.payload); err != nil {
return nil, err
}
req.ID = id
return req, nil
}
func decodeDeleteScheduledQueryRequest(ctx context.Context, r *http.Request) (interface{}, error) {
id, err := idFromRequest(r, "id")
if err != nil {
return nil, err
}
var req deleteScheduledQueryRequest
req.ID = id
return req, nil
}
func decodeGetScheduledQueryRequest(ctx context.Context, r *http.Request) (interface{}, error) {
id, err := idFromRequest(r, "id")
if err != nil {
return nil, err
}
var req getScheduledQueryRequest
req.ID = id
return req, nil
}
func decodeGetScheduledQueriesInPackRequest(ctx context.Context, r *http.Request) (interface{}, error) {
id, err := idFromRequest(r, "id")
if err != nil {
return nil, err
}
var req getScheduledQueriesInPackRequest
req.ID = id
return req, nil
}

View file

@ -0,0 +1,156 @@
package service
import (
"bytes"
"net/http"
"net/http/httptest"
"testing"
"github.com/gorilla/mux"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"golang.org/x/net/context"
)
func TestDecodeScheduleQueriesRequest(t *testing.T) {
router := mux.NewRouter()
router.HandleFunc("/api/v1/kolide/schedule", func(writer http.ResponseWriter, request *http.Request) {
r, err := decodeScheduleQueriesRequest(context.Background(), request)
require.Nil(t, err)
params := r.(scheduleQueriesRequest)
require.Len(t, params.Options, 2)
accessed := struct {
Five bool
Six bool
}{}
for _, q := range params.Options {
switch q.PackID {
case uint(5):
accessed.Five = true
assert.Equal(t, uint(60), q.Interval)
assert.Equal(t, true, *q.Snapshot)
assert.Nil(t, q.Removed)
assert.Len(t, q.QueryIDs, 1)
assert.Equal(t, q.QueryIDs[0], uint(1))
case uint(6):
accessed.Six = true
assert.Equal(t, uint(120), q.Interval)
assert.Nil(t, q.Removed)
assert.Nil(t, q.Snapshot)
assert.Len(t, q.QueryIDs, 3)
default:
t.Errorf("Found an unexpected pack_id: %d", q.PackID)
}
}
if !accessed.Five {
t.Error("Create scheduled query for pack 5 not read")
}
if !accessed.Six {
t.Error("Create scheduled query for pack 6 not read")
}
}).Methods("POST")
var body bytes.Buffer
body.Write([]byte(`{
"options": [{
"pack_id": 5,
"interval": 60,
"snapshot": true,
"query_ids": [1]
},{
"pack_id": 6,
"interval": 120,
"query_ids": [1, 2, 3]
}]
}`))
router.ServeHTTP(
httptest.NewRecorder(),
httptest.NewRequest("POST", "/api/v1/kolide/schedule", &body),
)
}
func TestDecodeModifyScheduledQueryRequest(t *testing.T) {
router := mux.NewRouter()
router.HandleFunc("/api/v1/kolide/scheduled/{id}", func(writer http.ResponseWriter, request *http.Request) {
r, err := decodeModifyScheduledQueryRequest(context.Background(), request)
assert.Nil(t, err)
params := r.(modifyScheduledQueryRequest)
assert.Equal(t, uint(1), params.ID)
assert.Equal(t, uint(5), params.payload.PackID)
assert.Equal(t, uint(6), params.payload.QueryID)
assert.Equal(t, true, *params.payload.Removed)
assert.Equal(t, uint(60), params.payload.Interval)
assert.Equal(t, uint(1), *params.payload.Shard)
}).Methods("PATCH")
var body bytes.Buffer
body.Write([]byte(`{
"pack_id": 5,
"query_id": 6,
"removed": true,
"interval": 60,
"shard": 1
}`))
router.ServeHTTP(
httptest.NewRecorder(),
httptest.NewRequest("PATCH", "/api/v1/kolide/scheduled/1", &body),
)
}
func TestDecodeDeleteScheduledQueryRequest(t *testing.T) {
router := mux.NewRouter()
router.HandleFunc("/api/v1/kolide/scheduled/{id}", func(writer http.ResponseWriter, request *http.Request) {
r, err := decodeDeleteScheduledQueryRequest(context.Background(), request)
assert.Nil(t, err)
params := r.(deleteScheduledQueryRequest)
assert.Equal(t, uint(1), params.ID)
}).Methods("DELETE")
router.ServeHTTP(
httptest.NewRecorder(),
httptest.NewRequest("DELETE", "/api/v1/kolide/scheduled/1", nil),
)
}
func TestDecodeGetScheduledQueryRequest(t *testing.T) {
router := mux.NewRouter()
router.HandleFunc("/api/v1/kolide/scheduled/{id}", func(writer http.ResponseWriter, request *http.Request) {
r, err := decodeGetScheduledQueryRequest(context.Background(), request)
assert.Nil(t, err)
params := r.(getScheduledQueryRequest)
assert.Equal(t, uint(1), params.ID)
}).Methods("GET")
router.ServeHTTP(
httptest.NewRecorder(),
httptest.NewRequest("GET", "/api/v1/kolide/scheduled/1", nil),
)
}
func TestDecodeGetScheduledQueriesInPackRequest(t *testing.T) {
router := mux.NewRouter()
router.HandleFunc("/api/v1/kolide/packs/{id}/scheduled", func(writer http.ResponseWriter, request *http.Request) {
r, err := decodeGetScheduledQueriesInPackRequest(context.Background(), request)
assert.Nil(t, err)
params := r.(getScheduledQueriesInPackRequest)
assert.Equal(t, uint(1), params.ID)
}).Methods("GET")
router.ServeHTTP(
httptest.NewRecorder(),
httptest.NewRequest("GET", "/api/v1/kolide/packs/1/scheduled", nil),
)
}

View file

@ -1,4 +1,4 @@
package datastore
package test
import (
"testing"
@ -8,7 +8,7 @@ import (
"github.com/stretchr/testify/require"
)
func newQuery(t *testing.T, ds kolide.Datastore, name, q string, authorID uint, saved bool) *kolide.Query {
func NewQuery(t *testing.T, ds kolide.Datastore, name, q string, authorID uint, saved bool) *kolide.Query {
query, err := ds.NewQuery(&kolide.Query{
Name: name,
Query: q,
@ -24,7 +24,7 @@ func newQuery(t *testing.T, ds kolide.Datastore, name, q string, authorID uint,
return query
}
func newPack(t *testing.T, ds kolide.Datastore, name string) *kolide.Pack {
func NewPack(t *testing.T, ds kolide.Datastore, name string) *kolide.Pack {
pack, err := ds.NewPack(&kolide.Pack{
Name: name,
})
@ -37,12 +37,7 @@ func newPack(t *testing.T, ds kolide.Datastore, name string) *kolide.Pack {
return pack
}
func addQueryToPack(t *testing.T, ds kolide.Datastore, queryID, packID uint) {
err := ds.AddQueryToPack(queryID, packID)
require.Nil(t, err)
}
func newCampaign(t *testing.T, ds kolide.Datastore, queryID uint, status kolide.DistributedQueryStatus, now time.Time) *kolide.DistributedQueryCampaign {
func NewCampaign(t *testing.T, ds kolide.Datastore, queryID uint, status kolide.DistributedQueryStatus, now time.Time) *kolide.DistributedQueryCampaign {
campaign, err := ds.NewDistributedQueryCampaign(&kolide.DistributedQueryCampaign{
UpdateCreateTimestamps: kolide.UpdateCreateTimestamps{
CreateTimestamp: kolide.CreateTimestamp{
@ -61,7 +56,7 @@ func newCampaign(t *testing.T, ds kolide.Datastore, queryID uint, status kolide.
return campaign
}
func addHostToCampaign(t *testing.T, ds kolide.Datastore, campaignID, hostID uint) {
func AddHostToCampaign(t *testing.T, ds kolide.Datastore, campaignID, hostID uint) {
_, err := ds.NewDistributedQueryCampaignTarget(
&kolide.DistributedQueryCampaignTarget{
Type: kolide.TargetHost,
@ -71,7 +66,7 @@ func addHostToCampaign(t *testing.T, ds kolide.Datastore, campaignID, hostID uin
require.Nil(t, err)
}
func addLabelToCampaign(t *testing.T, ds kolide.Datastore, campaignID, labelID uint) {
func AddLabelToCampaign(t *testing.T, ds kolide.Datastore, campaignID, labelID uint) {
_, err := ds.NewDistributedQueryCampaignTarget(
&kolide.DistributedQueryCampaignTarget{
Type: kolide.TargetLabel,
@ -81,7 +76,7 @@ func addLabelToCampaign(t *testing.T, ds kolide.Datastore, campaignID, labelID u
require.Nil(t, err)
}
func newExecution(t *testing.T, ds kolide.Datastore, campaignID uint, hostID uint) *kolide.DistributedQueryExecution {
func NewExecution(t *testing.T, ds kolide.Datastore, campaignID uint, hostID uint) *kolide.DistributedQueryExecution {
execution, err := ds.NewDistributedQueryExecution(&kolide.DistributedQueryExecution{
HostID: hostID,
DistributedQueryCampaignID: campaignID,
@ -91,7 +86,7 @@ func newExecution(t *testing.T, ds kolide.Datastore, campaignID uint, hostID uin
return execution
}
func newHost(t *testing.T, ds kolide.Datastore, name, ip, key, uuid string, now time.Time) *kolide.Host {
func NewHost(t *testing.T, ds kolide.Datastore, name, ip, key, uuid string, now time.Time) *kolide.Host {
osqueryHostID, _ := kolide.RandomText(10)
h, err := ds.NewHost(&kolide.Host{
HostName: name,
@ -108,7 +103,7 @@ func newHost(t *testing.T, ds kolide.Datastore, name, ip, key, uuid string, now
return h
}
func newLabel(t *testing.T, ds kolide.Datastore, name, query string) *kolide.Label {
func NewLabel(t *testing.T, ds kolide.Datastore, name, query string) *kolide.Label {
l, err := ds.NewLabel(&kolide.Label{Name: name, Query: query})
require.Nil(t, err)
@ -117,7 +112,7 @@ func newLabel(t *testing.T, ds kolide.Datastore, name, query string) *kolide.Lab
return l
}
func newUser(t *testing.T, ds kolide.Datastore, name, username, email string, admin bool) *kolide.User {
func NewUser(t *testing.T, ds kolide.Datastore, name, username, email string, admin bool) *kolide.User {
u, err := ds.NewUser(&kolide.User{
Password: []byte("garbage"),
Salt: "garbage",
@ -132,3 +127,17 @@ func newUser(t *testing.T, ds kolide.Datastore, name, username, email string, ad
return u
}
func NewScheduledQuery(t *testing.T, ds kolide.Datastore, pid, qid, interval uint, snapshot, removed bool) *kolide.ScheduledQuery {
sq, err := ds.NewScheduledQuery(&kolide.ScheduledQuery{
PackID: pid,
QueryID: qid,
Interval: interval,
Snapshot: &snapshot,
Removed: &removed,
})
require.Nil(t, err)
require.NotZero(t, sq.ID)
return sq
}