Update labels interfaces for fleetctl (#1686)

- Remove unnecessary labels code
- Remove unnecessary packs code
- Update tests as appropriate
This commit is contained in:
Zachary Wasserman 2018-01-10 11:38:20 -08:00 committed by GitHub
parent 26dc30bd25
commit bde7256a09
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
35 changed files with 824 additions and 1671 deletions

View file

@ -45,8 +45,18 @@ func testDistributedQueryCampaign(t *testing.T, ds kolide.Datastore) {
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 := test.NewLabel(t, ds, "label foo", "query foo")
l2 := test.NewLabel(t, ds, "label bar", "query foo")
l1 := kolide.LabelSpec{
ID: 1,
Name: "label foo",
Query: "query foo",
}
l2 := kolide.LabelSpec{
ID: 2,
Name: "label bar",
Query: "query bar",
}
err := ds.ApplyLabelSpecs([]*kolide.LabelSpec{&l1, &l2})
require.Nil(t, err)
checkTargets(t, ds, campaign.ID, []uint{}, []uint{})

View file

@ -411,10 +411,12 @@ func testDistributedQueriesForHost(t *testing.T, ds kolide.Datastore) {
assert.Empty(t, queries)
// Create a label
l1, err := ds.NewLabel(&kolide.Label{
l1 := kolide.LabelSpec{
ID: 1,
Name: "label foo",
Query: "query1",
})
}
err = ds.ApplyLabelSpecs([]*kolide.LabelSpec{&l1})
require.Nil(t, err)
// Add hosts to label

View file

@ -39,35 +39,34 @@ func testLabels(t *testing.T, db kolide.Datastore) {
assert.Nil(t, err)
assert.Empty(t, queries)
newLabels := []kolide.Label{
newLabels := []*kolide.LabelSpec{
// Note these are intentionally out of order
kolide.Label{
&kolide.LabelSpec{
ID: 1,
Name: "label3",
Query: "query3",
Platform: "darwin",
},
kolide.Label{
&kolide.LabelSpec{
ID: 2,
Name: "label1",
Query: "query1",
},
kolide.Label{
&kolide.LabelSpec{
ID: 3,
Name: "label2",
Query: "query2",
Platform: "darwin",
},
kolide.Label{
&kolide.LabelSpec{
ID: 4,
Name: "label4",
Query: "query4",
Platform: "darwin",
},
}
for _, label := range newLabels {
var newLabel *kolide.Label
newLabel, err = db.NewLabel(&label)
assert.Nil(t, err)
assert.NotZero(t, newLabel.ID)
}
err = db.ApplyLabelSpecs(newLabels)
require.Nil(t, err)
expectQueries := map[string]string{
"1": "query3",
@ -141,66 +140,87 @@ func testLabels(t *testing.T, db kolide.Datastore) {
}
func testManagingLabelsOnPacks(t *testing.T, ds kolide.Datastore) {
monitoringPack := &kolide.Pack{
Name: "monitoring",
pack := &kolide.PackSpec{
ID: 1,
Name: "pack1",
}
_, err := ds.NewPack(monitoringPack)
err := ds.ApplyPackSpecs([]*kolide.PackSpec{pack})
require.Nil(t, err)
mysqlLabel := &kolide.Label{
labels, err := ds.ListLabelsForPack(pack.ID)
require.Nil(t, err)
assert.Len(t, labels, 0)
mysqlLabel := &kolide.LabelSpec{
ID: 1,
Name: "MySQL Monitoring",
Query: "select pid from processes where name = 'mysqld';",
}
mysqlLabel, err = ds.NewLabel(mysqlLabel)
err = ds.ApplyLabelSpecs([]*kolide.LabelSpec{mysqlLabel})
require.Nil(t, err)
err = ds.AddLabelToPack(mysqlLabel.ID, monitoringPack.ID)
pack.Targets = kolide.PackSpecTargets{
Labels: []string{
mysqlLabel.Name,
},
}
err = ds.ApplyPackSpecs([]*kolide.PackSpec{pack})
require.Nil(t, err)
labels, err := ds.ListLabelsForPack(monitoringPack.ID)
labels, err = ds.ListLabelsForPack(pack.ID)
require.Nil(t, err)
if assert.Len(t, labels, 1) {
assert.Equal(t, "MySQL Monitoring", labels[0].Name)
}
osqueryLabel := &kolide.Label{
osqueryLabel := &kolide.LabelSpec{
ID: 2,
Name: "Osquery Monitoring",
Query: "select pid from processes where name = 'osqueryd';",
}
osqueryLabel, err = ds.NewLabel(osqueryLabel)
err = ds.ApplyLabelSpecs([]*kolide.LabelSpec{mysqlLabel, osqueryLabel})
require.Nil(t, err)
err = ds.AddLabelToPack(osqueryLabel.ID, monitoringPack.ID)
pack.Targets = kolide.PackSpecTargets{
Labels: []string{
mysqlLabel.Name,
osqueryLabel.Name,
},
}
err = ds.ApplyPackSpecs([]*kolide.PackSpec{pack})
require.Nil(t, err)
labels, err = ds.ListLabelsForPack(monitoringPack.ID)
labels, err = ds.ListLabelsForPack(pack.ID)
require.Nil(t, err)
assert.Len(t, labels, 2)
}
func testSearchLabels(t *testing.T, db kolide.Datastore) {
_, err := db.NewLabel(&kolide.Label{
Name: "foo",
})
specs := []*kolide.LabelSpec{
&kolide.LabelSpec{
ID: 1,
Name: "foo",
},
&kolide.LabelSpec{
ID: 2,
Name: "bar",
},
&kolide.LabelSpec{
ID: 3,
Name: "foo-bar",
},
&kolide.LabelSpec{
ID: 4,
Name: "All Hosts",
LabelType: kolide.LabelTypeBuiltIn,
},
}
err := db.ApplyLabelSpecs(specs)
require.Nil(t, err)
_, err = db.NewLabel(&kolide.Label{
Name: "bar",
})
all, err := db.Label(specs[3].ID)
require.Nil(t, err)
l3, err := db.NewLabel(&kolide.Label{
Name: "foo-bar",
})
require.Nil(t, err)
all, err := db.NewLabel(&kolide.Label{
Name: "All Hosts",
LabelType: kolide.LabelTypeBuiltIn,
})
require.Nil(t, err)
all, err = db.Label(all.ID)
l3, err := db.Label(specs[2].ID)
require.Nil(t, err)
// We once threw errors when the search query was empty. Verify that we
@ -230,15 +250,18 @@ func testSearchLabelsLimit(t *testing.T, db kolide.Datastore) {
t.Skip("inmem is being deprecated, test skipped")
}
_, err := db.NewLabel(&kolide.Label{
all := &kolide.LabelSpec{
Name: "All Hosts",
LabelType: kolide.LabelTypeBuiltIn,
})
}
err := db.ApplyLabelSpecs([]*kolide.LabelSpec{all})
require.Nil(t, err)
for i := 0; i < 15; i++ {
_, err := db.NewLabel(&kolide.Label{
Name: fmt.Sprintf("foo-%d", i),
})
l := &kolide.LabelSpec{
Name: fmt.Sprintf("foo%d", i),
}
err := db.ApplyLabelSpecs([]*kolide.LabelSpec{l})
require.Nil(t, err)
}
@ -278,12 +301,13 @@ func testListHostsInLabel(t *testing.T, db kolide.Datastore) {
})
require.Nil(t, err)
l1, err := db.NewLabel(&kolide.Label{
l1 := &kolide.LabelSpec{
ID: 1,
Name: "label foo",
Query: "query1",
})
}
err = db.ApplyLabelSpecs([]*kolide.LabelSpec{l1})
require.Nil(t, err)
require.NotZero(t, l1.ID)
{
@ -331,19 +355,18 @@ func testListUniqueHostsInLabels(t *testing.T, db kolide.Datastore) {
hosts = append(hosts, h)
}
l1, err := db.NewLabel(&kolide.Label{
l1 := kolide.LabelSpec{
ID: 1,
Name: "label foo",
Query: "query1",
})
require.Nil(t, err)
require.NotZero(t, l1.ID)
l2, err := db.NewLabel(&kolide.Label{
}
l2 := kolide.LabelSpec{
ID: 2,
Name: "label bar",
Query: "query2",
})
}
err := db.ApplyLabelSpecs([]*kolide.LabelSpec{&l1, &l2})
require.Nil(t, err)
require.NotZero(t, l2.ID)
for i := 0; i < 3; i++ {
err = db.RecordLabelQueryExecutions(hosts[i], map[uint]bool{l1.ID: true}, time.Now())
@ -365,63 +388,62 @@ func testListUniqueHostsInLabels(t *testing.T, db kolide.Datastore) {
}
func testSaveLabel(t *testing.T, db kolide.Datastore) {
func testChangeLabelDetails(t *testing.T, db kolide.Datastore) {
if db.Name() == "inmem" {
t.Skip("inmem is being deprecated")
}
label := &kolide.Label{
label := kolide.LabelSpec{
ID: 1,
Name: "my label",
Description: "a label",
Query: "select 1 from processes;",
Query: "select 1 from processes",
Platform: "darwin",
}
label, err := db.NewLabel(label)
err := db.ApplyLabelSpecs([]*kolide.LabelSpec{&label})
require.Nil(t, err)
label.Name = "changed name"
label.Description = "changed description"
_, err = db.SaveLabel(label)
err = db.ApplyLabelSpecs([]*kolide.LabelSpec{&label})
require.Nil(t, err)
saved, err := db.Label(label.ID)
require.Nil(t, err)
assert.Equal(t, label.Name, saved.Name)
assert.Equal(t, label.Description, saved.Description)
}
func testReplaceDeletedLabel(t *testing.T, db kolide.Datastore) {
if db.Name() == "inmem" {
t.Skip("inmem is being deprecated, test skipped")
func testApplyLabelSpecsRoundtrip(t *testing.T, ds kolide.Datastore) {
expectedSpecs := []*kolide.LabelSpec{
&kolide.LabelSpec{
Name: "foo",
Query: "select * from foo",
Description: "foo description",
Platform: "darwin",
},
&kolide.LabelSpec{
Name: "bar",
Query: "select * from bar",
},
&kolide.LabelSpec{
Name: "bing",
Query: "select * from bing",
},
&kolide.LabelSpec{
Name: "All Hosts",
Query: "SELECT 1",
LabelType: kolide.LabelTypeBuiltIn,
},
}
label := &kolide.Label{
Name: "my label",
Query: "select 1 from processes;",
}
saved, err := db.NewLabel(label)
err := ds.ApplyLabelSpecs(expectedSpecs)
require.Nil(t, err)
saved, err = db.Label(saved.ID)
specs, err := ds.GetLabelSpecs()
require.Nil(t, err)
assert.Equal(t, label.Name, saved.Name)
assert.Equal(t, label.Description, saved.Description)
assert.Equal(t, expectedSpecs, specs)
newLabel := &kolide.Label{
Name: "my label",
Query: " select * from time",
}
// Replace should fail when label already exists and isn't soft deleted
_, err = db.NewLabel(newLabel)
require.NotNil(t, err)
// Now delete label and replace should succeed
err = db.DeleteLabel(label.ID)
// Should be idempotent
err = ds.ApplyLabelSpecs(expectedSpecs)
require.Nil(t, err)
saved, err = db.NewLabel(newLabel)
specs, err = ds.GetLabelSpecs()
require.Nil(t, err)
saved, err = db.Label(saved.ID)
require.Nil(t, err)
assert.Equal(t, newLabel.Name, saved.Name)
assert.Equal(t, newLabel.Description, saved.Description)
assert.Equal(t, expectedSpecs, specs)
}

View file

@ -1,6 +1,7 @@
package datastore
import (
"fmt"
"testing"
"github.com/WatchBeam/clock"
@ -11,14 +12,10 @@ import (
)
func testDeletePack(t *testing.T, ds kolide.Datastore) {
pack := &kolide.Pack{
Name: "foo",
}
_, err := ds.NewPack(pack)
assert.Nil(t, err)
pack := test.NewPack(t, ds, "foo")
assert.NotEqual(t, uint(0), pack.ID)
pack, err = ds.Pack(pack.ID)
pack, err := ds.Pack(pack.ID)
require.Nil(t, err)
err = ds.DeletePack(pack.ID)
@ -30,11 +27,7 @@ func testDeletePack(t *testing.T, ds kolide.Datastore) {
}
func testGetPackByName(t *testing.T, ds kolide.Datastore) {
pack := &kolide.Pack{
Name: "foo",
}
_, err := ds.NewPack(pack)
assert.Nil(t, err)
pack := test.NewPack(t, ds, "foo")
assert.NotEqual(t, uint(0), pack.ID)
pack, ok, err := ds.PackByName(pack.Name)
@ -50,28 +43,64 @@ func testGetPackByName(t *testing.T, ds kolide.Datastore) {
}
func testGetHostsInPack(t *testing.T, ds kolide.Datastore) {
func testListPacks(t *testing.T, ds kolide.Datastore) {
p1 := &kolide.PackSpec{
ID: 1,
Name: "foo_pack",
}
p2 := &kolide.PackSpec{
ID: 2,
Name: "bar_pack",
}
err := ds.ApplyPackSpecs([]*kolide.PackSpec{p1})
require.Nil(t, err)
packs, err := ds.ListPacks(kolide.ListOptions{})
require.Nil(t, err)
assert.Len(t, packs, 1)
err = ds.ApplyPackSpecs([]*kolide.PackSpec{p1, p2})
require.Nil(t, err)
packs, err = ds.ListPacks(kolide.ListOptions{})
require.Nil(t, err)
assert.Len(t, packs, 2)
fmt.Println(packs[0], packs[1])
}
func testListHostsInPack(t *testing.T, ds kolide.Datastore) {
if ds.Name() == "inmem" {
t.Skip("inmem is deprecated")
}
mockClock := clock.NewMockClock()
p1, err := ds.NewPack(&kolide.Pack{
l1 := kolide.LabelSpec{
ID: 1,
Name: "foo",
})
}
err := ds.ApplyLabelSpecs([]*kolide.LabelSpec{&l1})
require.Nil(t, err)
l1, err := ds.NewLabel(&kolide.Label{
Name: "foo",
})
require.Nil(t, err)
err = ds.AddLabelToPack(l1.ID, p1.ID)
p1 := &kolide.PackSpec{
ID: 1,
Name: "foo_pack",
Targets: kolide.PackSpecTargets{
Labels: []string{
l1.Name,
},
},
}
err = ds.ApplyPackSpecs([]*kolide.PackSpec{p1})
require.Nil(t, err)
h1 := test.NewHost(t, ds, "h1.local", "10.10.10.1", "1", "1", mockClock.Now())
hostsInPack, err := ds.ListHostsInPack(p1.ID, kolide.ListOptions{})
require.Nil(t, err)
require.Len(t, hostsInPack, 0)
err = ds.RecordLabelQueryExecutions(
h1,
map[uint]bool{l1.ID: true},
@ -79,7 +108,7 @@ func testGetHostsInPack(t *testing.T, ds kolide.Datastore) {
)
require.Nil(t, err)
hostsInPack, err := ds.ListHostsInPack(p1.ID, kolide.ListOptions{})
hostsInPack, err = ds.ListHostsInPack(p1.ID, kolide.ListOptions{})
require.Nil(t, err)
require.Len(t, hostsInPack, 1)
@ -99,38 +128,29 @@ func testGetHostsInPack(t *testing.T, ds kolide.Datastore) {
hostsInPack, err = ds.ListHostsInPack(p1.ID, kolide.ListOptions{})
require.Nil(t, err)
require.Len(t, hostsInPack, 2)
h3 := test.NewHost(t, ds, "h3.local", "10.10.10.3", "3", "3", mockClock.Now())
err = ds.AddHostToPack(h3.ID, p1.ID)
require.Nil(t, err)
hostsInPack, err = ds.ListHostsInPack(p1.ID, kolide.ListOptions{})
require.Nil(t, err)
require.Len(t, hostsInPack, 3)
explicitHostsInPack, err = ds.ListExplicitHostsInPack(p1.ID, kolide.ListOptions{})
require.Nil(t, err)
require.Len(t, explicitHostsInPack, 1)
}
func testAddLabelToPackTwice(t *testing.T, ds kolide.Datastore) {
l1 := test.NewLabel(t, ds, "l1", "select 1;")
p1 := test.NewPack(t, ds, "p1")
l1 := kolide.LabelSpec{
ID: 1,
Name: "l1",
Query: "select 1",
}
err := ds.ApplyLabelSpecs([]*kolide.LabelSpec{&l1})
require.Nil(t, err)
err := ds.AddLabelToPack(l1.ID, p1.ID)
assert.Nil(t, err)
labels, err := ds.ListLabelsForPack(p1.ID)
assert.Nil(t, err)
assert.Len(t, labels, 1)
err = ds.AddLabelToPack(l1.ID, p1.ID)
assert.Nil(t, err)
labels, err = ds.ListLabelsForPack(p1.ID)
assert.Nil(t, err)
assert.Len(t, labels, 1)
p1 := &kolide.PackSpec{
ID: 1,
Name: "pack1",
Targets: kolide.PackSpecTargets{
Labels: []string{
l1.Name,
l1.Name,
},
},
}
err = ds.ApplyPackSpecs([]*kolide.PackSpec{p1})
require.NotNil(t, err)
}
func testApplyPackSpecRoundtrip(t *testing.T, ds kolide.Datastore) {
@ -143,9 +163,22 @@ func testApplyPackSpecRoundtrip(t *testing.T, ds kolide.Datastore) {
err := ds.ApplyQueries(zwass.ID, queries)
require.Nil(t, err)
test.NewLabel(t, ds, "foo", "select * from foo")
test.NewLabel(t, ds, "bar", "select * from bar")
test.NewLabel(t, ds, "bing", "select * from bing")
labels := []*kolide.LabelSpec{
&kolide.LabelSpec{
Name: "foo",
Query: "select * from foo",
},
&kolide.LabelSpec{
Name: "bar",
Query: "select * from bar",
},
&kolide.LabelSpec{
Name: "bing",
Query: "select * from bing",
},
}
err = ds.ApplyLabelSpecs(labels)
require.Nil(t, err)
boolPtr := func(b bool) *bool { return &b }
uintPtr := func(x uint) *uint { return &x }
@ -196,7 +229,6 @@ func testApplyPackSpecRoundtrip(t *testing.T, ds kolide.Datastore) {
func testApplyPackSpecMissingQueries(t *testing.T, ds kolide.Datastore) {
// Do not define queries mentioned in spec
specs := []*kolide.PackSpec{
&kolide.PackSpec{
ID: 1,
@ -219,3 +251,172 @@ func testApplyPackSpecMissingQueries(t *testing.T, ds kolide.Datastore) {
assert.Contains(t, err.Error(), "unknown query 'bar'")
}
}
func testListLabelsForPack(t *testing.T, ds kolide.Datastore) {
labelSpecs := []*kolide.LabelSpec{
&kolide.LabelSpec{
Name: "foo",
Query: "select * from foo",
},
&kolide.LabelSpec{
Name: "bar",
Query: "select * from bar",
},
&kolide.LabelSpec{
Name: "bing",
Query: "select * from bing",
},
}
err := ds.ApplyLabelSpecs(labelSpecs)
require.Nil(t, err)
specs := []*kolide.PackSpec{
&kolide.PackSpec{
ID: 1,
Name: "test_pack",
Targets: kolide.PackSpecTargets{
Labels: []string{
"foo",
"bar",
"bing",
},
},
},
&kolide.PackSpec{
ID: 2,
Name: "test 2",
Targets: kolide.PackSpecTargets{
Labels: []string{
"bing",
},
},
},
&kolide.PackSpec{
ID: 3,
Name: "test 3",
},
}
err = ds.ApplyPackSpecs(specs)
require.Nil(t, err)
labels, err := ds.ListLabelsForPack(specs[0].ID)
require.Nil(t, err)
assert.Len(t, labels, 3)
labels, err = ds.ListLabelsForPack(specs[1].ID)
require.Nil(t, err)
assert.Len(t, labels, 1)
assert.Equal(t, "bing", labels[0].Name)
labels, err = ds.ListLabelsForPack(specs[2].ID)
require.Nil(t, err)
assert.Len(t, labels, 0)
}
func testListPacksForHost(t *testing.T, ds kolide.Datastore) {
if ds.Name() == "inmem" {
t.Skip("inmem is deprecated")
}
mockClock := clock.NewMockClock()
l1 := &kolide.LabelSpec{
ID: 1,
Name: "foo",
}
l2 := &kolide.LabelSpec{
ID: 2,
Name: "bar",
}
err := ds.ApplyLabelSpecs([]*kolide.LabelSpec{l1, l2})
require.Nil(t, err)
p1 := &kolide.PackSpec{
ID: 1,
Name: "foo_pack",
Targets: kolide.PackSpecTargets{
Labels: []string{
l1.Name,
l2.Name,
},
},
}
p2 := &kolide.PackSpec{
ID: 2,
Name: "shmoo_pack",
Targets: kolide.PackSpecTargets{
Labels: []string{
l2.Name,
},
},
}
err = ds.ApplyPackSpecs([]*kolide.PackSpec{p1, p2})
require.Nil(t, err)
h1 := test.NewHost(t, ds, "h1.local", "10.10.10.1", "1", "1", mockClock.Now())
packs, err := ds.ListPacksForHost(h1.ID)
require.Nil(t, err)
require.Len(t, packs, 0)
err = ds.RecordLabelQueryExecutions(
h1,
map[uint]bool{l1.ID: true},
mockClock.Now(),
)
require.Nil(t, err)
packs, err = ds.ListPacksForHost(h1.ID)
require.Nil(t, err)
if assert.Len(t, packs, 1) {
assert.Equal(t, "foo_pack", packs[0].Name)
}
err = ds.RecordLabelQueryExecutions(
h1,
map[uint]bool{l1.ID: false, l2.ID: true},
mockClock.Now(),
)
require.Nil(t, err)
packs, err = ds.ListPacksForHost(h1.ID)
require.Nil(t, err)
assert.Len(t, packs, 2)
err = ds.RecordLabelQueryExecutions(
h1,
map[uint]bool{l1.ID: true, l2.ID: true},
mockClock.Now(),
)
require.Nil(t, err)
packs, err = ds.ListPacksForHost(h1.ID)
require.Nil(t, err)
assert.Len(t, packs, 2)
h2 := test.NewHost(t, ds, "h2.local", "10.10.10.2", "2", "2", mockClock.Now())
err = ds.RecordLabelQueryExecutions(
h2,
map[uint]bool{l2.ID: true},
mockClock.Now(),
)
require.Nil(t, err)
packs, err = ds.ListPacksForHost(h1.ID)
require.Nil(t, err)
assert.Len(t, packs, 2)
err = ds.RecordLabelQueryExecutions(
h1,
map[uint]bool{l2.ID: false},
mockClock.Now(),
)
require.Nil(t, err)
packs, err = ds.ListPacksForHost(h1.ID)
require.Nil(t, err)
if assert.Len(t, packs, 1) {
assert.Equal(t, "foo_pack", packs[0].Name)
}
}

View file

@ -43,19 +43,18 @@ func testCountHostsInTargets(t *testing.T, ds kolide.Datastore) {
const thirtyDaysAndAMinuteAgo = -1 * (30*24*60 + 1)
h6 := initHost(mockClock.Now().Add(thirtyDaysAndAMinuteAgo*time.Minute), 3600, 3600)
l1, err := ds.NewLabel(&kolide.Label{
l1 := kolide.LabelSpec{
ID: 1,
Name: "label foo",
Query: "query foo",
})
require.Nil(t, err)
require.NotZero(t, l1.ID)
l2, err := ds.NewLabel(&kolide.Label{
}
l2 := kolide.LabelSpec{
ID: 2,
Name: "label bar",
Query: "query foo",
})
Query: "query bar",
}
err := ds.ApplyLabelSpecs([]*kolide.LabelSpec{&l1, &l2})
require.Nil(t, err)
require.NotZero(t, l2.ID)
for _, h := range []*kolide.Host{h1, h2, h3, h6} {
err = ds.RecordLabelQueryExecutions(h, map[uint]bool{l1.ID: true}, mockClock.Now())

View file

@ -47,7 +47,9 @@ var testFunctions = [...]func(*testing.T, kolide.Datastore){
testSaveHosts,
testDeleteHost,
testListHost,
testGetHostsInPack,
testListHostsInPack,
testListPacksForHost,
testListPacks,
testDistributedQueryCampaign,
testCleanupDistributedQueryCampaigns,
testBuiltInLabels,
@ -66,9 +68,8 @@ var testFunctions = [...]func(*testing.T, kolide.Datastore){
testDuplicateNewQuery,
testIdempotentDeleteHost,
testChangeEmail,
testSaveLabel,
testChangeLabelDetails,
testFlappingNetworkInterfaces,
testReplaceDeletedLabel,
testMigrationStatus,
testUnicode,
testCountHostsInTargets,
@ -80,4 +81,6 @@ var testFunctions = [...]func(*testing.T, kolide.Datastore){
testApplyQueries,
testApplyPackSpecRoundtrip,
testApplyPackSpecMissingQueries,
testApplyLabelSpecsRoundtrip,
testListLabelsForPack,
}

View file

@ -5,6 +5,7 @@ import (
"time"
"github.com/kolide/fleet/server/kolide"
"github.com/kolide/fleet/server/test"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@ -14,10 +15,15 @@ func testUnicode(t *testing.T, ds kolide.Datastore) {
t.Skip("inmem is being deprecated, test skipped")
}
label, err := ds.NewLabel(&kolide.Label{Name: "測試"})
l1 := kolide.LabelSpec{
ID: 1,
Name: "測試",
Query: "query foo",
}
err := ds.ApplyLabelSpecs([]*kolide.LabelSpec{&l1})
require.Nil(t, err)
label, err = ds.Label(label.ID)
label, err := ds.Label(l1.ID)
require.Nil(t, err)
assert.Equal(t, "測試", label.Name)
@ -35,10 +41,10 @@ func testUnicode(t *testing.T, ds kolide.Datastore) {
require.Nil(t, err)
user, err = ds.User(user.Username)
require.Nil(t, err)
assert.Equal(t, "🍱", user.Username)
pack, err := ds.NewPack(&kolide.Pack{Name: "👨🏾‍🚒"})
require.Nil(t, err)
pack := test.NewPack(t, ds, "👨🏾‍🚒")
pack, err = ds.Pack(pack.ID)
assert.Equal(t, "👨🏾‍🚒", pack.Name)

View file

@ -47,6 +47,7 @@ type Datastore struct {
kolide.QueryStore
kolide.PackStore
kolide.ScheduledQueryStore
kolide.LabelStore
}
func New(config config.KolideConfig) (*Datastore, error) {
@ -138,7 +139,7 @@ func (d *Datastore) MigrateData() error {
SMTPVerifySSLCerts: true,
}
return d.createBuiltinLabels()
return nil
}
func (m *Datastore) MigrationStatus() (kolide.MigrationStatus, error) {
@ -162,10 +163,6 @@ func (d *Datastore) Initialize() error {
return err
}
if err := d.createDevLabels(); err != nil {
return err
}
if err := d.createDevOrgInfo(); err != nil {
return err
}
@ -252,18 +249,6 @@ func (d *Datastore) createDevPacksAndQueries() error {
return err
}
func (d *Datastore) createBuiltinLabels() error {
for _, label := range appstate.Labels2() {
label := label
_, err := d.NewLabel(&label)
if err != nil {
return err
}
}
return nil
}
// Bootstrap a few users when using the in-memory database.
// Each user's default password will just be their username.
func (d *Datastore) createDevUsers() error {
@ -465,43 +450,3 @@ func (d *Datastore) createDevOrgInfo() error {
_, err := d.NewAppConfig(devOrgInfo)
return err
}
func (d *Datastore) createDevLabels() error {
labels := []kolide.Label{
{
UpdateCreateTimestamps: kolide.UpdateCreateTimestamps{
CreateTimestamp: kolide.CreateTimestamp{
CreatedAt: time.Date(2016, time.October, 27, 8, 31, 16, 0, time.UTC),
},
UpdateTimestamp: kolide.UpdateTimestamp{
UpdatedAt: time.Date(2016, time.October, 27, 8, 31, 16, 0, time.UTC),
},
},
Name: "dev_label_apache",
Query: "select * from processes where name like '%Apache%'",
},
{
UpdateCreateTimestamps: kolide.UpdateCreateTimestamps{
CreateTimestamp: kolide.CreateTimestamp{
CreatedAt: time.Now().Add(-1 * time.Hour),
},
UpdateTimestamp: kolide.UpdateTimestamp{
UpdatedAt: time.Now(),
},
},
Name: "dev_label_darwin",
Query: "select * from osquery_info where platform='darwin'",
},
}
for _, label := range labels {
label := label
_, err := d.NewLabel(&label)
if err != nil {
return err
}
}
return nil
}

View file

@ -2,6 +2,7 @@ package mysql
import (
"database/sql"
"fmt"
"time"
"github.com/jmoiron/sqlx"
@ -9,48 +10,66 @@ import (
"github.com/pkg/errors"
)
// NewLabel creates a new kolide.Label
func (d *Datastore) NewLabel(label *kolide.Label, opts ...kolide.OptionalArg) (*kolide.Label, error) {
db := d.getTransaction(opts)
var (
deletedLabel kolide.Label
query string
)
err := db.Get(&deletedLabel,
"SELECT * FROM labels WHERE name = ? AND deleted", label.Name)
switch err {
case nil:
query = `
REPLACE INTO labels (
name,
description,
query,
platform,
label_type
) VALUES ( ?, ?, ?, ?, ?)
`
case sql.ErrNoRows:
query = `
func (d *Datastore) ApplyLabelSpecs(specs []*kolide.LabelSpec) (err error) {
tx, err := d.db.Beginx()
if err != nil {
return errors.Wrap(err, "begin ApplyLabelSpecs transaction")
}
defer func() {
if err != nil {
rbErr := tx.Rollback()
// It seems possible that there might be a case in
// which the error we are dealing with here was thrown
// by the call to tx.Commit(), and the docs suggest
// this call would then result in sql.ErrTxDone.
if rbErr != nil && rbErr != sql.ErrTxDone {
panic(fmt.Sprintf("got err '%s' rolling back after err '%s'", rbErr, err))
}
}
}()
sql := `
INSERT INTO labels (
name,
description,
query,
platform,
label_type
) VALUES ( ?, ?, ?, ?, ?)
) VALUES ( ?, ?, ?, ?, ? )
ON DUPLICATE KEY UPDATE
name = VALUES(name),
description = VALUES(description),
query = VALUES(query),
platform = VALUES(platform),
label_type = VALUES(label_type),
deleted = false
`
default:
return nil, errors.Wrap(err, "check for existing label")
}
result, err := db.Exec(query, label.Name, label.Description, label.Query, label.Platform, label.LabelType)
stmt, err := tx.Prepare(sql)
if err != nil {
return nil, errors.Wrap(err, "inserting label")
return errors.Wrap(err, "prepare ApplyLabelSpecs insert")
}
id, _ := result.LastInsertId()
label.ID = uint(id)
return label, nil
for _, s := range specs {
_, err := stmt.Exec(s.Name, s.Description, s.Query, s.Platform, s.LabelType)
if err != nil {
return errors.Wrap(err, "exec ApplyLabelSpecs insert")
}
}
err = tx.Commit()
return errors.Wrap(err, "commit ApplyLabelSpecs transaction")
}
func (d *Datastore) GetLabelSpecs() ([]*kolide.LabelSpec, error) {
var specs []*kolide.LabelSpec
// Get basic specs
query := "SELECT name, description, query, platform, label_type FROM labels"
if err := d.db.Select(&specs, query); err != nil {
return nil, errors.Wrap(err, "get labels")
}
return specs, nil
}
// DeleteLabel soft deletes a kolide.Label
@ -378,17 +397,3 @@ func (d *Datastore) SearchLabels(query string, omit ...uint) ([]kolide.Label, er
return matches, nil
}
func (d *Datastore) SaveLabel(label *kolide.Label) (*kolide.Label, error) {
query := `
UPDATE labels SET
name = ?,
description = ?
WHERE id = ?
`
_, err := d.db.Exec(query, label.Name, label.Description, label.ID)
if err != nil {
return nil, errors.Wrap(err, "saving label")
}
return label, nil
}

View file

@ -135,7 +135,6 @@ func (d *Datastore) GetPackSpecs() (specs []*kolide.PackSpec, err error) {
// Get basic specs
query := "SELECT id, name, description, platform FROM packs"
if err := tx.Select(&specs, query); err != nil {
fmt.Println(err)
return nil, errors.Wrap(err, "get packs")
}
@ -151,17 +150,6 @@ WHERE pack_id = ? AND pt.type = ? AND pt.target_id = l.id
}
}
// query = `
// INSERT INTO scheduled_queries (
// pack_id, query_name, name, description, ` + "`interval`" + `,
// snapshot, removed, shard, platform, version
// )
// VALUES (
// ?, ?, ?, ?, ?,
// ?, ?, ?, ?, ?
// )
// `
// Load queries
for _, spec := range specs {
query = `
@ -203,67 +191,6 @@ func (d *Datastore) PackByName(name string, opts ...kolide.OptionalArg) (*kolide
return &pack, true, nil
}
// NewPack creates a new Pack
func (d *Datastore) NewPack(pack *kolide.Pack, opts ...kolide.OptionalArg) (*kolide.Pack, error) {
db := d.getTransaction(opts)
var (
deletedPack kolide.Pack
query string
)
err := db.Get(&deletedPack,
"SELECT * FROM packs WHERE name = ? AND deleted", pack.Name)
switch err {
case nil:
query = `
REPLACE INTO packs
( name, description, platform, disabled, deleted)
VALUES ( ?, ?, ?, ?, ?)
`
case sql.ErrNoRows:
query = `
INSERT INTO packs
( name, description, platform, disabled, deleted)
VALUES ( ?, ?, ?, ?, ?)
`
default:
return nil, errors.Wrap(err, "check for existing pack")
}
deleted := false
result, err := db.Exec(query, pack.Name, pack.Description, pack.Platform, pack.Disabled, deleted)
if err != nil && isDuplicate(err) {
return nil, alreadyExists("Pack", deletedPack.ID)
} else if err != nil {
return nil, errors.Wrap(err, "creating new pack")
}
id, _ := result.LastInsertId()
pack.ID = uint(id)
return pack, nil
}
// SavePack stores changes to pack
func (d *Datastore) SavePack(pack *kolide.Pack) error {
query := `
UPDATE packs
SET name = ?, platform = ?, disabled = ?, description = ?
WHERE id = ? AND NOT deleted
`
results, err := d.db.Exec(query, pack.Name, pack.Platform, pack.Disabled, pack.Description, pack.ID)
if err != nil {
return errors.Wrap(err, "updating pack")
}
rowsAffected, err := results.RowsAffected()
if err != nil {
return errors.Wrap(err, "rows affected updating packs")
}
if rowsAffected == 0 {
return notFound("Pack").WithID(pack.ID)
}
return nil
}
// DeletePack soft deletes a kolide.Pack so that it won't show up in results
func (d *Datastore) DeletePack(pid uint) error {
return d.deleteEntity("packs", pid)
@ -294,38 +221,6 @@ func (d *Datastore) ListPacks(opt kolide.ListOptions) ([]*kolide.Pack, error) {
return packs, nil
}
// AddLabelToPack associates a kolide.Label with a kolide.Pack
func (d *Datastore) AddLabelToPack(lid uint, pid uint, opts ...kolide.OptionalArg) error {
db := d.getTransaction(opts)
query := `
INSERT INTO pack_targets ( pack_id, type, target_id )
VALUES ( ?, ?, ? )
ON DUPLICATE KEY UPDATE id=id
`
_, err := db.Exec(query, pid, kolide.TargetLabel, lid)
if err != nil {
return errors.Wrap(err, "adding label to pack")
}
return nil
}
// AddHostToPack associates a kolide.Host with a kolide.Pack
func (d *Datastore) AddHostToPack(hid, pid uint) error {
query := `
INSERT INTO pack_targets ( pack_id, type, target_id )
VALUES ( ?, ?, ? )
ON DUPLICATE KEY UPDATE id=id
`
_, err := d.db.Exec(query, pid, kolide.TargetHost, hid)
if err != nil {
return errors.Wrap(err, "adding host to pack")
}
return nil
}
// ListLabelsForPack will return a list of kolide.Label records associated with kolide.Pack
func (d *Datastore) ListLabelsForPack(pid uint) ([]*kolide.Label, error) {
query := `
@ -356,39 +251,26 @@ func (d *Datastore) ListLabelsForPack(pid uint) ([]*kolide.Label, error) {
return labels, nil
}
// RemoreLabelFromPack will remove the association between a kolide.Label and
// a kolide.Pack
func (d *Datastore) RemoveLabelFromPack(lid, pid uint) error {
func (d *Datastore) ListPacksForHost(hid uint) ([]*kolide.Pack, error) {
query := `
DELETE FROM pack_targets
WHERE target_id = ? AND pack_id = ? AND type = ?
SELECT DISTINCT p.*
FROM packs p
JOIN pack_targets pt
JOIN label_query_executions lqe
ON (
p.id = pt.pack_id
AND pt.target_id = lqe.label_id
AND pt.type = ?
AND lqe.matches
)
WHERE lqe.host_id = ? AND NOT p.disabled
`
_, err := d.db.Exec(query, lid, pid, kolide.TargetLabel)
if err == sql.ErrNoRows {
return notFound("PackTarget").WithMessage(fmt.Sprintf("label ID: %d, pack ID: %d", lid, pid))
} else if err != nil {
return errors.Wrap(err, "removing label from pack")
packs := []*kolide.Pack{}
if err := d.db.Select(&packs, query, kolide.TargetLabel, hid); err != nil && err != sql.ErrNoRows {
return nil, errors.Wrap(err, "listing hosts in pack")
}
return nil
}
// RemoveHostFromPack will remove the association between a kolide.Host and a
// kolide.Pack
func (d *Datastore) RemoveHostFromPack(hid, pid uint) error {
query := `
DELETE FROM pack_targets
WHERE target_id = ? AND pack_id = ? AND type = ?
`
_, err := d.db.Exec(query, hid, pid, kolide.TargetHost)
if err == sql.ErrNoRows {
return notFound("PackTarget").WithMessage(fmt.Sprintf("host ID: %d, pack ID: %d", hid, pid))
} else if err != nil {
return errors.Wrap(err, "removing host from pack")
}
return nil
return packs, nil
}
func (d *Datastore) ListHostsInPack(pid uint, opt kolide.ListOptions) ([]uint, error) {

View file

@ -8,9 +8,19 @@ import (
func (d *Datastore) ListScheduledQueriesInPack(id uint, opts kolide.ListOptions) ([]*kolide.ScheduledQuery, error) {
query := `
SELECT
sq.id, sq.pack_id, sq.name, sq.query_name, q.query,
sq.description, sq.interval, sq.snapshot, sq.removed, sq.platform,
sq.version, sq.shard
sq.id,
sq.pack_id,
COALESCE(sq.name, q.name) AS name,
sq.query_name,
COALESCE(sq.description, '') AS description,
sq.interval,
sq.snapshot,
sq.removed,
COALESCE(sq.platform, '') AS platform,
sq.version,
sq.shard,
q.query,
q.id AS query_id
FROM scheduled_queries sq
JOIN queries q
ON sq.query_name = q.name

View file

@ -6,8 +6,13 @@ import (
)
type LabelStore interface {
// ApplyLabelSpes applies a list of LabelSpecs to the datastore,
// creating and updating labels as necessary.
ApplyLabelSpecs(specs []*LabelSpec) error
// GetLabelSpecs returns all of the stored LabelSpecs.
GetLabelSpecs() ([]*LabelSpec, error)
// Label methods
NewLabel(Label *Label, opts ...OptionalArg) (*Label, error)
DeleteLabel(lid uint) error
Label(lid uint) (*Label, error)
ListLabels(opt ListOptions) ([]*Label, error)
@ -38,31 +43,24 @@ type LabelStore interface {
ListUniqueHostsInLabels(labels []uint) ([]Host, error)
SearchLabels(query string, omit ...uint) ([]Label, error)
// SaveLabel allows modification of a label's name and/or description
SaveLabel(label *Label) (*Label, error)
}
type LabelService interface {
// ApplyLabelSpes applies a list of LabelSpecs to the datastore,
// creating and updating labels as necessary.
ApplyLabelSpecs(ctx context.Context, specs []*LabelSpec) error
// GetLabelSpecs returns all of the stored LabelSpecs.
GetLabelSpecs(ctx context.Context) ([]*LabelSpec, error)
ListLabels(ctx context.Context, opt ListOptions) (labels []*Label, err error)
GetLabel(ctx context.Context, id uint) (label *Label, err error)
NewLabel(ctx context.Context, p LabelPayload) (label *Label, err error)
DeleteLabel(ctx context.Context, id uint) (err error)
// ModifyLabel is used to change editable fields belonging to a Label
ModifyLabel(ctx context.Context, id uint, payload ModifyLabelPayload) (*Label, error)
// HostIDsForLabel returns ids of hosts that belong to the label identified
// by lid
HostIDsForLabel(lid uint) ([]uint, error)
}
// ModifyLabelPayload is used to change editable fields for a Label
type ModifyLabelPayload struct {
Name *string `json:"name"`
Description *string `json:"description"`
}
type LabelPayload struct {
Name *string `json:"name"`
Query *string `json:"query"`
@ -99,3 +97,12 @@ type LabelQueryExecution struct {
LabelID uint
HostID uint
}
type LabelSpec struct {
ID uint
Name string `json:"name"`
Description string `json:"description"`
Query string `json:"query"`
Platform string `json:"platform,omitempty"`
LabelType LabelType `json:"label_type" db:"label_type"`
}

View file

@ -6,15 +6,12 @@ import (
// PackStore is the datastore interface for managing query packs.
type PackStore interface {
// ApplyPackSpecs applies a list of PackSpecs to the datastore,
// creating and updating packs as necessary.
ApplyPackSpecs(specs []*PackSpec) error
// GetPackSpecs returns all of the stored PackSpecs.
GetPackSpecs() ([]*PackSpec, error)
// NewPack creates a new pack in the datastore.
NewPack(pack *Pack, opts ...OptionalArg) (*Pack, error)
// SavePack updates an existing pack in the datastore.
SavePack(pack *Pack) error
// DeletePack deletes a pack record from the datastore.
DeletePack(pid uint) error
@ -27,25 +24,14 @@ type PackStore interface {
// exists the bool return value is true
PackByName(name string, opts ...OptionalArg) (*Pack, bool, error)
// AddLabelToPack adds an existing label to an existing pack, both by ID.
AddLabelToPack(lid, pid uint, opts ...OptionalArg) error
// RemoveLabelFromPack removes an existing label from it's association with
// an existing pack, both by ID.
RemoveLabelFromPack(lid, pid uint) error
// ListLabelsForPack lists all labels that are associated with a pack.
ListLabelsForPack(pid uint) ([]*Label, error)
// AddHostToPack adds an existing host to an existing pack, both by ID.
AddHostToPack(hid uint, pid uint) error
// ListPacksForHost lists the packs that a host should execute.
ListPacksForHost(hid uint) (packs []*Pack, err error)
// RemoveHostFromPack removes an existing host from it's association with
// an existing pack, both by ID.
RemoveHostFromPack(hid uint, pid uint) error
// ListHostsInPack lists the IDs of all hosts that are associated with a pack,
// both through labels and manual associations.
// ListHostsInPack lists the IDs of all hosts that are associated with a pack
// through labels.
ListHostsInPack(pid uint, opt ListOptions) ([]uint, error)
// ListExplicitHostsInPack lists the IDs of hosts that have been manually
@ -55,38 +41,24 @@ type PackStore interface {
// PackService is the service interface for managing query packs.
type PackService interface {
// ApplyPackSpecs applies a list of PackSpecs to the datastore,
// creating and updating packs as necessary.
ApplyPackSpecs(ctx context.Context, specs []*PackSpec) error
// GetPackSpecs returns all of the stored PackSpecs.
GetPackSpecs(ctx context.Context) ([]*PackSpec, error)
// ListPacks lists all packs in the application.
ListPacks(ctx context.Context, opt ListOptions) (packs []*Pack, err error)
// GetPack retrieves a pack by ID.
GetPack(ctx context.Context, id uint) (pack *Pack, err error)
// NewPack creates a new pack in the datastore.
NewPack(ctx context.Context, p PackPayload) (pack *Pack, err error)
// ModifyPack modifies an existing pack in the datastore.
ModifyPack(ctx context.Context, id uint, p PackPayload) (pack *Pack, err error)
// DeletePack deletes a pack record from the datastore.
DeletePack(ctx context.Context, id uint) (err error)
// AddLabelToPack adds an existing label to an existing pack, both by ID.
AddLabelToPack(ctx context.Context, lid, pid uint) (err error)
// RemoveLabelFromPack removes an existing label from it's association with
// an existing pack, both by ID.
RemoveLabelFromPack(ctx context.Context, lid, pid uint) (err error)
// ListLabelsForPack lists all labels that are associated with a pack.
ListLabelsForPack(ctx context.Context, pid uint) (labels []*Label, err error)
// AddHostToPack adds an existing host to an existing pack, both by ID.
AddHostToPack(ctx context.Context, hid, pid uint) (err error)
// RemoveHostFromPack removes an existing host from it's association with
// an existing pack, both by ID.
RemoveHostFromPack(ctx context.Context, hid, pid uint) (err error)
// ListPacksForHost lists the packs that a host should execute.
ListPacksForHost(ctx context.Context, hid uint) (packs []*Pack, err error)

View file

@ -18,6 +18,7 @@ type ScheduledQuery struct {
ID uint `json:"id"`
PackID uint `json:"pack_id" db:"pack_id"`
Name string `json:"name"`
QueryID uint `json:"query_id" db:"query_id"`
QueryName string `json:"query_name" db:"query_name"`
Query string `json:"query"` // populated via a join on queries
Description string `json:"description"`

View file

@ -12,17 +12,18 @@ package mock
//go:generate mockimpl -o datastore_osquery_options.go "s *OsqueryOptionsStore" "kolide.OsqueryOptionsStore"
//go:generate mockimpl -o datastore_scheduled_queries.go "s *ScheduledQueryStore" "kolide.ScheduledQueryStore"
//go:generate mockimpl -o datastore_queries.go "s *QueryStore" "kolide.QueryStore"
//go:generate mockimpl -o datastore_campaigns.go "s *CampaignStore" "kolide.CampaignStore"
import "github.com/kolide/fleet/server/kolide"
var _ kolide.Datastore = (*Store)(nil)
type Store struct {
kolide.CampaignStore
kolide.SessionStore
kolide.PasswordResetStore
kolide.YARAStore
kolide.TargetStore
CampaignStore
ScheduledQueryStore
OsqueryOptionsStore
FileIntegrityMonitoringStore

View file

@ -0,0 +1,83 @@
// Automatically generated by mockimpl. DO NOT EDIT!
package mock
import (
"time"
"github.com/kolide/fleet/server/kolide"
)
var _ kolide.CampaignStore = (*CampaignStore)(nil)
type NewDistributedQueryCampaignFunc func(camp *kolide.DistributedQueryCampaign) (*kolide.DistributedQueryCampaign, error)
type DistributedQueryCampaignFunc func(id uint) (*kolide.DistributedQueryCampaign, error)
type SaveDistributedQueryCampaignFunc func(camp *kolide.DistributedQueryCampaign) error
type DistributedQueryCampaignTargetIDsFunc func(id uint) (hostIDs []uint, labelIDs []uint, err error)
type NewDistributedQueryCampaignTargetFunc func(target *kolide.DistributedQueryCampaignTarget) (*kolide.DistributedQueryCampaignTarget, error)
type NewDistributedQueryExecutionFunc func(exec *kolide.DistributedQueryExecution) (*kolide.DistributedQueryExecution, error)
type CleanupDistributedQueryCampaignsFunc func(now time.Time) (expired uint, deleted uint, err error)
type CampaignStore struct {
NewDistributedQueryCampaignFunc NewDistributedQueryCampaignFunc
NewDistributedQueryCampaignFuncInvoked bool
DistributedQueryCampaignFunc DistributedQueryCampaignFunc
DistributedQueryCampaignFuncInvoked bool
SaveDistributedQueryCampaignFunc SaveDistributedQueryCampaignFunc
SaveDistributedQueryCampaignFuncInvoked bool
DistributedQueryCampaignTargetIDsFunc DistributedQueryCampaignTargetIDsFunc
DistributedQueryCampaignTargetIDsFuncInvoked bool
NewDistributedQueryCampaignTargetFunc NewDistributedQueryCampaignTargetFunc
NewDistributedQueryCampaignTargetFuncInvoked bool
NewDistributedQueryExecutionFunc NewDistributedQueryExecutionFunc
NewDistributedQueryExecutionFuncInvoked bool
CleanupDistributedQueryCampaignsFunc CleanupDistributedQueryCampaignsFunc
CleanupDistributedQueryCampaignsFuncInvoked bool
}
func (s *CampaignStore) NewDistributedQueryCampaign(camp *kolide.DistributedQueryCampaign) (*kolide.DistributedQueryCampaign, error) {
s.NewDistributedQueryCampaignFuncInvoked = true
return s.NewDistributedQueryCampaignFunc(camp)
}
func (s *CampaignStore) DistributedQueryCampaign(id uint) (*kolide.DistributedQueryCampaign, error) {
s.DistributedQueryCampaignFuncInvoked = true
return s.DistributedQueryCampaignFunc(id)
}
func (s *CampaignStore) SaveDistributedQueryCampaign(camp *kolide.DistributedQueryCampaign) error {
s.SaveDistributedQueryCampaignFuncInvoked = true
return s.SaveDistributedQueryCampaignFunc(camp)
}
func (s *CampaignStore) DistributedQueryCampaignTargetIDs(id uint) (hostIDs []uint, labelIDs []uint, err error) {
s.DistributedQueryCampaignTargetIDsFuncInvoked = true
return s.DistributedQueryCampaignTargetIDsFunc(id)
}
func (s *CampaignStore) NewDistributedQueryCampaignTarget(target *kolide.DistributedQueryCampaignTarget) (*kolide.DistributedQueryCampaignTarget, error) {
s.NewDistributedQueryCampaignTargetFuncInvoked = true
return s.NewDistributedQueryCampaignTargetFunc(target)
}
func (s *CampaignStore) NewDistributedQueryExecution(exec *kolide.DistributedQueryExecution) (*kolide.DistributedQueryExecution, error) {
s.NewDistributedQueryExecutionFuncInvoked = true
return s.NewDistributedQueryExecutionFunc(exec)
}
func (s *CampaignStore) CleanupDistributedQueryCampaigns(now time.Time) (expired uint, deleted uint, err error) {
s.CleanupDistributedQueryCampaignsFuncInvoked = true
return s.CleanupDistributedQueryCampaignsFunc(now)
}

View file

@ -10,7 +10,9 @@ import (
var _ kolide.LabelStore = (*LabelStore)(nil)
type NewLabelFunc func(Label *kolide.Label, opts ...kolide.OptionalArg) (*kolide.Label, error)
type ApplyLabelSpecsFunc func(specs []*kolide.LabelSpec) error
type GetLabelSpecsFunc func() ([]*kolide.LabelSpec, error)
type DeleteLabelFunc func(lid uint) error
@ -30,11 +32,12 @@ type ListUniqueHostsInLabelsFunc func(labels []uint) ([]kolide.Host, error)
type SearchLabelsFunc func(query string, omit ...uint) ([]kolide.Label, error)
type SaveLabelFunc func(label *kolide.Label) (*kolide.Label, error)
type LabelStore struct {
NewLabelFunc NewLabelFunc
NewLabelFuncInvoked bool
ApplyLabelSpecsFunc ApplyLabelSpecsFunc
ApplyLabelSpecsFuncInvoked bool
GetLabelSpecsFunc GetLabelSpecsFunc
GetLabelSpecsFuncInvoked bool
DeleteLabelFunc DeleteLabelFunc
DeleteLabelFuncInvoked bool
@ -62,14 +65,16 @@ type LabelStore struct {
SearchLabelsFunc SearchLabelsFunc
SearchLabelsFuncInvoked bool
SaveLabelFunc SaveLabelFunc
SaveLabelFuncInvoked bool
}
func (s *LabelStore) NewLabel(Label *kolide.Label, opts ...kolide.OptionalArg) (*kolide.Label, error) {
s.NewLabelFuncInvoked = true
return s.NewLabelFunc(Label, opts...)
func (s *LabelStore) ApplyLabelSpecs(specs []*kolide.LabelSpec) error {
s.ApplyLabelSpecsFuncInvoked = true
return s.ApplyLabelSpecsFunc(specs)
}
func (s *LabelStore) GetLabelSpecs() ([]*kolide.LabelSpec, error) {
s.GetLabelSpecsFuncInvoked = true
return s.GetLabelSpecsFunc()
}
func (s *LabelStore) DeleteLabel(lid uint) error {
@ -116,8 +121,3 @@ func (s *LabelStore) SearchLabels(query string, omit ...uint) ([]kolide.Label, e
s.SearchLabelsFuncInvoked = true
return s.SearchLabelsFunc(query, omit...)
}
func (s *LabelStore) SaveLabel(label *kolide.Label) (*kolide.Label, error) {
s.SaveLabelFuncInvoked = true
return s.SaveLabelFunc(label)
}

View file

@ -10,10 +10,6 @@ type ApplyPackSpecsFunc func(specs []*kolide.PackSpec) error
type GetPackSpecsFunc func() ([]*kolide.PackSpec, error)
type NewPackFunc func(pack *kolide.Pack, opts ...kolide.OptionalArg) (*kolide.Pack, error)
type SavePackFunc func(pack *kolide.Pack) error
type DeletePackFunc func(pid uint) error
type PackFunc func(pid uint) (*kolide.Pack, error)
@ -22,15 +18,9 @@ type ListPacksFunc func(opt kolide.ListOptions) ([]*kolide.Pack, error)
type PackByNameFunc func(name string, opts ...kolide.OptionalArg) (*kolide.Pack, bool, error)
type AddLabelToPackFunc func(lid uint, pid uint, opts ...kolide.OptionalArg) error
type RemoveLabelFromPackFunc func(lid uint, pid uint) error
type ListLabelsForPackFunc func(pid uint) ([]*kolide.Label, error)
type AddHostToPackFunc func(hid uint, pid uint) error
type RemoveHostFromPackFunc func(hid uint, pid uint) error
type ListPacksForHostFunc func(hid uint) (packs []*kolide.Pack, err error)
type ListHostsInPackFunc func(pid uint, opt kolide.ListOptions) ([]uint, error)
@ -43,12 +33,6 @@ type PackStore struct {
GetPackSpecsFunc GetPackSpecsFunc
GetPackSpecsFuncInvoked bool
NewPackFunc NewPackFunc
NewPackFuncInvoked bool
SavePackFunc SavePackFunc
SavePackFuncInvoked bool
DeletePackFunc DeletePackFunc
DeletePackFuncInvoked bool
@ -61,20 +45,11 @@ type PackStore struct {
PackByNameFunc PackByNameFunc
PackByNameFuncInvoked bool
AddLabelToPackFunc AddLabelToPackFunc
AddLabelToPackFuncInvoked bool
RemoveLabelFromPackFunc RemoveLabelFromPackFunc
RemoveLabelFromPackFuncInvoked bool
ListLabelsForPackFunc ListLabelsForPackFunc
ListLabelsForPackFuncInvoked bool
AddHostToPackFunc AddHostToPackFunc
AddHostToPackFuncInvoked bool
RemoveHostFromPackFunc RemoveHostFromPackFunc
RemoveHostFromPackFuncInvoked bool
ListPacksForHostFunc ListPacksForHostFunc
ListPacksForHostFuncInvoked bool
ListHostsInPackFunc ListHostsInPackFunc
ListHostsInPackFuncInvoked bool
@ -93,16 +68,6 @@ func (s *PackStore) GetPackSpecs() ([]*kolide.PackSpec, error) {
return s.GetPackSpecsFunc()
}
func (s *PackStore) NewPack(pack *kolide.Pack, opts ...kolide.OptionalArg) (*kolide.Pack, error) {
s.NewPackFuncInvoked = true
return s.NewPackFunc(pack, opts...)
}
func (s *PackStore) SavePack(pack *kolide.Pack) error {
s.SavePackFuncInvoked = true
return s.SavePackFunc(pack)
}
func (s *PackStore) DeletePack(pid uint) error {
s.DeletePackFuncInvoked = true
return s.DeletePackFunc(pid)
@ -123,29 +88,14 @@ func (s *PackStore) PackByName(name string, opts ...kolide.OptionalArg) (*kolide
return s.PackByNameFunc(name, opts...)
}
func (s *PackStore) AddLabelToPack(lid uint, pid uint, opts ...kolide.OptionalArg) error {
s.AddLabelToPackFuncInvoked = true
return s.AddLabelToPackFunc(lid, pid, opts...)
}
func (s *PackStore) RemoveLabelFromPack(lid uint, pid uint) error {
s.RemoveLabelFromPackFuncInvoked = true
return s.RemoveLabelFromPackFunc(lid, pid)
}
func (s *PackStore) ListLabelsForPack(pid uint) ([]*kolide.Label, error) {
s.ListLabelsForPackFuncInvoked = true
return s.ListLabelsForPackFunc(pid)
}
func (s *PackStore) AddHostToPack(hid uint, pid uint) error {
s.AddHostToPackFuncInvoked = true
return s.AddHostToPackFunc(hid, pid)
}
func (s *PackStore) RemoveHostFromPack(hid uint, pid uint) error {
s.RemoveHostFromPackFuncInvoked = true
return s.RemoveHostFromPackFunc(hid, pid)
func (s *PackStore) ListPacksForHost(hid uint) (packs []*kolide.Pack, err error) {
s.ListPacksForHostFuncInvoked = true
return s.ListPacksForHostFunc(hid)
}
func (s *PackStore) ListHostsInPack(pid uint, opt kolide.ListOptions) ([]uint, error) {

View file

@ -102,39 +102,6 @@ func makeListLabelsEndpoint(svc kolide.Service) endpoint.Endpoint {
}
}
////////////////////////////////////////////////////////////////////////////////
// Create Label
////////////////////////////////////////////////////////////////////////////////
type createLabelRequest struct {
payload kolide.LabelPayload
}
type createLabelResponse struct {
Label labelResponse `json:"label"`
Err error `json:"error,omitempty"`
}
func (r createLabelResponse) error() error { return r.Err }
func makeCreateLabelEndpoint(svc kolide.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
req := request.(createLabelRequest)
label, err := svc.NewLabel(ctx, req.payload)
if err != nil {
return createLabelResponse{Err: err}, nil
}
labelResp, err := labelResponseForLabel(ctx, svc, label)
if err != nil {
return createLabelResponse{Err: err}, nil
}
return createLabelResponse{Label: *labelResp}, nil
}
}
////////////////////////////////////////////////////////////////////////////////
// Delete Label
////////////////////////////////////////////////////////////////////////////////
@ -159,36 +126,3 @@ func makeDeleteLabelEndpoint(svc kolide.Service) endpoint.Endpoint {
return deleteLabelResponse{}, nil
}
}
////////////////////////////////////////////////////////////////////////////////
// Modify Label
////////////////////////////////////////////////////////////////////////////////
type modifyLabelRequest struct {
ID uint
payload kolide.ModifyLabelPayload
}
type modifyLabelResponse struct {
Label labelResponse `json:"label"`
Err error `json:"error,omitempty"`
}
func (r modifyLabelResponse) error() error { return r.Err }
func makeModifyLabelEndpoint(svc kolide.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
req := request.(modifyLabelRequest)
label, err := svc.ModifyLabel(ctx, req.ID, req.payload)
if err != nil {
return modifyLabelResponse{Err: err}, nil
}
labelResp, err := labelResponseForLabel(ctx, svc, label)
if err != nil {
return modifyLabelResponse{Err: err}, nil
}
return modifyLabelResponse{Label: *labelResp}, err
}
}

View file

@ -125,75 +125,6 @@ func makeListPacksEndpoint(svc kolide.Service) endpoint.Endpoint {
}
}
////////////////////////////////////////////////////////////////////////////////
// Create Pack
////////////////////////////////////////////////////////////////////////////////
type createPackRequest struct {
payload kolide.PackPayload
}
type createPackResponse struct {
Pack packResponse `json:"pack,omitempty"`
Err error `json:"error,omitempty"`
}
func (r createPackResponse) error() error { return r.Err }
func makeCreatePackEndpoint(svc kolide.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
req := request.(createPackRequest)
pack, err := svc.NewPack(ctx, req.payload)
if err != nil {
return createPackResponse{Err: err}, nil
}
resp, err := packResponseForPack(ctx, svc, *pack)
if err != nil {
return createPackResponse{Err: err}, nil
}
return createPackResponse{
Pack: *resp,
}, nil
}
}
////////////////////////////////////////////////////////////////////////////////
// Modify Pack
////////////////////////////////////////////////////////////////////////////////
type modifyPackRequest struct {
ID uint
payload kolide.PackPayload
}
type modifyPackResponse struct {
Pack packResponse `json:"pack,omitempty"`
Err error `json:"error,omitempty"`
}
func (r modifyPackResponse) error() error { return r.Err }
func makeModifyPackEndpoint(svc kolide.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
req := request.(modifyPackRequest)
pack, err := svc.ModifyPack(ctx, req.ID, req.payload)
if err != nil {
return modifyPackResponse{Err: err}, nil
}
resp, err := packResponseForPack(ctx, svc, *pack)
if err != nil {
return modifyPackResponse{Err: err}, nil
}
return modifyPackResponse{
Pack: *resp,
}, nil
}
}
////////////////////////////////////////////////////////////////////////////////
// Delete Pack
////////////////////////////////////////////////////////////////////////////////

View file

@ -48,8 +48,6 @@ type KolideEndpoints struct {
CreateDistributedQueryCampaign endpoint.Endpoint
GetPack endpoint.Endpoint
ListPacks endpoint.Endpoint
CreatePack endpoint.Endpoint
ModifyPack endpoint.Endpoint
DeletePack endpoint.Endpoint
GetScheduledQueriesInPack endpoint.Endpoint
EnrollAgent endpoint.Endpoint
@ -59,9 +57,7 @@ type KolideEndpoints struct {
SubmitLogs endpoint.Endpoint
GetLabel endpoint.Endpoint
ListLabels endpoint.Endpoint
CreateLabel endpoint.Endpoint
DeleteLabel endpoint.Endpoint
ModifyLabel endpoint.Endpoint
ListDecorators endpoint.Endpoint
NewDecorator endpoint.Endpoint
ModifyDecorator endpoint.Endpoint
@ -132,8 +128,6 @@ func MakeKolideServerEndpoints(svc kolide.Service, jwtKey string) KolideEndpoint
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)),
GetScheduledQueriesInPack: authenticatedUser(jwtKey, svc, makeGetScheduledQueriesInPackEndpoint(svc)),
GetHost: authenticatedUser(jwtKey, svc, makeGetHostEndpoint(svc)),
@ -142,9 +136,7 @@ func MakeKolideServerEndpoints(svc kolide.Service, jwtKey string) KolideEndpoint
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)),
ModifyLabel: authenticatedUser(jwtKey, svc, makeModifyLabelEndpoint(svc)),
ListDecorators: authenticatedUser(jwtKey, svc, makeListDecoratorsEndpoint(svc)),
NewDecorator: authenticatedUser(jwtKey, svc, makeNewDecoratorEndpoint(svc)),
ModifyDecorator: authenticatedUser(jwtKey, svc, makeModifyDecoratorEndpoint(svc)),
@ -201,8 +193,6 @@ type kolideHandlers struct {
CreateDistributedQueryCampaign http.Handler
GetPack http.Handler
ListPacks http.Handler
CreatePack http.Handler
ModifyPack http.Handler
DeletePack http.Handler
GetScheduledQueriesInPack http.Handler
EnrollAgent http.Handler
@ -212,9 +202,7 @@ type kolideHandlers struct {
SubmitLogs http.Handler
GetLabel http.Handler
ListLabels http.Handler
CreateLabel http.Handler
DeleteLabel http.Handler
ModifyLabel http.Handler
ListDecorators http.Handler
NewDecorator http.Handler
ModifyDecorator http.Handler
@ -274,8 +262,6 @@ func makeKolideKitHandlers(e KolideEndpoints, opts []kithttp.ServerOption) *koli
CreateDistributedQueryCampaign: newServer(e.CreateDistributedQueryCampaign, decodeCreateDistributedQueryCampaignRequest),
GetPack: newServer(e.GetPack, decodeGetPackRequest),
ListPacks: newServer(e.ListPacks, decodeListPacksRequest),
CreatePack: newServer(e.CreatePack, decodeCreatePackRequest),
ModifyPack: newServer(e.ModifyPack, decodeModifyPackRequest),
DeletePack: newServer(e.DeletePack, decodeDeletePackRequest),
GetScheduledQueriesInPack: newServer(e.GetScheduledQueriesInPack, decodeGetScheduledQueriesInPackRequest),
EnrollAgent: newServer(e.EnrollAgent, decodeEnrollAgentRequest),
@ -285,9 +271,7 @@ func makeKolideKitHandlers(e KolideEndpoints, opts []kithttp.ServerOption) *koli
SubmitLogs: newServer(e.SubmitLogs, decodeSubmitLogsRequest),
GetLabel: newServer(e.GetLabel, decodeGetLabelRequest),
ListLabels: newServer(e.ListLabels, decodeListLabelsRequest),
CreateLabel: newServer(e.CreateLabel, decodeCreateLabelRequest),
DeleteLabel: newServer(e.DeleteLabel, decodeDeleteLabelRequest),
ModifyLabel: newServer(e.ModifyLabel, decodeModifyLabelRequest),
ListDecorators: newServer(e.ListDecorators, decodeNoParamsRequest),
NewDecorator: newServer(e.NewDecorator, decodeNewDecoratorRequest),
ModifyDecorator: newServer(e.ModifyDecorator, decodeModifyDecoratorRequest),
@ -392,15 +376,11 @@ func attachKolideAPIRoutes(r *mux.Router, h *kolideHandlers) {
r.Handle("/api/v1/kolide/packs/{id}", h.GetPack).Methods("GET").Name("get_pack")
r.Handle("/api/v1/kolide/packs", h.ListPacks).Methods("GET").Name("list_packs")
r.Handle("/api/v1/kolide/packs", h.CreatePack).Methods("POST").Name("create_pack")
r.Handle("/api/v1/kolide/packs/{id}", h.ModifyPack).Methods("PATCH").Name("modify_pack")
r.Handle("/api/v1/kolide/packs/{id}", h.DeletePack).Methods("DELETE").Name("delete_pack")
r.Handle("/api/v1/kolide/packs/{id}/scheduled", h.GetScheduledQueriesInPack).Methods("GET").Name("get_scheduled_queries_in_pack")
r.Handle("/api/v1/kolide/labels/{id}", h.GetLabel).Methods("GET").Name("get_label")
r.Handle("/api/v1/kolide/labels", h.ListLabels).Methods("GET").Name("list_labels")
r.Handle("/api/v1/kolide/labels", h.CreateLabel).Methods("POST").Name("create_label")
r.Handle("/api/v1/kolide/labels/{id}", h.DeleteLabel).Methods("DELETE").Name("delete_label")
r.Handle("/api/v1/kolide/labels/{id}", h.ModifyLabel).Methods("PATCH").Name("modify_label")
r.Handle("/api/v1/kolide/decorators", h.ListDecorators).Methods("GET").Name("list_decorators")
r.Handle("/api/v1/kolide/decorators", h.NewDecorator).Methods("POST").Name("create_decorator")

View file

@ -7,24 +7,6 @@ import (
"github.com/kolide/fleet/server/kolide"
)
func (mw loggingMiddleware) ModifyLabel(ctx context.Context, id uint, p kolide.ModifyLabelPayload) (*kolide.Label, error) {
var (
label *kolide.Label
err error
)
defer func(begin time.Time) {
mw.logger.Log(
"method", "ModifyLabel",
"err", err,
"took", time.Since(begin),
)
}(time.Now())
label, err = mw.Service.ModifyLabel(ctx, id, p)
return label, err
}
func (mw loggingMiddleware) ListLabels(ctx context.Context, opt kolide.ListOptions) ([]*kolide.Label, error) {
var (
labels []*kolide.Label
@ -61,24 +43,6 @@ func (mw loggingMiddleware) GetLabel(ctx context.Context, id uint) (*kolide.Labe
return label, err
}
func (mw loggingMiddleware) NewLabel(ctx context.Context, p kolide.LabelPayload) (*kolide.Label, error) {
var (
label *kolide.Label
err error
)
defer func(begin time.Time) {
_ = mw.logger.Log(
"method", "NewLabel",
"err", err,
"took", time.Since(begin),
)
}(time.Now())
label, err = mw.Service.NewLabel(ctx, p)
return label, err
}
func (mw loggingMiddleware) DeleteLabel(ctx context.Context, id uint) error {
var (
err error

View file

@ -43,42 +43,6 @@ func (mw loggingMiddleware) GetPack(ctx context.Context, id uint) (*kolide.Pack,
return pack, err
}
func (mw loggingMiddleware) NewPack(ctx context.Context, p kolide.PackPayload) (*kolide.Pack, error) {
var (
pack *kolide.Pack
err error
)
defer func(begin time.Time) {
_ = mw.logger.Log(
"method", "NewPack",
"err", err,
"took", time.Since(begin),
)
}(time.Now())
pack, err = mw.Service.NewPack(ctx, p)
return pack, err
}
func (mw loggingMiddleware) ModifyPack(ctx context.Context, id uint, p kolide.PackPayload) (*kolide.Pack, error) {
var (
pack *kolide.Pack
err error
)
defer func(begin time.Time) {
_ = mw.logger.Log(
"method", "ModifyPack",
"err", err,
"took", time.Since(begin),
)
}(time.Now())
pack, err = mw.Service.ModifyPack(ctx, id, p)
return pack, err
}
func (mw loggingMiddleware) DeletePack(ctx context.Context, id uint) error {
var (
err error
@ -96,40 +60,6 @@ func (mw loggingMiddleware) DeletePack(ctx context.Context, id uint) error {
return err
}
func (mw loggingMiddleware) AddLabelToPack(ctx context.Context, lid uint, pid uint) error {
var (
err error
)
defer func(begin time.Time) {
_ = mw.logger.Log(
"method", "AddLabelToPack",
"err", err,
"took", time.Since(begin),
)
}(time.Now())
err = mw.Service.AddLabelToPack(ctx, lid, pid)
return err
}
func (mw loggingMiddleware) RemoveLabelFromPack(ctx context.Context, lid uint, pid uint) error {
var (
err error
)
defer func(begin time.Time) {
_ = mw.logger.Log(
"method", "RemoveLabelFromPack",
"err", err,
"took", time.Since(begin),
)
}(time.Now())
err = mw.Service.RemoveLabelFromPack(ctx, lid, pid)
return err
}
func (mw loggingMiddleware) ListLabelsForPack(ctx context.Context, pid uint) ([]*kolide.Label, error) {
var (
labels []*kolide.Label
@ -148,40 +78,6 @@ func (mw loggingMiddleware) ListLabelsForPack(ctx context.Context, pid uint) ([]
return labels, err
}
func (mw loggingMiddleware) AddHostToPack(ctx context.Context, hid uint, pid uint) error {
var (
err error
)
defer func(begin time.Time) {
_ = mw.logger.Log(
"method", "AddHostToPack",
"err", err,
"took", time.Since(begin),
)
}(time.Now())
err = mw.Service.AddHostToPack(ctx, hid, pid)
return err
}
func (mw loggingMiddleware) RemoveHostFromPack(ctx context.Context, hid uint, pid uint) error {
var (
err error
)
defer func(begin time.Time) {
_ = mw.logger.Log(
"method", "RemoveHostFromPack",
"err", err,
"took", time.Since(begin),
)
}(time.Now())
err = mw.Service.RemoveHostFromPack(ctx, hid, pid)
return err
}
func (mw loggingMiddleware) ListPacksForHost(ctx context.Context, hid uint) ([]*kolide.Pack, error) {
var (
packs []*kolide.Pack

View file

@ -1,24 +0,0 @@
package service
import (
"context"
"fmt"
"time"
"github.com/kolide/fleet/server/kolide"
)
func (mw metricsMiddleware) ModifyLabel(ctx context.Context, id uint, p kolide.ModifyLabelPayload) (*kolide.Label, error) {
var (
lic *kolide.Label
err error
)
defer func(begin time.Time) {
lvs := []string{"method", "ModifyLabel", "error", fmt.Sprint(err != nil)}
mw.requestCount.With(lvs...).Add(1)
mw.requestLatency.With(lvs...).Observe(time.Since(begin).Seconds())
}(time.Now())
lic, err = mw.Service.ModifyLabel(ctx, id, p)
return lic, err
}

View file

@ -6,6 +6,14 @@ import (
"github.com/kolide/fleet/server/kolide"
)
func (svc service) ApplyLabelSpecs(ctx context.Context, specs []*kolide.LabelSpec) error {
return svc.ds.ApplyLabelSpecs(specs)
}
func (svc service) GetLabelSpecs(ctx context.Context) ([]*kolide.LabelSpec, error) {
return svc.ds.GetLabelSpecs()
}
func (svc service) ListLabels(ctx context.Context, opt kolide.ListOptions) ([]*kolide.Label, error) {
return svc.ds.ListLabels(opt)
}
@ -14,34 +22,6 @@ func (svc service) GetLabel(ctx context.Context, id uint) (*kolide.Label, error)
return svc.ds.Label(id)
}
func (svc service) NewLabel(ctx context.Context, p kolide.LabelPayload) (*kolide.Label, error) {
label := &kolide.Label{}
if p.Name == nil {
return nil, newInvalidArgumentError("name", "missing required argument")
}
label.Name = *p.Name
if p.Query == nil {
return nil, newInvalidArgumentError("query", "missing required argument")
}
label.Query = *p.Query
if p.Platform != nil {
label.Platform = *p.Platform
}
if p.Description != nil {
label.Description = *p.Description
}
label, err := svc.ds.NewLabel(label)
if err != nil {
return nil, err
}
return label, nil
}
func (svc service) DeleteLabel(ctx context.Context, id uint) error {
return svc.ds.DeleteLabel(id)
}
@ -57,17 +37,3 @@ func (svc service) HostIDsForLabel(lid uint) ([]uint, error) {
}
return ids, nil
}
func (svc service) ModifyLabel(ctx context.Context, id uint, payload kolide.ModifyLabelPayload) (*kolide.Label, error) {
label, err := svc.ds.Label(id)
if err != nil {
return nil, err
}
if payload.Name != nil {
label.Name = *payload.Name
}
if payload.Description != nil {
label.Description = *payload.Description
}
return svc.ds.SaveLabel(label)
}

View file

@ -7,62 +7,9 @@ import (
"github.com/kolide/fleet/server/config"
"github.com/kolide/fleet/server/datastore/inmem"
"github.com/kolide/fleet/server/kolide"
"github.com/kolide/fleet/server/mock"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestModifyLabel(t *testing.T) {
ds := new(mock.Store)
ds.LabelFunc = func(id uint) (*kolide.Label, error) {
l := &kolide.Label{
ID: id,
Name: "name",
Description: "desc",
}
return l, nil
}
ds.SaveLabelFunc = func(l *kolide.Label) (*kolide.Label, error) {
return l, nil
}
svc, err := newTestService(ds, nil)
require.Nil(t, err)
lp := kolide.ModifyLabelPayload{
Name: stringPtr("new name"),
Description: stringPtr("new desc"),
}
l, err := svc.ModifyLabel(context.Background(), uint(1), lp)
assert.Equal(t, "new name", l.Name)
assert.Equal(t, "new desc", l.Description)
assert.True(t, ds.LabelFuncInvoked)
assert.True(t, ds.SaveLabelFuncInvoked)
}
func TestListLabels(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()
labels, err := svc.ListLabels(ctx, kolide.ListOptions{})
assert.Nil(t, err)
assert.Len(t, labels, 0)
_, err = ds.NewLabel(&kolide.Label{
Name: "foo",
Query: "select * from foo;",
})
assert.Nil(t, err)
labels, err = svc.ListLabels(ctx, kolide.ListOptions{})
assert.Nil(t, err)
assert.Len(t, labels, 1)
assert.Equal(t, "foo", labels[0].Name)
}
func TestGetLabel(t *testing.T) {
ds, err := inmem.New(config.TestConfig())
assert.Nil(t, err)
@ -85,31 +32,6 @@ func TestGetLabel(t *testing.T) {
assert.Equal(t, label.ID, labelVerify.ID)
}
func TestNewLabel(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()
name := "foo"
query := "select * from foo;"
label, err := svc.NewLabel(ctx, kolide.LabelPayload{
Name: &name,
Query: &query,
})
assert.NotZero(t, label.ID)
assert.Nil(t, err)
labels, err := ds.ListLabels(kolide.ListOptions{})
assert.Nil(t, err)
assert.Len(t, labels, 1)
assert.Equal(t, "foo", labels[0].Name)
}
func TestDeleteLabel(t *testing.T) {
ds, err := inmem.New(config.TestConfig())
assert.Nil(t, err)

View file

@ -136,7 +136,7 @@ func (svc service) GetClientConfig(ctx context.Context) (map[string]interface{},
config["decorators"] = json.RawMessage(decJSON)
}
packs, err := svc.ListPacksForHost(ctx, host.ID)
packs, err := svc.ds.ListPacksForHost(host.ID)
if err != nil {
return nil, osqueryError{message: "database error: " + err.Error()}
}

View file

@ -219,19 +219,33 @@ func TestHostDetailQueries(t *testing.T) {
}
}
func TestGetDistributedQueriesMissingHost(t *testing.T) {
svc, err := newTestService(&mock.Store{}, nil)
require.Nil(t, err)
_, _, err = svc.GetDistributedQueries(context.Background())
require.NotNil(t, err)
assert.Contains(t, err.Error(), "missing host")
}
func TestLabelQueries(t *testing.T) {
ds, svc, mockClock := setupOsqueryTests(t)
ctx := context.Background()
_, err := svc.EnrollAgent(ctx, "", "host123")
mockClock := clock.NewMockClock()
ds := new(mock.Store)
svc, err := newTestServiceWithClock(ds, nil, mockClock)
require.Nil(t, err)
hosts, err := ds.ListHosts(kolide.ListOptions{})
require.Nil(t, err)
require.Len(t, hosts, 1)
host := hosts[0]
ds.LabelQueriesForHostFunc = func(host *kolide.Host, cutoff time.Time) (map[string]string, error) {
return map[string]string{}, nil
}
ds.DistributedQueriesForHostFunc = func(host *kolide.Host) (map[uint]string, error) {
return map[uint]string{}, nil
}
ds.SaveHostFunc = func(host *kolide.Host) error {
return nil
}
ctx = hostctx.NewContext(ctx, *host)
host := &kolide.Host{}
ctx := hostctx.NewContext(context.Background(), *host)
// With a new host, we should get the detail queries (and accelerate
// should be turned on so that we can quickly fill labels)
@ -244,7 +258,6 @@ func TestLabelQueries(t *testing.T) {
host.DetailUpdateTime = mockClock.Now().Add(-1 * time.Minute)
host.Platform = "darwin"
host.HostName = "zwass.local"
ds.SaveHost(host)
ctx = hostctx.NewContext(ctx, *host)
queries, acc, err = svc.GetDistributedQueries(ctx)
@ -252,32 +265,12 @@ func TestLabelQueries(t *testing.T) {
assert.Len(t, queries, 0)
assert.Zero(t, acc)
labels := []kolide.Label{
kolide.Label{
Name: "label1",
Query: "query1",
Platform: "darwin",
},
kolide.Label{
Name: "label2",
Query: "query2",
Platform: "darwin",
},
kolide.Label{
Name: "label3",
Query: "query3",
Platform: "darwin,linux",
},
kolide.Label{
Name: "label4",
Query: "query4",
Platform: "linux",
},
}
for _, label := range labels {
_, err := ds.NewLabel(&label)
assert.Nil(t, err)
ds.LabelQueriesForHostFunc = func(host *kolide.Host, cutoff time.Time) (map[string]string, error) {
return map[string]string{
"label1": "query1",
"label2": "query2",
"label3": "query3",
}, nil
}
// Now we should get the label queries
@ -286,6 +279,16 @@ func TestLabelQueries(t *testing.T) {
assert.Len(t, queries, 3)
assert.Zero(t, acc)
var gotHost *kolide.Host
var gotResults map[uint]bool
var gotTime time.Time
ds.RecordLabelQueryExecutionsFunc = func(host *kolide.Host, results map[uint]bool, t time.Time) error {
gotHost = host
gotResults = results
gotTime = t
return nil
}
// Record a query execution
err = svc.SubmitDistributedQueryResults(
ctx,
@ -295,32 +298,13 @@ func TestLabelQueries(t *testing.T) {
map[string]string{},
)
assert.Nil(t, err)
assert.Equal(t, host, gotHost)
assert.Equal(t, mockClock.Now(), gotTime)
if assert.Len(t, gotResults, 1) {
assert.Equal(t, true, gotResults[1])
}
// Verify that labels are set appropriately
hostLabels, err := ds.ListLabelsForHost(host.ID)
assert.Len(t, hostLabels, 1)
assert.Equal(t, "label1", hostLabels[0].Name)
// Now that query should not be returned
queries, acc, err = svc.GetDistributedQueries(ctx)
assert.Nil(t, err)
assert.Len(t, queries, 2)
assert.NotContains(t, queries, "kolide_label_query_1")
assert.Zero(t, acc)
// Advance the time
mockClock.AddTime(1*time.Hour + 1*time.Minute)
// Keep the host details fresh
host.DetailUpdateTime = mockClock.Now().Add(-1 * time.Minute)
ds.SaveHost(host)
ctx = hostctx.NewContext(ctx, *host)
// Now we should get all the label queries again
queries, acc, err = svc.GetDistributedQueries(ctx)
assert.Nil(t, err)
assert.Len(t, queries, 3)
assert.Zero(t, acc)
mockClock.AddTime(1 * time.Second)
// Record a query execution
err = svc.SubmitDistributedQueryResults(
@ -332,20 +316,11 @@ func TestLabelQueries(t *testing.T) {
map[string]string{},
)
assert.Nil(t, err)
// Now these should no longer show up in the necessary to run queries
queries, acc, err = svc.GetDistributedQueries(ctx)
assert.Nil(t, err)
assert.Len(t, queries, 1)
assert.Zero(t, acc)
// Verify that labels are set appropriately
hostLabels, err = ds.ListLabelsForHost(host.ID)
assert.Len(t, hostLabels, 2)
expectLabelNames := map[string]bool{"label1": true, "label2": true}
for _, label := range hostLabels {
assert.Contains(t, expectLabelNames, label.Name)
delete(expectLabelNames, label.Name)
assert.Equal(t, host, gotHost)
assert.Equal(t, mockClock.Now(), gotTime)
if assert.Len(t, gotResults, 2) {
assert.Equal(t, true, gotResults[2])
assert.Equal(t, false, gotResults[3])
}
}
@ -354,32 +329,9 @@ func TestGetClientConfig(t *testing.T) {
ds.ListDecoratorsFunc = func(opt ...kolide.OptionalArg) ([]*kolide.Decorator, error) {
return []*kolide.Decorator{}, nil
}
ds.ListPacksFunc = func(opt kolide.ListOptions) ([]*kolide.Pack, error) {
ds.ListPacksForHostFunc = func(hid uint) ([]*kolide.Pack, error) {
return []*kolide.Pack{}, nil
}
ds.ListLabelsForHostFunc = func(hid uint) ([]kolide.Label, error) {
return []kolide.Label{
{ID: 1, Name: "foo_label"},
}, nil
}
ds.ListLabelsForPackFunc = func(pid uint) ([]*kolide.Label, error) {
switch pid {
case 1, 2:
return []*kolide.Label{
{ID: 1, Name: "foo_label"},
}, nil
default:
return []*kolide.Label{}, nil
}
}
ds.ListExplicitHostsInPackFunc = func(pid uint, opt kolide.ListOptions) ([]uint, error) {
switch pid {
case 4:
return []uint{1}, nil
default:
return []uint{}, nil
}
}
ds.ListScheduledQueriesInPackFunc = func(pid uint, opt kolide.ListOptions) ([]*kolide.ScheduledQuery, error) {
tru := true
fals := false
@ -411,7 +363,8 @@ func TestGetClientConfig(t *testing.T) {
svc, err := newTestService(ds, nil)
require.Nil(t, err)
ctx := hostctx.NewContext(context.Background(), kolide.Host{ID: 1})
ctx1 := hostctx.NewContext(context.Background(), kolide.Host{ID: 1})
ctx2 := hostctx.NewContext(context.Background(), kolide.Host{ID: 2})
expectedOptions := map[string]interface{}{
"distributed_interval": float64(11),
@ -419,25 +372,36 @@ func TestGetClientConfig(t *testing.T) {
}
// No packs loaded yet
conf, err := svc.GetClientConfig(ctx)
conf, err := svc.GetClientConfig(ctx1)
require.Nil(t, err)
assert.Equal(t, map[string]interface{}{"options": expectedOptions}, conf)
conf, err = svc.GetClientConfig(ctx2)
require.Nil(t, err)
assert.Equal(t, map[string]interface{}{"options": expectedOptions}, conf)
// Now add packs
ds.ListPacksFunc = func(opt kolide.ListOptions) ([]*kolide.Pack, error) {
return []*kolide.Pack{
{ID: 1, Name: "pack_by_label"},
{ID: 2, Name: "disabled_pack", Disabled: true},
{ID: 3, Name: "not_matching_pack"},
{ID: 4, Name: "pack_by_explicit_host"},
}, nil
ds.ListPacksForHostFunc = func(hid uint) ([]*kolide.Pack, error) {
switch hid {
case 1:
return []*kolide.Pack{
{ID: 1, Name: "pack_by_label"},
{ID: 4, Name: "pack_by_other_label"},
}, nil
case 2:
return []*kolide.Pack{
{ID: 1, Name: "pack_by_label"},
}, nil
}
return []*kolide.Pack{}, nil
}
conf, err = svc.GetClientConfig(ctx)
conf, err = svc.GetClientConfig(ctx1)
require.Nil(t, err)
assert.Equal(t, expectedOptions, conf["options"])
assert.JSONEq(t, `{
"pack_by_explicit_host": {
"pack_by_other_label": {
"queries": {
"foobar":{"query":"select 3","interval":20,"shard":42},
"froobing":{"query":"select 'guacamole'","interval":60,"snapshot":true}
@ -451,6 +415,19 @@ func TestGetClientConfig(t *testing.T) {
}`,
string(conf["packs"].(json.RawMessage)),
)
conf, err = svc.GetClientConfig(ctx2)
require.Nil(t, err)
assert.Equal(t, expectedOptions, conf["options"])
assert.JSONEq(t, `{
"pack_by_label": {
"queries":{
"time":{"query":"select * from time","interval":30,"removed":false}
}
}
}`,
string(conf["packs"].(json.RawMessage)),
)
}
func TestDetailQueriesWithEmptyStrings(t *testing.T) {
@ -785,71 +762,97 @@ func TestDetailQueries(t *testing.T) {
assert.Zero(t, acc)
}
func TestDistributedQueries(t *testing.T) {
ds, err := inmem.New(config.TestConfig())
require.Nil(t, err)
_, err = ds.NewAppConfig(&kolide.AppConfig{EnrollSecret: ""})
require.Nil(t, err)
func TestNewDistributedQueryCampaign(t *testing.T) {
mockClock := clock.NewMockClock()
rs := pubsub.NewInmemQueryResults()
svc, err := newTestServiceWithClock(ds, rs, mockClock)
ds := new(mock.Store)
svc, err := newTestServiceWithClock(ds, nil, mockClock)
require.Nil(t, err)
ctx := context.Background()
ds.LabelQueriesForHostFunc = func(host *kolide.Host, cutoff time.Time) (map[string]string, error) {
return map[string]string{}, nil
}
ds.DistributedQueriesForHostFunc = func(host *kolide.Host) (map[uint]string, error) {
return map[uint]string{}, nil
}
ds.SaveHostFunc = func(host *kolide.Host) error {
return nil
}
var gotQuery *kolide.Query
ds.NewQueryFunc = func(query *kolide.Query, opts ...kolide.OptionalArg) (*kolide.Query, error) {
gotQuery = query
query.ID = 42
return query, nil
}
var gotCampaign *kolide.DistributedQueryCampaign
ds.NewDistributedQueryCampaignFunc = func(camp *kolide.DistributedQueryCampaign) (*kolide.DistributedQueryCampaign, error) {
gotCampaign = camp
camp.ID = 21
return camp, nil
}
var gotTargets []*kolide.DistributedQueryCampaignTarget
ds.NewDistributedQueryCampaignTargetFunc = func(target *kolide.DistributedQueryCampaignTarget) (*kolide.DistributedQueryCampaignTarget, error) {
gotTargets = append(gotTargets, target)
return target, nil
}
nodeKey, err := svc.EnrollAgent(ctx, "", "host123")
require.Nil(t, err)
host, err := ds.AuthenticateHost(nodeKey)
require.Nil(t, err)
host.Platform = "centos"
host.HostName = "zwass.local"
require.Nil(t, ds.SaveHost(host))
// Create label
n := "foo"
q := "select * from foo;"
label, err := svc.NewLabel(ctx, kolide.LabelPayload{
Name: &n,
Query: &q,
})
require.Nil(t, err)
// Record match with label
ctx = viewer.NewContext(ctx, viewer.Viewer{
viewerCtx := viewer.NewContext(context.Background(), viewer.Viewer{
User: &kolide.User{
ID: 0,
},
})
err = ds.RecordLabelQueryExecutions(host, map[uint]bool{label.ID: true}, mockClock.Now())
q := "select year, month, day, hour, minutes, seconds from time"
campaign, err := svc.NewDistributedQueryCampaign(viewerCtx, q, []uint{2}, []uint{1})
require.Nil(t, err)
err = ds.MarkHostSeen(host, mockClock.Now())
require.Nil(t, err)
ctx = hostctx.NewContext(ctx, *host)
assert.Equal(t, gotQuery.ID, gotCampaign.QueryID)
assert.Equal(t, []*kolide.DistributedQueryCampaignTarget{
&kolide.DistributedQueryCampaignTarget{
Type: kolide.TargetHost,
DistributedQueryCampaignID: campaign.ID,
TargetID: 2,
},
&kolide.DistributedQueryCampaignTarget{
Type: kolide.TargetLabel,
DistributedQueryCampaignID: campaign.ID,
TargetID: 1,
},
}, gotTargets,
)
}
q = "select year, month, day, hour, minutes, seconds from time"
campaign, err := svc.NewDistributedQueryCampaign(ctx, q, []uint{}, []uint{label.ID})
func TestDistributedQueryResults(t *testing.T) {
mockClock := clock.NewMockClock()
ds := new(mock.Store)
rs := pubsub.NewInmemQueryResults()
svc, err := newTestServiceWithClock(ds, rs, mockClock)
require.Nil(t, err)
// Manually set the campaign to running (so that it shows up when
// requesting queries)
campaign.Status = kolide.QueryRunning
err = ds.SaveDistributedQueryCampaign(campaign)
require.Nil(t, err)
campaign := &kolide.DistributedQueryCampaign{ID: 42}
queryKey := fmt.Sprintf("%s%d", hostDistributedQueryPrefix, campaign.ID)
ds.LabelQueriesForHostFunc = func(host *kolide.Host, cutoff time.Time) (map[string]string, error) {
return map[string]string{}, nil
}
ds.SaveHostFunc = func(host *kolide.Host) error {
return nil
}
ds.DistributedQueriesForHostFunc = func(host *kolide.Host) (map[uint]string, error) {
return map[uint]string{campaign.ID: "select * from time"}, nil
}
var gotExecution *kolide.DistributedQueryExecution
ds.NewDistributedQueryExecutionFunc = func(exec *kolide.DistributedQueryExecution) (*kolide.DistributedQueryExecution, error) {
gotExecution = exec
return exec, nil
}
host := &kolide.Host{ID: 1}
hostCtx := hostctx.NewContext(context.Background(), *host)
// Now we should get the active distributed query
queries, acc, err := svc.GetDistributedQueries(ctx)
queries, acc, err := svc.GetDistributedQueries(hostCtx)
require.Nil(t, err)
assert.Len(t, queries, len(detailQueries)+1)
assert.Equal(t, q, queries[queryKey])
assert.Zero(t, acc)
queryKey := fmt.Sprintf("%s%d", hostDistributedQueryPrefix, campaign.ID)
assert.Equal(t, "select * from time", queries[queryKey])
assert.NotZero(t, acc)
expectedRows := []map[string]string{
{
@ -866,7 +869,7 @@ func TestDistributedQueries(t *testing.T) {
}
// TODO use service method
readChan, err := rs.ReadChannel(ctx, *campaign)
readChan, err := rs.ReadChannel(context.Background(), *campaign)
require.Nil(t, err)
// We need to listen for the result in a separate thread to prevent the
@ -901,17 +904,11 @@ func TestDistributedQueries(t *testing.T) {
// this test.
time.Sleep(10 * time.Millisecond)
err = svc.SubmitDistributedQueryResults(ctx, results, map[string]string{})
err = svc.SubmitDistributedQueryResults(hostCtx, results, map[string]string{})
require.Nil(t, err)
// Now the distributed query should be completed and not returned
queries, acc, err = svc.GetDistributedQueries(ctx)
require.Nil(t, err)
assert.Len(t, queries, len(detailQueries))
assert.NotContains(t, queries, queryKey)
assert.Zero(t, acc)
waitComplete.Wait()
assert.Equal(t, campaign.ID, gotExecution.DistributedQueryCampaignID)
assert.Equal(t, host.ID, gotExecution.HostID)
assert.Equal(t, kolide.ExecutionSucceeded, gotExecution.Status)
}
func TestOrphanedQueryCampaign(t *testing.T) {
@ -983,12 +980,9 @@ func TestUpdateHostIntervals(t *testing.T) {
ds.ListDecoratorsFunc = func(opt ...kolide.OptionalArg) ([]*kolide.Decorator, error) {
return []*kolide.Decorator{}, nil
}
ds.ListPacksFunc = func(opt kolide.ListOptions) ([]*kolide.Pack, error) {
ds.ListPacksForHostFunc = func(hid uint) ([]*kolide.Pack, error) {
return []*kolide.Pack{}, nil
}
ds.ListLabelsForHostFunc = func(hid uint) ([]kolide.Label, error) {
return []kolide.Label{}, nil
}
var testCases = []struct {
initHost kolide.Host

View file

@ -6,6 +6,14 @@ import (
"github.com/kolide/fleet/server/kolide"
)
func (svc service) ApplyPackSpecs(ctx context.Context, specs []*kolide.PackSpec) error {
return svc.ds.ApplyPackSpecs(specs)
}
func (svc service) GetPackSpecs(ctx context.Context) ([]*kolide.PackSpec, error) {
return svc.ds.GetPackSpecs()
}
func (svc service) ListPacks(ctx context.Context, opt kolide.ListOptions) ([]*kolide.Pack, error) {
return svc.ds.ListPacks(opt)
}
@ -14,201 +22,14 @@ func (svc service) GetPack(ctx context.Context, id uint) (*kolide.Pack, error) {
return svc.ds.Pack(id)
}
func (svc service) NewPack(ctx context.Context, p kolide.PackPayload) (*kolide.Pack, error) {
var pack kolide.Pack
if p.Name != nil {
pack.Name = *p.Name
}
if p.Description != nil {
pack.Description = *p.Description
}
if p.Platform != nil {
pack.Platform = *p.Platform
}
if p.Disabled != nil {
pack.Disabled = *p.Disabled
}
_, err := svc.ds.NewPack(&pack)
if err != nil {
return nil, err
}
if p.HostIDs != nil {
for _, hostID := range *p.HostIDs {
err = svc.AddHostToPack(ctx, hostID, pack.ID)
if err != nil {
return nil, err
}
}
}
if p.LabelIDs != nil {
for _, labelID := range *p.LabelIDs {
err = svc.AddLabelToPack(ctx, labelID, pack.ID)
if err != nil {
return nil, err
}
}
}
return &pack, nil
}
func (svc service) ModifyPack(ctx context.Context, id uint, p kolide.PackPayload) (*kolide.Pack, error) {
pack, err := svc.ds.Pack(id)
if err != nil {
return nil, err
}
if p.Name != nil {
pack.Name = *p.Name
}
if p.Description != nil {
pack.Description = *p.Description
}
if p.Platform != nil {
pack.Platform = *p.Platform
}
if p.Disabled != nil {
pack.Disabled = *p.Disabled
}
err = svc.ds.SavePack(pack)
if err != nil {
return nil, err
}
// we must determine what hosts are attached to this pack. then, given
// our new set of host_ids, we will mutate the database to reflect the
// desired state.
if p.HostIDs != nil {
// first, let's retrieve the total set of hosts
hosts, err := svc.ListHostsInPack(ctx, pack.ID, kolide.ListOptions{})
if err != nil {
return nil, err
}
// it will be efficient to create a data structure with constant time
// lookups to determine whether or not a host is already added
existingHosts := map[uint]bool{}
for _, host := range hosts {
existingHosts[host] = true
}
// we will also make a constant time lookup map for the desired set of
// hosts as well.
desiredHosts := map[uint]bool{}
for _, hostID := range *p.HostIDs {
desiredHosts[hostID] = true
}
// if the request declares a host ID but the host is not already
// associated with the pack, we add it
for _, hostID := range *p.HostIDs {
if !existingHosts[hostID] {
err = svc.AddHostToPack(ctx, hostID, pack.ID)
if err != nil {
return nil, err
}
}
}
// if the request does not declare the ID of a host which currently
// exists, we delete the existing relationship
for hostID := range existingHosts {
if !desiredHosts[hostID] {
err = svc.RemoveHostFromPack(ctx, hostID, pack.ID)
if err != nil {
return nil, err
}
}
}
}
// we must determine what labels are attached to this pack. then, given
// our new set of label_ids, we will mutate the database to reflect the
// desired state.
if p.LabelIDs != nil {
// first, let's retrieve the total set of labels
labels, err := svc.ListLabelsForPack(ctx, pack.ID)
if err != nil {
return nil, err
}
// it will be efficient to create a data structure with constant time
// lookups to determine whether or not a label is already added
existingLabels := map[uint]bool{}
for _, label := range labels {
existingLabels[label.ID] = true
}
// we will also make a constant time lookup map for the desired set of
// labels as well.
desiredLabels := map[uint]bool{}
for _, labelID := range *p.LabelIDs {
desiredLabels[labelID] = true
}
// if the request declares a label ID but the label is not already
// associated with the pack, we add it
for _, labelID := range *p.LabelIDs {
if !existingLabels[labelID] {
err = svc.AddLabelToPack(ctx, labelID, pack.ID)
if err != nil {
return nil, err
}
}
}
// if the request does not declare the ID of a label which currently
// exists, we delete the existing relationship
for labelID := range existingLabels {
if !desiredLabels[labelID] {
err = svc.RemoveLabelFromPack(ctx, labelID, pack.ID)
if err != nil {
return nil, err
}
}
}
}
return pack, err
}
func (svc service) DeletePack(ctx context.Context, id uint) error {
return svc.ds.DeletePack(id)
}
func (svc service) AddLabelToPack(ctx context.Context, lid, pid uint) error {
return svc.ds.AddLabelToPack(lid, pid)
}
func (svc service) ListLabelsForPack(ctx context.Context, pid uint) ([]*kolide.Label, error) {
return svc.ds.ListLabelsForPack(pid)
}
func (svc service) RemoveLabelFromPack(ctx context.Context, lid, pid uint) error {
return svc.ds.RemoveLabelFromPack(lid, pid)
}
func (svc service) AddHostToPack(ctx context.Context, hid, pid uint) error {
return svc.ds.AddHostToPack(hid, pid)
}
func (svc service) RemoveHostFromPack(ctx context.Context, hid, pid uint) error {
return svc.ds.RemoveHostFromPack(hid, pid)
}
func (svc service) ListHostsInPack(ctx context.Context, pid uint, opt kolide.ListOptions) ([]uint, error) {
return svc.ds.ListHostsInPack(pid, opt)
}
@ -218,65 +39,5 @@ func (svc service) ListExplicitHostsInPack(ctx context.Context, pid uint, opt ko
}
func (svc service) ListPacksForHost(ctx context.Context, hid uint) ([]*kolide.Pack, error) {
packs := []*kolide.Pack{}
// we will need to give some subset of packs to this host based on the
// labels which this host is known to belong to
allPacks, err := svc.ds.ListPacks(kolide.ListOptions{})
if err != nil {
return nil, err
}
// pull the labels that this host belongs to
labels, err := svc.ds.ListLabelsForHost(hid)
if err != nil {
return nil, err
}
// in order to use o(1) array indexing in an o(n) loop vs a o(n^2) double
// for loop iteration, we must create the array which may be indexed below
labelIDs := map[uint]bool{}
for _, label := range labels {
labelIDs[label.ID] = true
}
for _, pack := range allPacks {
// don't include packs which have been disabled
if pack.Disabled {
continue
}
// for each pack, we must know what labels have been assigned to that
// pack
labelsForPack, err := svc.ds.ListLabelsForPack(pack.ID)
if err != nil {
return nil, err
}
// o(n) iteration to determine whether or not a pack is enabled
// in this case, n is len(labelsForPack)
for _, label := range labelsForPack {
if labelIDs[label.ID] {
packs = append(packs, pack)
break
}
}
// for each pack, we must know what host have been assigned to that pack
hostsForPack, err := svc.ds.ListExplicitHostsInPack(pack.ID, kolide.ListOptions{})
if err != nil {
return nil, err
}
// o(n) iteration to determine whether or not a pack is enabled
// in this case, n is len(hostsForPack)
for _, host := range hostsForPack {
if host == hid {
packs = append(packs, pack)
break
}
}
}
return packs, nil
return svc.ds.ListPacksForHost(hid)
}

View file

@ -4,13 +4,10 @@ import (
"context"
"testing"
"github.com/WatchBeam/clock"
"github.com/kolide/fleet/server/config"
"github.com/kolide/fleet/server/datastore/inmem"
"github.com/kolide/fleet/server/kolide"
"github.com/kolide/fleet/server/test"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestListPacks(t *testing.T) {
@ -58,95 +55,6 @@ func TestGetPack(t *testing.T) {
assert.Equal(t, pack.ID, packVerify.ID)
}
func TestNewPack(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()
labelName := "label"
labelQuery := "select 1"
label, err := svc.NewLabel(ctx, kolide.LabelPayload{
Name: &labelName,
Query: &labelQuery,
})
packName := "foo"
packLabelIDs := []uint{label.ID}
pack, err := svc.NewPack(ctx, kolide.PackPayload{
Name: &packName,
LabelIDs: &packLabelIDs,
})
assert.Nil(t, err)
packs, err := ds.ListPacks(kolide.ListOptions{})
assert.Nil(t, err)
require.Len(t, packs, 1)
assert.Equal(t, pack.ID, packs[0].ID)
labels, err := ds.ListLabelsForPack(pack.ID)
assert.Nil(t, err)
require.Len(t, labels, 1)
assert.Equal(t, label.ID, labels[0].ID)
}
func TestModifyPack(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()
label := &kolide.Label{
Name: "label",
Query: "select 1",
}
label, err = ds.NewLabel(label)
assert.Nil(t, err)
assert.NotZero(t, label.ID)
pack := &kolide.Pack{
Name: "foo",
}
pack, err = ds.NewPack(pack)
assert.Nil(t, err)
assert.NotZero(t, pack.ID)
newName := "bar"
labelIDs := []uint{label.ID}
packVerify, err := svc.ModifyPack(ctx, pack.ID, kolide.PackPayload{
Name: &newName,
LabelIDs: &labelIDs,
})
assert.Nil(t, err)
assert.Equal(t, pack.ID, packVerify.ID)
assert.Equal(t, "bar", packVerify.Name)
labels, err := ds.ListLabelsForPack(pack.ID)
assert.Nil(t, err)
require.Len(t, labels, 1)
assert.Equal(t, label.ID, labels[0].ID)
newLabelIDs := []uint{}
packVerify2, err := svc.ModifyPack(ctx, pack.ID, kolide.PackPayload{
LabelIDs: &newLabelIDs,
})
assert.Nil(t, err)
assert.Equal(t, pack.ID, packVerify2.ID)
labels, err = ds.ListLabelsForPack(pack.ID)
assert.Nil(t, err)
require.Len(t, labels, 0)
}
func TestDeletePack(t *testing.T) {
ds, err := inmem.New(config.TestConfig())
assert.Nil(t, err)
@ -170,38 +78,3 @@ func TestDeletePack(t *testing.T) {
assert.Nil(t, err)
assert.Len(t, queries, 0)
}
func TestListPacksForHost(t *testing.T) {
ds, err := inmem.New(config.TestConfig())
assert.Nil(t, err)
mockClock := clock.NewMockClock()
svc, err := newTestService(ds, nil)
assert.Nil(t, err)
ctx := context.Background()
h1 := test.NewHost(t, ds, "h1", "10.10.10.1", "1", "1", mockClock.Now())
h2 := test.NewHost(t, ds, "h2", "10.10.10.2", "2", "2", mockClock.Now())
p1 := test.NewPack(t, ds, "p1")
p2 := test.NewPack(t, ds, "p2")
require.Nil(t, svc.AddHostToPack(ctx, h1.ID, p1.ID))
require.Nil(t, svc.AddHostToPack(ctx, h2.ID, p1.ID))
require.Nil(t, svc.AddHostToPack(ctx, h1.ID, p2.ID))
{
packs, err := svc.ListPacksForHost(ctx, h1.ID)
require.Nil(t, err)
require.Len(t, packs, 2)
}
{
packs, err := svc.ListPacksForHost(ctx, h2.ID)
require.Nil(t, err)
require.Len(t, packs, 1)
}
}

View file

@ -2,18 +2,9 @@ package service
import (
"context"
"encoding/json"
"net/http"
)
func decodeCreateLabelRequest(ctx context.Context, r *http.Request) (interface{}, error) {
var req createLabelRequest
if err := json.NewDecoder(r.Body).Decode(&req.payload); err != nil {
return nil, err
}
return req, nil
}
func decodeDeleteLabelRequest(ctx context.Context, r *http.Request) (interface{}, error) {
id, err := idFromRequest(r, "id")
if err != nil {
@ -41,17 +32,3 @@ func decodeListLabelsRequest(ctx context.Context, r *http.Request) (interface{},
}
return listLabelsRequest{ListOptions: opt}, nil
}
func decodeModifyLabelRequest(ctx context.Context, r *http.Request) (interface{}, error) {
id, err := idFromRequest(r, "id")
if err != nil {
return nil, err
}
var resp modifyLabelRequest
err = json.NewDecoder(r.Body).Decode(&resp.payload)
if err != nil {
return nil, err
}
resp.ID = id
return resp, nil
}

View file

@ -1,7 +1,6 @@
package service
import (
"bytes"
"context"
"net/http"
"net/http/httptest"
@ -11,31 +10,6 @@ import (
"github.com/stretchr/testify/assert"
)
func TestDecodeCreateLabelRequest(t *testing.T) {
router := mux.NewRouter()
router.HandleFunc("/api/v1/kolide/labels", func(writer http.ResponseWriter, request *http.Request) {
r, err := decodeCreateLabelRequest(context.Background(), request)
assert.Nil(t, err)
params := r.(createLabelRequest)
assert.Equal(t, "foo", *params.payload.Name)
assert.Equal(t, "select * from foo;", *params.payload.Query)
assert.Equal(t, "darwin", *params.payload.Platform)
}).Methods("POST")
var body bytes.Buffer
body.Write([]byte(`{
"name": "foo",
"query": "select * from foo;",
"platform": "darwin"
}`))
router.ServeHTTP(
httptest.NewRecorder(),
httptest.NewRequest("POST", "/api/v1/kolide/labels", &body),
)
}
func TestDecodeDeleteLabelRequest(t *testing.T) {
router := mux.NewRouter()
router.HandleFunc("/api/v1/kolide/labels/{id}", func(writer http.ResponseWriter, request *http.Request) {

View file

@ -2,32 +2,9 @@ package service
import (
"context"
"encoding/json"
"net/http"
)
func decodeCreatePackRequest(ctx context.Context, r *http.Request) (interface{}, error) {
var req createPackRequest
if err := json.NewDecoder(r.Body).Decode(&req.payload); err != nil {
return nil, err
}
return req, nil
}
func decodeModifyPackRequest(ctx context.Context, r *http.Request) (interface{}, error) {
id, err := idFromRequest(r, "id")
if err != nil {
return nil, err
}
var req modifyPackRequest
if err := json.NewDecoder(r.Body).Decode(&req.payload); err != nil {
return nil, err
}
req.ID = id
return req, nil
}
func decodeDeletePackRequest(ctx context.Context, r *http.Request) (interface{}, error) {
id, err := idFromRequest(r, "id")
if err != nil {

View file

@ -1,7 +1,6 @@
package service
import (
"bytes"
"context"
"net/http"
"net/http/httptest"
@ -9,68 +8,8 @@ import (
"github.com/gorilla/mux"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestDecodeCreatePackRequest(t *testing.T) {
router := mux.NewRouter()
router.HandleFunc("/api/v1/kolide/packs", func(writer http.ResponseWriter, request *http.Request) {
r, err := decodeCreatePackRequest(context.Background(), request)
assert.Nil(t, err)
params := r.(createPackRequest)
assert.Equal(t, "foo", *params.payload.Name)
assert.Equal(t, "bar", *params.payload.Description)
require.NotNil(t, params.payload.HostIDs)
assert.Len(t, *params.payload.HostIDs, 3)
require.NotNil(t, params.payload.LabelIDs)
assert.Len(t, *params.payload.LabelIDs, 2)
}).Methods("POST")
var body bytes.Buffer
body.Write([]byte(`{
"name": "foo",
"description": "bar",
"host_ids": [1, 2, 3],
"label_ids": [1, 5]
}`))
router.ServeHTTP(
httptest.NewRecorder(),
httptest.NewRequest("POST", "/api/v1/kolide/packs", &body),
)
}
func TestDecodeModifyPackRequest(t *testing.T) {
router := mux.NewRouter()
router.HandleFunc("/api/v1/kolide/packs/{id}", func(writer http.ResponseWriter, request *http.Request) {
r, err := decodeModifyPackRequest(context.Background(), request)
assert.Nil(t, err)
params := r.(modifyPackRequest)
assert.Equal(t, uint(1), params.ID)
assert.Equal(t, "foo", *params.payload.Name)
assert.Equal(t, "bar", *params.payload.Description)
require.NotNil(t, params.payload.HostIDs)
assert.Len(t, *params.payload.HostIDs, 3)
require.NotNil(t, params.payload.LabelIDs)
assert.Len(t, *params.payload.LabelIDs, 2)
}).Methods("PATCH")
var body bytes.Buffer
body.Write([]byte(`{
"name": "foo",
"description": "bar",
"host_ids": [1, 2, 3],
"label_ids": [1, 5]
}`))
router.ServeHTTP(
httptest.NewRecorder(),
httptest.NewRequest("PATCH", "/api/v1/kolide/packs/1", &body),
)
}
func TestDecodeDeletePackRequest(t *testing.T) {
router := mux.NewRouter()
router.HandleFunc("/api/v1/kolide/packs/{id}", func(writer http.ResponseWriter, request *http.Request) {

View file

@ -25,13 +25,12 @@ func NewQuery(t *testing.T, ds kolide.Datastore, name, q string, authorID uint,
}
func NewPack(t *testing.T, ds kolide.Datastore, name string) *kolide.Pack {
pack, err := ds.NewPack(&kolide.Pack{
Name: name,
})
err := ds.ApplyPackSpecs([]*kolide.PackSpec{&kolide.PackSpec{Name: name}})
require.Nil(t, err)
// Loading gives us the timestamps
pack, err = ds.Pack(pack.ID)
pack, ok, err := ds.PackByName(name)
require.True(t, ok)
require.Nil(t, err)
return pack
@ -104,15 +103,6 @@ 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 {
l, err := ds.NewLabel(&kolide.Label{Name: name, Query: query})
require.Nil(t, err)
require.NotZero(t, l.ID)
return l
}
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"),