From f109b14f9d8551d81ae3a612ccf7bb7563a4e567 Mon Sep 17 00:00:00 2001 From: Mike Arpaia Date: Tue, 13 Dec 2016 14:22:05 -0800 Subject: [PATCH] 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 --- server/datastore/datastore_campaigns_test.go | 51 ++--- server/datastore/datastore_hosts_test.go | 5 +- server/datastore/datastore_packs_test.go | 58 +---- server/datastore/datastore_queries_test.go | 41 ++-- .../datastore_scheduled_queries_test.go | 79 +++++++ server/datastore/datastore_test.go | 5 +- server/datastore/inmem/inmem.go | 29 ++- server/datastore/inmem/packs.go | 44 ---- server/datastore/inmem/queries.go | 6 +- server/datastore/inmem/scheduled_queries.go | 111 ++++++++++ ...1118212613_CreateTableScheduledQueries.go} | 12 +- .../20161118212758_CreateTableQueries.go | 5 - server/datastore/mysql/packs.go | 72 +------ server/datastore/mysql/queries.go | 31 ++- server/datastore/mysql/scheduled_queries.go | 93 ++++++++ server/kolide/datastore.go | 1 + server/kolide/osquery.go | 16 +- server/kolide/packs.go | 19 -- server/kolide/queries.go | 28 +-- server/kolide/scheduled_queries.go | 37 ++++ server/kolide/service.go | 1 + server/service/endpoint_packs.go | 87 +------- server/service/endpoint_scheduled_queries.go | 198 ++++++++++++++++++ server/service/handler.go | 86 ++++---- server/service/handler_test.go | 14 +- server/service/service_osquery.go | 2 +- server/service/service_osquery_test.go | 10 +- server/service/service_packs.go | 36 ---- server/service/service_packs_test.go | 107 ---------- server/service/service_queries.go | 40 ---- server/service/service_scheduled_queries.go | 26 +++ .../service/service_scheduled_queries_test.go | 104 +++++++++ server/service/transport_packs.go | 40 ---- server/service/transport_packs_test.go | 50 ----- server/service/transport_scheduled_queries.go | 63 ++++++ .../transport_scheduled_queries_test.go | 156 ++++++++++++++ .../test_util.go => test/new_objects.go} | 39 ++-- 37 files changed, 1084 insertions(+), 718 deletions(-) create mode 100644 server/datastore/datastore_scheduled_queries_test.go create mode 100644 server/datastore/inmem/scheduled_queries.go rename server/datastore/mysql/migrations/{20161118212613_CreateTablePackQueries.go => 20161118212613_CreateTableScheduledQueries.go} (58%) create mode 100644 server/datastore/mysql/scheduled_queries.go create mode 100644 server/kolide/scheduled_queries.go create mode 100644 server/service/endpoint_scheduled_queries.go create mode 100644 server/service/service_scheduled_queries.go create mode 100644 server/service/service_scheduled_queries_test.go create mode 100644 server/service/transport_scheduled_queries.go create mode 100644 server/service/transport_scheduled_queries_test.go rename server/{datastore/test_util.go => test/new_objects.go} (74%) diff --git a/server/datastore/datastore_campaigns_test.go b/server/datastore/datastore_campaigns_test.go index e607b67a31..be3f912047 100644 --- a/server/datastore/datastore_campaigns_test.go +++ b/server/datastore/datastore_campaigns_test.go @@ -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) diff --git a/server/datastore/datastore_hosts_test.go b/server/datastore/datastore_hosts_test.go index c32871806a..09f6e2f933 100644 --- a/server/datastore/datastore_hosts_test.go +++ b/server/datastore/datastore_hosts_test.go @@ -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", diff --git a/server/datastore/datastore_packs_test.go b/server/datastore/datastore_packs_test.go index 55e8d4fbf2..49b0d34039 100644 --- a/server/datastore/datastore_packs_test.go +++ b/server/datastore/datastore_packs_test.go @@ -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", diff --git a/server/datastore/datastore_queries_test.go b/server/datastore/datastore_queries_test.go index 8f997c8888..247c21c81b 100644 --- a/server/datastore/datastore_queries_test.go +++ b/server/datastore/datastore_queries_test.go @@ -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) diff --git a/server/datastore/datastore_scheduled_queries_test.go b/server/datastore/datastore_scheduled_queries_test.go new file mode 100644 index 0000000000..816ad6b5b2 --- /dev/null +++ b/server/datastore/datastore_scheduled_queries_test.go @@ -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) +} diff --git a/server/datastore/datastore_test.go b/server/datastore/datastore_test.go index 86d4da7451..731032afc2 100644 --- a/server/datastore/datastore_test.go +++ b/server/datastore/datastore_test.go @@ -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, } diff --git a/server/datastore/inmem/inmem.go b/server/datastore/inmem/inmem.go index d7fe9f62ac..a7b4d64ac0 100644 --- a/server/datastore/inmem/inmem.go +++ b/server/datastore/inmem/inmem.go @@ -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 } diff --git a/server/datastore/inmem/packs.go b/server/datastore/inmem/packs.go index 2bf334351e..6a0783ccd4 100644 --- a/server/datastore/inmem/packs.go +++ b/server/datastore/inmem/packs.go @@ -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, diff --git a/server/datastore/inmem/queries.go b/server/datastore/inmem/queries.go index 5740c7ddf2..2d87894f78 100644 --- a/server/datastore/inmem/queries.go +++ b/server/datastore/inmem/queries.go @@ -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]) } } } diff --git a/server/datastore/inmem/scheduled_queries.go b/server/datastore/inmem/scheduled_queries.go new file mode 100644 index 0000000000..c4c9da2a02 --- /dev/null +++ b/server/datastore/inmem/scheduled_queries.go @@ -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 +} diff --git a/server/datastore/mysql/migrations/20161118212613_CreateTablePackQueries.go b/server/datastore/mysql/migrations/20161118212613_CreateTableScheduledQueries.go similarity index 58% rename from server/datastore/mysql/migrations/20161118212613_CreateTablePackQueries.go rename to server/datastore/mysql/migrations/20161118212613_CreateTableScheduledQueries.go index e599a616c8..967a15673b 100644 --- a/server/datastore/mysql/migrations/20161118212613_CreateTablePackQueries.go +++ b/server/datastore/mysql/migrations/20161118212613_CreateTableScheduledQueries.go @@ -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 } diff --git a/server/datastore/mysql/migrations/20161118212758_CreateTableQueries.go b/server/datastore/mysql/migrations/20161118212758_CreateTableQueries.go index 486ccbefcf..a0932ad195 100644 --- a/server/datastore/mysql/migrations/20161118212758_CreateTableQueries.go +++ b/server/datastore/mysql/migrations/20161118212758_CreateTableQueries.go @@ -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" + diff --git a/server/datastore/mysql/packs.go b/server/datastore/mysql/packs.go index 4a783110de..4901d60998 100644 --- a/server/datastore/mysql/packs.go +++ b/server/datastore/mysql/packs.go @@ -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) diff --git a/server/datastore/mysql/queries.go b/server/datastore/mysql/queries.go index 434d75336b..411ed9446a 100644 --- a/server/datastore/mysql/queries.go +++ b/server/datastore/mysql/queries.go @@ -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 (?) ` diff --git a/server/datastore/mysql/scheduled_queries.go b/server/datastore/mysql/scheduled_queries.go new file mode 100644 index 0000000000..fbf340f3be --- /dev/null +++ b/server/datastore/mysql/scheduled_queries.go @@ -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 +} diff --git a/server/kolide/datastore.go b/server/kolide/datastore.go index bcbded8b30..2bc472b665 100644 --- a/server/kolide/datastore.go +++ b/server/kolide/datastore.go @@ -12,6 +12,7 @@ type Datastore interface { SessionStore AppConfigStore InviteStore + ScheduledQueryStore Name() string Drop() error Migrate() error diff --git a/server/kolide/osquery.go b/server/kolide/osquery.go index d63dba1722..743e8d435e 100644 --- a/server/kolide/osquery.go +++ b/server/kolide/osquery.go @@ -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 diff --git a/server/kolide/packs.go b/server/kolide/packs.go index 88dce9a65a..1ebf9b52bb 100644 --- a/server/kolide/packs.go +++ b/server/kolide/packs.go @@ -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 diff --git a/server/kolide/queries.go b/server/kolide/queries.go index 8a4b5afd55..d4622a47ac 100644 --- a/server/kolide/queries.go +++ b/server/kolide/queries.go @@ -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"` diff --git a/server/kolide/scheduled_queries.go b/server/kolide/scheduled_queries.go new file mode 100644 index 0000000000..9677f8d56e --- /dev/null +++ b/server/kolide/scheduled_queries.go @@ -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"` +} diff --git a/server/kolide/service.go b/server/kolide/service.go index 05d3784761..55abc6f320 100644 --- a/server/kolide/service.go +++ b/server/kolide/service.go @@ -13,4 +13,5 @@ type Service interface { AppConfigService InviteService TargetService + ScheduledQueryService } diff --git a/server/service/endpoint_packs.go b/server/service/endpoint_packs.go index f02bb950a2..96568fdab9 100644 --- a/server/service/endpoint_packs.go +++ b/server/service/endpoint_packs.go @@ -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 //////////////////////////////////////////////////////////////////////////////// diff --git a/server/service/endpoint_scheduled_queries.go b/server/service/endpoint_scheduled_queries.go new file mode 100644 index 0000000000..7435baab51 --- /dev/null +++ b/server/service/endpoint_scheduled_queries.go @@ -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 + } +} diff --git a/server/service/handler.go b/server/service/handler.go index bfac7ccdb7..78363bd7be 100644 --- a/server/service/handler.go +++ b/server/service/handler.go @@ -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") diff --git a/server/service/handler_test.go b/server/service/handler_test.go index 2716b36b48..f0dd9c4750 100644 --- a/server/service/handler_test.go +++ b/server/service/handler_test.go @@ -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", diff --git a/server/service/service_osquery.go b/server/service/service_osquery.go index 046e0b75a7..9ff248566d 100644 --- a/server/service/service_osquery.go +++ b/server/service/service_osquery.go @@ -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()} } diff --git a/server/service/service_osquery_test.go b/server/service/service_osquery_test.go index cb32c0e36e..1c7e00d7a6 100644 --- a/server/service/service_osquery_test.go +++ b/server/service/service_osquery_test.go @@ -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", diff --git a/server/service/service_packs.go b/server/service/service_packs.go index 958f7ea738..10aeb1d783 100644 --- a/server/service/service_packs.go +++ b/server/service/service_packs.go @@ -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) } diff --git a/server/service/service_packs_test.go b/server/service/service_packs_test.go index ae5c1f19cd..0c9b5724e2 100644 --- a/server/service/service_packs_test.go +++ b/server/service/service_packs_test.go @@ -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) -} diff --git a/server/service/service_queries.go b/server/service/service_queries.go index 2a481244b2..42935e82cf 100644 --- a/server/service/service_queries.go +++ b/server/service/service_queries.go @@ -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 diff --git a/server/service/service_scheduled_queries.go b/server/service/service_scheduled_queries.go new file mode 100644 index 0000000000..b5587b480d --- /dev/null +++ b/server/service/service_scheduled_queries.go @@ -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) +} diff --git a/server/service/service_scheduled_queries_test.go b/server/service/service_scheduled_queries_test.go new file mode 100644 index 0000000000..fca1688229 --- /dev/null +++ b/server/service/service_scheduled_queries_test.go @@ -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) +} diff --git a/server/service/transport_packs.go b/server/service/transport_packs.go index 6dd2545315..b9ef23b87a 100644 --- a/server/service/transport_packs.go +++ b/server/service/transport_packs.go @@ -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 { diff --git a/server/service/transport_packs_test.go b/server/service/transport_packs_test.go index 6dcbc9bee6..a00295a3df 100644 --- a/server/service/transport_packs_test.go +++ b/server/service/transport_packs_test.go @@ -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), - ) -} diff --git a/server/service/transport_scheduled_queries.go b/server/service/transport_scheduled_queries.go new file mode 100644 index 0000000000..71a6110be8 --- /dev/null +++ b/server/service/transport_scheduled_queries.go @@ -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 +} diff --git a/server/service/transport_scheduled_queries_test.go b/server/service/transport_scheduled_queries_test.go new file mode 100644 index 0000000000..0a17fdf59a --- /dev/null +++ b/server/service/transport_scheduled_queries_test.go @@ -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), + ) +} diff --git a/server/datastore/test_util.go b/server/test/new_objects.go similarity index 74% rename from server/datastore/test_util.go rename to server/test/new_objects.go index 820710f35f..92aacf3ccd 100644 --- a/server/datastore/test_util.go +++ b/server/test/new_objects.go @@ -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 +}