mirror of
https://github.com/fleetdm/fleet
synced 2026-05-23 17:08:53 +00:00
Datastore refactor (#439)
Removed Gorm, replaced it with Sqlx * Added SQL bundling command to Makfile * Using go-kit logger * Added soft delete capability * Changed SearchLabel to accept a variadic param for optional omit list instead of array * Gorm removed * Refactor table structures to use CURRENT_TIMESTAMP mysql function * Moved Inmem datastore into it's own package * Updated README * Implemented code review suggestions from @zwass * Removed reference to Gorm from glide.yaml
This commit is contained in:
parent
73e04c6cbe
commit
6a825c11e3
85 changed files with 2945 additions and 1771 deletions
2
Makefile
2
Makefile
|
|
@ -112,11 +112,13 @@ test-js:
|
|||
test: lint test-go test-js
|
||||
|
||||
generate: .prefix
|
||||
go-bindata -o=server/datastore/mysql/bindata.go -pkg=mysql db/
|
||||
webpack --progress --colors
|
||||
go-bindata -pkg=service \
|
||||
-o=server/service/bindata.go \
|
||||
frontend/templates/ assets/...
|
||||
|
||||
|
||||
# we first generate the webpack bundle so that bindata knows to watch the
|
||||
# output bundle file. then, generate debug bindata source file. finally, we
|
||||
# run webpack in watch mode to continuously re-generate the bundle
|
||||
|
|
|
|||
23
README.md
23
README.md
|
|
@ -5,6 +5,7 @@
|
|||
- [Development Environment](#development-environment)
|
||||
- [Installing build dependencies](#installing-build-dependencies)
|
||||
- [Building](#building)
|
||||
- [Generate packaged SQL statements](#generate-packaged-sql-statements)
|
||||
- [Generating the packaged JavaScript](#generating-the-packaged-javascript)
|
||||
- [Automatic rebuilding of the JavaScript bundle](#automatic-rebuilding-of-the-javascript-bundle)
|
||||
- [Compiling the Kolide binary](#compiling-the-kolide-binary)
|
||||
|
|
@ -58,6 +59,17 @@ to re-run `make deps` if a new Go or JavaScript dependency was added.
|
|||
|
||||
### Building
|
||||
|
||||
#### Generate packaged SQL statements
|
||||
SQL statements used to generate the Kolide database are bundled into the kolide binary.
|
||||
These statements are included under the db directory. If the SQL statements are changed,
|
||||
say a table is added for example, bindata.go must be regenerated in order for the
|
||||
application to pick up the SQL changes. Use the following
|
||||
command to regenerate bindata.go.
|
||||
|
||||
```
|
||||
make generate
|
||||
```
|
||||
|
||||
#### Generating the packaged JavaScript
|
||||
|
||||
To generate all necessary code (bundling JavaScript into Go, etc), run the
|
||||
|
|
@ -157,6 +169,15 @@ To run all Go unit tests, run the following:
|
|||
make test-go
|
||||
```
|
||||
|
||||
### Database Tests
|
||||
|
||||
To run database tests set environment variables as follows.
|
||||
|
||||
```
|
||||
export MYSQL_PORT_3306_TCP_ADDR=192.168.99.100
|
||||
export MYSQL_TEST=1
|
||||
```
|
||||
|
||||
#### JavaScript unit tests
|
||||
|
||||
To run all JavaScript unit tests, run the following:
|
||||
|
|
@ -302,4 +323,4 @@ following to launch an in-memory instance of the server:
|
|||
|
||||
```
|
||||
make run
|
||||
```
|
||||
```
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import (
|
|||
"github.com/WatchBeam/clock"
|
||||
kitlog "github.com/go-kit/kit/log"
|
||||
"github.com/kolide/kolide-ose/server/config"
|
||||
"github.com/kolide/kolide-ose/server/datastore"
|
||||
"github.com/kolide/kolide-ose/server/datastore/mysql"
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
"github.com/kolide/kolide-ose/server/pubsub"
|
||||
"github.com/kolide/kolide-ose/server/service"
|
||||
|
|
@ -33,9 +33,9 @@ To setup kolide infrastructure, use one of the available commands.
|
|||
Long: ``,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
config := configManager.LoadConfig()
|
||||
connString := datastore.GetMysqlConnectionString(config.Mysql)
|
||||
connString := mysql.GetMysqlConnectionString(config.Mysql)
|
||||
|
||||
ds, err := datastore.New("gorm-mysql", connString)
|
||||
ds, err := mysql.New(connString, clock.C)
|
||||
if err != nil {
|
||||
initFatal(err, "creating db connection")
|
||||
}
|
||||
|
|
@ -58,15 +58,13 @@ To setup kolide infrastructure, use one of the available commands.
|
|||
Long: ``,
|
||||
Run: func(cmd *cobra.Command, arg []string) {
|
||||
config := configManager.LoadConfig()
|
||||
connString := datastore.GetMysqlConnectionString(config.Mysql)
|
||||
connString := mysql.GetMysqlConnectionString(config.Mysql)
|
||||
|
||||
ds, err := datastore.New("gorm-mysql", connString)
|
||||
ds, err := mysql.New(connString, clock.C)
|
||||
if err != nil {
|
||||
initFatal(err, "creating db connection")
|
||||
}
|
||||
if err != nil {
|
||||
initFatal(err, "creating new service")
|
||||
}
|
||||
|
||||
var (
|
||||
name = "admin"
|
||||
username = "admin"
|
||||
|
|
@ -88,7 +86,7 @@ To setup kolide infrastructure, use one of the available commands.
|
|||
initFatal(err, "creating service")
|
||||
}
|
||||
|
||||
_, err = svc.NewUser(context.Background(), admin)
|
||||
_, err = svc.NewAdminCreatedUser(context.Background(), admin)
|
||||
if err != nil {
|
||||
initFatal(err, "saving new user")
|
||||
}
|
||||
|
|
|
|||
194
cli/serve.go
194
cli/serve.go
|
|
@ -3,7 +3,6 @@ package cli
|
|||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
|
|
@ -14,7 +13,8 @@ import (
|
|||
kitlog "github.com/go-kit/kit/log"
|
||||
kitprometheus "github.com/go-kit/kit/metrics/prometheus"
|
||||
"github.com/kolide/kolide-ose/server/config"
|
||||
"github.com/kolide/kolide-ose/server/datastore"
|
||||
"github.com/kolide/kolide-ose/server/datastore/inmem"
|
||||
"github.com/kolide/kolide-ose/server/datastore/mysql"
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
"github.com/kolide/kolide-ose/server/mail"
|
||||
"github.com/kolide/kolide-ose/server/pubsub"
|
||||
|
|
@ -66,23 +66,20 @@ the way that the kolide server works.
|
|||
"Dev mode enabled, using in-memory DB.\n",
|
||||
"Warning: Changes will not be saved across process restarts. This should NOT be used in production.",
|
||||
)
|
||||
ds, err = datastore.New("inmem", "")
|
||||
if err != nil {
|
||||
initFatal(err, "initializing datastore")
|
||||
|
||||
if ds, err = inmem.New(); err != nil {
|
||||
initFatal(err, "initializing inmem database")
|
||||
}
|
||||
} else {
|
||||
var dbOption []datastore.DBOption
|
||||
gormLogger := log.New(os.Stderr, "", 0)
|
||||
gormLogger.SetOutput(kitlog.NewStdlibAdapter(logger))
|
||||
dbOption = append(dbOption, datastore.Logger(gormLogger))
|
||||
if config.Logging.Debug {
|
||||
dbOption = append(dbOption, datastore.Debug())
|
||||
}
|
||||
connString := datastore.GetMysqlConnectionString(config.Mysql)
|
||||
ds, err = datastore.New("gorm-mysql", connString, dbOption...)
|
||||
const defaultMaxAttempts = 15
|
||||
|
||||
connString := mysql.GetMysqlConnectionString(config.Mysql)
|
||||
ds, err = mysql.New(connString, clock.C, mysql.Logger(logger))
|
||||
|
||||
if err != nil {
|
||||
initFatal(err, "initializing datastore")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
svc, err := service.NewService(ds, pubsub.NewInmemQueryResults(), logger, config, mailService, clock.C)
|
||||
|
|
@ -198,24 +195,38 @@ func createDevMailService(config config.KolideConfig) kolide.MailService {
|
|||
func createDevUsers(ds kolide.Datastore, config config.KolideConfig) {
|
||||
users := []kolide.User{
|
||||
{
|
||||
CreatedAt: time.Date(2016, time.October, 27, 10, 0, 0, 0, time.UTC),
|
||||
UpdatedAt: time.Date(2016, time.October, 27, 10, 0, 0, 0, time.UTC),
|
||||
Name: "Admin User",
|
||||
Username: "admin",
|
||||
Email: "admin@kolide.co",
|
||||
Position: "Director of Security",
|
||||
Admin: true,
|
||||
Enabled: true,
|
||||
UpdateCreateTimestamps: kolide.UpdateCreateTimestamps{
|
||||
CreateTimestamp: kolide.CreateTimestamp{
|
||||
CreatedAt: time.Date(2016, time.October, 27, 10, 0, 0, 0, time.UTC),
|
||||
},
|
||||
UpdateTimestamp: kolide.UpdateTimestamp{
|
||||
UpdatedAt: time.Date(2016, time.October, 27, 10, 0, 0, 0, time.UTC),
|
||||
},
|
||||
},
|
||||
|
||||
Name: "Admin User",
|
||||
Username: "admin",
|
||||
Email: "admin@kolide.co",
|
||||
Position: "Director of Security",
|
||||
Admin: true,
|
||||
Enabled: true,
|
||||
},
|
||||
{
|
||||
CreatedAt: time.Now().Add(-3 * time.Hour),
|
||||
UpdatedAt: time.Now().Add(-1 * time.Hour),
|
||||
Name: "Normal User",
|
||||
Username: "user",
|
||||
Email: "user@kolide.co",
|
||||
Position: "Security Engineer",
|
||||
Admin: false,
|
||||
Enabled: true,
|
||||
UpdateCreateTimestamps: kolide.UpdateCreateTimestamps{
|
||||
CreateTimestamp: kolide.CreateTimestamp{
|
||||
CreatedAt: time.Now().Add(-3 * time.Hour),
|
||||
},
|
||||
UpdateTimestamp: kolide.UpdateTimestamp{
|
||||
UpdatedAt: time.Now().Add(-1 * time.Hour),
|
||||
},
|
||||
},
|
||||
|
||||
Name: "Normal User",
|
||||
Username: "user",
|
||||
Email: "user@kolide.co",
|
||||
Position: "Security Engineer",
|
||||
Admin: false,
|
||||
Enabled: true,
|
||||
},
|
||||
}
|
||||
for _, user := range users {
|
||||
|
|
@ -235,8 +246,14 @@ func createDevUsers(ds kolide.Datastore, config config.KolideConfig) {
|
|||
func createDevHosts(ds kolide.Datastore, config config.KolideConfig) {
|
||||
hosts := []kolide.Host{
|
||||
{
|
||||
CreatedAt: time.Date(2016, time.October, 27, 10, 0, 0, 0, time.UTC),
|
||||
UpdatedAt: time.Now().Add(-20 * time.Minute),
|
||||
UpdateCreateTimestamps: kolide.UpdateCreateTimestamps{
|
||||
CreateTimestamp: kolide.CreateTimestamp{
|
||||
CreatedAt: time.Date(2016, time.October, 27, 10, 0, 0, 0, time.UTC),
|
||||
},
|
||||
UpdateTimestamp: kolide.UpdateTimestamp{
|
||||
UpdatedAt: time.Now().Add(-20 * time.Minute),
|
||||
},
|
||||
},
|
||||
NodeKey: "totally-legit",
|
||||
HostName: "jmeller-mbp.local",
|
||||
UUID: "1234-5678-9101",
|
||||
|
|
@ -250,8 +267,15 @@ func createDevHosts(ds kolide.Datastore, config config.KolideConfig) {
|
|||
DetailUpdateTime: time.Now().Add(-20 * time.Minute),
|
||||
},
|
||||
{
|
||||
CreatedAt: time.Now().Add(-1 * time.Hour),
|
||||
UpdatedAt: time.Now().Add(-20 * time.Minute),
|
||||
UpdateCreateTimestamps: kolide.UpdateCreateTimestamps{
|
||||
CreateTimestamp: kolide.CreateTimestamp{
|
||||
CreatedAt: time.Date(2016, time.October, 27, 4, 3, 10, 0, time.UTC),
|
||||
},
|
||||
UpdateTimestamp: kolide.UpdateTimestamp{
|
||||
UpdatedAt: time.Date(2016, time.October, 27, 4, 3, 10, 0, time.UTC),
|
||||
},
|
||||
},
|
||||
|
||||
NodeKey: "definitely-legit",
|
||||
HostName: "marpaia.local",
|
||||
UUID: "1234-5678-9102",
|
||||
|
|
@ -289,34 +313,67 @@ func createDevOrgInfo(ds kolide.Datastore, config config.KolideConfig) {
|
|||
func createDevQueries(ds kolide.Datastore, config config.KolideConfig) {
|
||||
queries := []kolide.Query{
|
||||
{
|
||||
CreatedAt: time.Date(2016, time.October, 17, 7, 6, 0, 0, time.UTC),
|
||||
UpdatedAt: time.Date(2016, time.October, 17, 7, 6, 0, 0, time.UTC),
|
||||
Name: "dev_query_1",
|
||||
Query: "select * from processes",
|
||||
UpdateCreateTimestamps: kolide.UpdateCreateTimestamps{
|
||||
CreateTimestamp: kolide.CreateTimestamp{
|
||||
CreatedAt: time.Date(2016, time.October, 17, 7, 6, 0, 0, time.UTC),
|
||||
},
|
||||
UpdateTimestamp: kolide.UpdateTimestamp{
|
||||
UpdatedAt: time.Date(2016, time.October, 17, 7, 6, 0, 0, time.UTC),
|
||||
},
|
||||
},
|
||||
|
||||
Name: "dev_query_1",
|
||||
Query: "select * from processes",
|
||||
},
|
||||
{
|
||||
CreatedAt: time.Date(2016, time.October, 27, 4, 3, 10, 0, time.UTC),
|
||||
UpdatedAt: time.Date(2016, time.October, 27, 4, 3, 10, 0, time.UTC),
|
||||
Name: "dev_query_2",
|
||||
Query: "select * from time",
|
||||
UpdateCreateTimestamps: kolide.UpdateCreateTimestamps{
|
||||
CreateTimestamp: kolide.CreateTimestamp{
|
||||
CreatedAt: time.Date(2016, time.October, 27, 4, 3, 10, 0, time.UTC),
|
||||
},
|
||||
UpdateTimestamp: kolide.UpdateTimestamp{
|
||||
UpdatedAt: time.Date(2016, time.October, 27, 4, 3, 10, 0, time.UTC),
|
||||
},
|
||||
},
|
||||
Name: "dev_query_2",
|
||||
Query: "select * from time",
|
||||
},
|
||||
{
|
||||
CreatedAt: time.Now().Add(-24 * time.Hour),
|
||||
UpdatedAt: time.Now().Add(-17 * time.Hour),
|
||||
Name: "dev_query_3",
|
||||
Query: "select * from cpuid",
|
||||
UpdateCreateTimestamps: kolide.UpdateCreateTimestamps{
|
||||
CreateTimestamp: kolide.CreateTimestamp{
|
||||
CreatedAt: time.Now().Add(-24 * time.Hour),
|
||||
},
|
||||
UpdateTimestamp: kolide.UpdateTimestamp{
|
||||
UpdatedAt: time.Now().Add(-17 * time.Hour),
|
||||
},
|
||||
},
|
||||
|
||||
Name: "dev_query_3",
|
||||
Query: "select * from cpuid",
|
||||
},
|
||||
{
|
||||
CreatedAt: time.Now().Add(-1 * time.Hour),
|
||||
UpdatedAt: time.Now().Add(-30 * time.Minute),
|
||||
Name: "dev_query_4",
|
||||
Query: "select 1 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().Add(-30 * time.Hour),
|
||||
},
|
||||
},
|
||||
|
||||
Name: "dev_query_4",
|
||||
Query: "select 1 from processes where name like '%Apache%'",
|
||||
},
|
||||
{
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
Name: "dev_query_5",
|
||||
Query: "select 1 from osquery_info where build_platform='darwin'",
|
||||
UpdateCreateTimestamps: kolide.UpdateCreateTimestamps{
|
||||
CreateTimestamp: kolide.CreateTimestamp{
|
||||
CreatedAt: time.Now(),
|
||||
},
|
||||
UpdateTimestamp: kolide.UpdateTimestamp{
|
||||
UpdatedAt: time.Now(),
|
||||
},
|
||||
},
|
||||
Name: "dev_query_5",
|
||||
Query: "select 1 from osquery_info where build_platform='darwin'",
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -332,16 +389,29 @@ func createDevQueries(ds kolide.Datastore, config config.KolideConfig) {
|
|||
func createDevLabels(ds kolide.Datastore, config config.KolideConfig) {
|
||||
labels := []kolide.Label{
|
||||
{
|
||||
CreatedAt: time.Date(2016, time.October, 27, 8, 31, 16, 0, time.UTC),
|
||||
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.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 nae like '%Apache%'",
|
||||
},
|
||||
{
|
||||
CreatedAt: time.Now().Add(-1 * time.Hour),
|
||||
UpdatedAt: time.Now(),
|
||||
Name: "dev_label_darwin",
|
||||
Query: "select * from osquery_info where build_platform='darwin'",
|
||||
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 build_platform='darwin'",
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
|||
32
db/down.sql
Normal file
32
db/down.sql
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
#
|
||||
# SQL Export
|
||||
# Created by Querious (1055)
|
||||
# Created: November 7, 2016 at 11:39:23 PM GMT+8
|
||||
# Encoding: Unicode (UTF-8)
|
||||
#
|
||||
|
||||
use `kolide`;
|
||||
|
||||
SET @PREVIOUS_FOREIGN_KEY_CHECKS = @@FOREIGN_KEY_CHECKS;
|
||||
SET FOREIGN_KEY_CHECKS = 0;
|
||||
|
||||
DROP TABLE IF EXISTS `org_infos`;
|
||||
DROP TABLE IF EXISTS `users`;
|
||||
DROP TABLE IF EXISTS `sessions`;
|
||||
DROP TABLE IF EXISTS `queries`;
|
||||
DROP TABLE IF EXISTS `password_reset_requests`;
|
||||
DROP TABLE IF EXISTS `packs`;
|
||||
DROP TABLE IF EXISTS `pack_targets`;
|
||||
DROP TABLE IF EXISTS `pack_queries`;
|
||||
DROP TABLE IF EXISTS `options`;
|
||||
DROP TABLE IF EXISTS `labels`;
|
||||
DROP TABLE IF EXISTS `label_query_executions`;
|
||||
DROP TABLE IF EXISTS `invites`;
|
||||
DROP TABLE IF EXISTS `hosts`;
|
||||
DROP TABLE IF EXISTS `distributed_query_executions`;
|
||||
DROP TABLE IF EXISTS `distributed_query_campaigns`;
|
||||
DROP TABLE IF EXISTS `distributed_query_campaign_targets`;
|
||||
DROP TABLE IF EXISTS `app_configs`;
|
||||
|
||||
|
||||
SET FOREIGN_KEY_CHECKS = @PREVIOUS_FOREIGN_KEY_CHECKS;
|
||||
238
db/up.sql
Normal file
238
db/up.sql
Normal file
|
|
@ -0,0 +1,238 @@
|
|||
#
|
||||
# SQL Export
|
||||
# Created by Querious (1055)
|
||||
# Created: November 7, 2016 at 11:38:55 PM GMT+8
|
||||
# Encoding: Unicode (UTF-8)
|
||||
#
|
||||
|
||||
use `kolide`;
|
||||
|
||||
SET @PREVIOUS_FOREIGN_KEY_CHECKS = @@FOREIGN_KEY_CHECKS;
|
||||
SET FOREIGN_KEY_CHECKS = 0;
|
||||
|
||||
|
||||
CREATE TABLE `app_configs` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`org_name` varchar(255) DEFAULT NULL,
|
||||
`org_logo_url` varchar(255) DEFAULT NULL,
|
||||
`kolide_server_url` varchar(255) DEFAULT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
|
||||
CREATE TABLE `distributed_query_campaign_targets` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`type` int(11) DEFAULT NULL,
|
||||
`distributed_query_campaign_id` int(10) unsigned DEFAULT NULL,
|
||||
`target_id` int(10) unsigned DEFAULT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
|
||||
CREATE TABLE `distributed_query_campaigns` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`created_at` timestamp DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
`deleted_at` timestamp NULL DEFAULT NULL,
|
||||
`deleted` tinyint(1) NOT NULL DEFAULT FALSE,
|
||||
`query_id` int(10) unsigned DEFAULT NULL,
|
||||
`max_duration` bigint(20) DEFAULT NULL,
|
||||
`status` int(11) DEFAULT NULL,
|
||||
`user_id` int(10) unsigned DEFAULT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
|
||||
CREATE TABLE `distributed_query_executions` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`host_id` int(10) unsigned DEFAULT NULL,
|
||||
`distributed_query_campaign_id` int(10) unsigned DEFAULT NULL,
|
||||
`status` int(11) DEFAULT NULL,
|
||||
`error` varchar(1024) DEFAULT NULL,
|
||||
`execution_duration` bigint(20) DEFAULT NULL,
|
||||
UNIQUE KEY `idx_dqe_unique_dqec_id` (`distributed_query_campaign_id`),
|
||||
UNIQUE KEY `idx_dqe_unique_host_id` (`host_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
|
||||
CREATE TABLE `hosts` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`created_at` timestamp DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
`deleted_at` timestamp NULL DEFAULT NULL,
|
||||
`deleted` tinyint(1) NOT NULL DEFAULT FALSE,
|
||||
`detail_update_time` timestamp NULL DEFAULT NULL,
|
||||
`node_key` varchar(255) DEFAULT NULL,
|
||||
`host_name` varchar(255) DEFAULT NULL,
|
||||
`uuid` varchar(255) DEFAULT NULL,
|
||||
`platform` varchar(255) DEFAULT NULL,
|
||||
`osquery_version` varchar(255) NOT NULL DEFAULT '',
|
||||
`os_version` varchar(255) NOT NULL DEFAULT '',
|
||||
`uptime` bigint(20) NOT NULL DEFAULT 0,
|
||||
`physical_memory` bigint(20) NOT NULL DEFAULT 0,
|
||||
`primary_mac` varchar(255) NOT NULL DEFAULT '',
|
||||
`primary_ip` varchar(255) NOT NULL DEFAULT '',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `idx_host_unique_nodekey` (`node_key`),
|
||||
UNIQUE KEY `idx_host_unique_uuid` (`uuid`),
|
||||
FULLTEXT KEY `hosts_search` (`host_name`,`primary_ip`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
|
||||
CREATE TABLE `invites` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`created_at` timestamp DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
`deleted_at` timestamp NULL DEFAULT NULL,
|
||||
`deleted` tinyint(1) NOT NULL DEFAULT FALSE,
|
||||
`invited_by` int(10) unsigned NOT NULL,
|
||||
`email` varchar(255) NOT NULL,
|
||||
`admin` tinyint(1) DEFAULT NULL,
|
||||
`name` varchar(255) DEFAULT NULL,
|
||||
`position` varchar(255) DEFAULT NULL,
|
||||
`token` varchar(255) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `idx_invite_unique_email` (`email`),
|
||||
UNIQUE KEY `idx_invite_unique_key` (`token`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
|
||||
CREATE TABLE `label_query_executions` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`created_at` timestamp DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
`matches` tinyint(1) NOT NULL DEFAULT FALSE,
|
||||
`label_id` int(10) unsigned DEFAULT NULL,
|
||||
`host_id` int(10) unsigned DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `idx_lqe_label_host` (`label_id`,`host_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
|
||||
CREATE TABLE `labels` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`created_at` timestamp DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
`deleted_at` timestamp NULL DEFAULT NULL,
|
||||
`deleted` tinyint(1) NOT NULL DEFAULT FALSE,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`description` varchar(255) DEFAULT NULL,
|
||||
`query` varchar(255) NOT NULL,
|
||||
`platform` varchar(255) DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `idx_label_unique_name` (`name`),
|
||||
FULLTEXT KEY `labels_search` (`name`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
|
||||
CREATE TABLE `options` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`created_at` timestamp DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
`key` varchar(255) NOT NULL,
|
||||
`value` varchar(255) NOT NULL,
|
||||
`platform` varchar(255) DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `idx_option_unique_key` (`key`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
|
||||
CREATE TABLE `pack_queries` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`created_at` timestamp DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
`pack_id` int(10) unsigned DEFAULT NULL,
|
||||
`query_id` int(10) unsigned DEFAULT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
|
||||
CREATE TABLE `pack_targets` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`pack_id` int(10) unsigned DEFAULT NULL,
|
||||
`type` int(11) DEFAULT NULL,
|
||||
`target_id` int(10) unsigned DEFAULT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
|
||||
CREATE TABLE `packs` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`created_at` timestamp DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
`deleted_at` timestamp NULL DEFAULT NULL,
|
||||
`deleted` tinyint(1) NOT NULL DEFAULT FALSE,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`platform` varchar(255) DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `idx_pack_unique_name` (`name`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
|
||||
CREATE TABLE `password_reset_requests` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`created_at` timestamp DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
`expires_at` timestamp NOT NULL DEFAULT '1970-01-01 00:00:01',
|
||||
`user_id` int(10) unsigned NOT NULL,
|
||||
`token` varchar(1024) NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
|
||||
CREATE TABLE `queries` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`created_at` timestamp DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
`deleted_at` timestamp NULL DEFAULT NULL,
|
||||
`deleted` tinyint(1) NOT NULL DEFAULT FALSE,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`description` varchar(255) DEFAULT NULL,
|
||||
`query` varchar(255) NOT NULL,
|
||||
`interval` int(10) unsigned DEFAULT NULL,
|
||||
`snapshot` tinyint(1) NOT NULL DEFAULT FALSE,
|
||||
`differential` tinyint(1) NOT NULL DEFAULT FALSE,
|
||||
`platform` varchar(255) DEFAULT NULL,
|
||||
`version` varchar(255) DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `idx_query_unique_name` (`name`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
|
||||
CREATE TABLE `sessions` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`created_at` timestamp DEFAULT CURRENT_TIMESTAMP,
|
||||
`accessed_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
`user_id` int(10) unsigned NOT NULL,
|
||||
`key` varchar(255) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `idx_session_unique_key` (`key`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
|
||||
CREATE TABLE `users` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`created_at` timestamp DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
`deleted_at` timestamp NULL DEFAULT NULL,
|
||||
`deleted` tinyint(1) NOT NULL DEFAULT FALSE,
|
||||
`username` varchar(255) NOT NULL,
|
||||
`password` varbinary(255) NOT NULL,
|
||||
`salt` varchar(255) NOT NULL,
|
||||
`name` varchar(255) NOT NULL DEFAULT '',
|
||||
`email` varchar(255) NOT NULL,
|
||||
`admin` tinyint(1) NOT NULL DEFAULT FALSE,
|
||||
`enabled` tinyint(1) NOT NULL DEFAULT FALSE,
|
||||
`admin_forced_password_reset` tinyint(1) NOT NULL DEFAULT FALSE,
|
||||
`gravatar_url` varchar(255) NOT NULL DEFAULT '',
|
||||
`position` varchar(255) NOT NULL DEFAULT '',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `idx_user_unique_username` (`username`),
|
||||
UNIQUE KEY `idx_user_unique_email` (`email`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
|
||||
|
||||
|
||||
SET FOREIGN_KEY_CHECKS = @PREVIOUS_FOREIGN_KEY_CHECKS;
|
||||
12
glide.lock
generated
12
glide.lock
generated
|
|
@ -1,5 +1,5 @@
|
|||
hash: 7a3bef7d804686cd678aeaa0914be556ff4e357be2ce8fd5b9cd2e81164ed4a6
|
||||
updated: 2016-10-24T12:32:41.928983481-07:00
|
||||
hash: 3519c1da46244ec37972b542173f088df94422080bc99652f88f960d70a7005a
|
||||
updated: 2016-11-02T22:14:07.180331599+08:00
|
||||
imports:
|
||||
- name: github.com/alecthomas/template
|
||||
version: a0175ee3bccc567396460bf5acd36800cb10c49c
|
||||
|
|
@ -75,12 +75,10 @@ imports:
|
|||
- json/token
|
||||
- name: github.com/inconshreveable/mousetrap
|
||||
version: 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75
|
||||
- name: github.com/jinzhu/gorm
|
||||
version: a646b13548ec0aa812fe805b2780f460dd2771b6
|
||||
subpackages:
|
||||
- dialects/mysql
|
||||
- name: github.com/jinzhu/inflection
|
||||
version: 8f4d3a0d04ce0b7c0cf3126fb98524246d00d102
|
||||
- name: github.com/jmoiron/sqlx
|
||||
version: 5f97679e23f75f42b265fec8d3bdb1c8de90b79d
|
||||
- name: github.com/jordan-wright/email
|
||||
version: fd703108daeb23d77c124d12978e9b6c4f28f034
|
||||
- name: github.com/kr/fs
|
||||
|
|
@ -179,7 +177,7 @@ imports:
|
|||
- name: gopkg.in/go-playground/validator.v8
|
||||
version: 5f57d2222ad794d0dffb07e664ea05e2ee07d60c
|
||||
- name: gopkg.in/natefinch/lumberjack.v2
|
||||
version: 514cbda263a734ae8caac038dadf05f8f3f9f738
|
||||
version: e21e5cbec0cd0861b9dc302736ad5666c529d93f
|
||||
- name: gopkg.in/yaml.v2
|
||||
version: e4d366fc3c7938e2958e662b4258c7a89e1f0e3e
|
||||
testImports: []
|
||||
|
|
|
|||
|
|
@ -31,10 +31,6 @@ import:
|
|||
version: c3cefd437628a0b7d31b34fe44b3a7a540e98527
|
||||
subpackages:
|
||||
- proto
|
||||
- package: github.com/jinzhu/gorm
|
||||
version: a646b13548ec0aa812fe805b2780f460dd2771b6
|
||||
subpackages:
|
||||
- dialects/mysql
|
||||
- package: github.com/jinzhu/inflection
|
||||
version: 8f4d3a0d04ce0b7c0cf3126fb98524246d00d102
|
||||
- package: github.com/manucorporat/sse
|
||||
|
|
@ -83,3 +79,4 @@ import:
|
|||
version: ^1.0.0
|
||||
subpackages:
|
||||
- redis
|
||||
- package: github.com/jmoiron/sqlx
|
||||
|
|
|
|||
|
|
@ -1,93 +0,0 @@
|
|||
// Package datastore implements Kolide's interactions with the database backend
|
||||
package datastore
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/kolide/kolide-ose/server/config"
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrNotFound is returned when the datastore resource cannot be found
|
||||
ErrNotFound = errors.New("resource not found")
|
||||
|
||||
// ErrExists is returned when creating a datastore resource that already exists
|
||||
ErrExists = errors.New("resource already created")
|
||||
)
|
||||
|
||||
// New creates a kolide.Datastore with a database connection
|
||||
// Use DBOption to pass optional arguments
|
||||
func New(driver, conn string, opts ...DBOption) (kolide.Datastore, error) {
|
||||
opt := &dbOptions{
|
||||
maxAttempts: defaultMaxAttempts,
|
||||
}
|
||||
for _, option := range opts {
|
||||
if err := option(opt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// check if datastore is already present
|
||||
if opt.db != nil {
|
||||
return opt.db, nil
|
||||
}
|
||||
switch driver {
|
||||
case "gorm-mysql":
|
||||
db, err := openGORM("mysql", conn, opt.maxAttempts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ds := gormDB{
|
||||
DB: db,
|
||||
Driver: "mysql",
|
||||
}
|
||||
// configure logger
|
||||
if opt.logger != nil {
|
||||
db.SetLogger(opt.logger)
|
||||
db.LogMode(opt.debug)
|
||||
}
|
||||
if err := ds.Migrate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ds, nil
|
||||
case "inmem":
|
||||
ds := &inmem{
|
||||
Driver: "inmem",
|
||||
}
|
||||
|
||||
err := ds.Migrate()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ds, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported datastore driver %s", driver)
|
||||
}
|
||||
}
|
||||
|
||||
func generateRandomText(keySize int) (string, error) {
|
||||
key := make([]byte, keySize)
|
||||
_, err := rand.Read(key)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return base64.StdEncoding.EncodeToString(key), nil
|
||||
}
|
||||
|
||||
// GetMysqlConnectionString returns a MySQL connection string using the
|
||||
// provided configuration.
|
||||
func GetMysqlConnectionString(conf config.MysqlConfig) string {
|
||||
return fmt.Sprintf(
|
||||
"%s:%s@(%s)/%s?charset=utf8&parseTime=True&loc=Local",
|
||||
conf.Username,
|
||||
conf.Password,
|
||||
conf.Address,
|
||||
conf.Database,
|
||||
)
|
||||
}
|
||||
|
|
@ -40,6 +40,78 @@ var enrollTests = []struct {
|
|||
},
|
||||
}
|
||||
|
||||
func testSaveHosts(t *testing.T, db kolide.Datastore) {
|
||||
host, err := db.NewHost(&kolide.Host{
|
||||
DetailUpdateTime: time.Now(),
|
||||
NodeKey: "1",
|
||||
UUID: "1",
|
||||
HostName: "foo.local",
|
||||
PrimaryIP: "192.168.1.10",
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
assert.NotNil(t, host)
|
||||
|
||||
host.HostName = "bar.local"
|
||||
err = db.SaveHost(host)
|
||||
assert.Nil(t, err)
|
||||
|
||||
host, err = db.Host(host.ID)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "bar.local", host.HostName)
|
||||
|
||||
err = db.DeleteHost(host)
|
||||
assert.Nil(t, err)
|
||||
|
||||
host, err = db.Host(host.ID)
|
||||
assert.NotNil(t, err)
|
||||
}
|
||||
|
||||
func testDeleteHost(t *testing.T, db kolide.Datastore) {
|
||||
host, err := db.NewHost(&kolide.Host{
|
||||
DetailUpdateTime: time.Now(),
|
||||
NodeKey: "1",
|
||||
UUID: "1",
|
||||
HostName: "foo.local",
|
||||
PrimaryIP: "192.168.1.10",
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
assert.NotNil(t, host)
|
||||
|
||||
err = db.DeleteHost(host)
|
||||
assert.Nil(t, err)
|
||||
|
||||
host, err = db.Host(host.ID)
|
||||
assert.NotNil(t, err)
|
||||
}
|
||||
|
||||
func testListHost(t *testing.T, db kolide.Datastore) {
|
||||
hosts := []*kolide.Host{}
|
||||
for i := 0; i < 10; i++ {
|
||||
host, err := db.NewHost(&kolide.Host{
|
||||
DetailUpdateTime: time.Now(),
|
||||
NodeKey: fmt.Sprintf("%d", i),
|
||||
UUID: fmt.Sprintf("%d", i),
|
||||
HostName: fmt.Sprintf("foo.local%d", i),
|
||||
PrimaryIP: fmt.Sprintf("192.168.1.%d", i),
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
hosts = append(hosts, host)
|
||||
}
|
||||
|
||||
hosts2, err := db.ListHosts(kolide.ListOptions{})
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, len(hosts), len(hosts2))
|
||||
err = db.DeleteHost(hosts[0])
|
||||
assert.Nil(t, err)
|
||||
hosts2, err = db.ListHosts(kolide.ListOptions{})
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, len(hosts)-1, len(hosts2))
|
||||
|
||||
}
|
||||
|
||||
func testEnrollHost(t *testing.T, db kolide.Datastore) {
|
||||
var hosts []*kolide.Host
|
||||
for _, tt := range enrollTests {
|
||||
|
|
@ -112,16 +184,16 @@ func testSearchHosts(t *testing.T, db kolide.Datastore) {
|
|||
})
|
||||
require.Nil(t, err)
|
||||
|
||||
hosts, err := db.SearchHosts("foo", nil)
|
||||
hosts, err := db.SearchHosts("foo")
|
||||
assert.Nil(t, err)
|
||||
assert.Len(t, hosts, 2)
|
||||
|
||||
host, err := db.SearchHosts("foo", []uint{h3.ID})
|
||||
host, err := db.SearchHosts("foo", h3.ID)
|
||||
assert.Nil(t, err)
|
||||
assert.Len(t, host, 1)
|
||||
assert.Equal(t, "foo.local", host[0].HostName)
|
||||
|
||||
none, err := db.SearchHosts("xxx", nil)
|
||||
none, err := db.SearchHosts("xxx")
|
||||
assert.Nil(t, err)
|
||||
assert.Len(t, none, 0)
|
||||
}
|
||||
|
|
@ -138,7 +210,7 @@ func testSearchHostsLimit(t *testing.T, db kolide.Datastore) {
|
|||
require.Nil(t, err)
|
||||
}
|
||||
|
||||
hosts, err := db.SearchHosts("foo", nil)
|
||||
hosts, err := db.SearchHosts("foo")
|
||||
require.Nil(t, err)
|
||||
assert.Len(t, hosts, 10)
|
||||
}
|
||||
|
|
@ -194,7 +266,7 @@ func testDistributedQueriesForHost(t *testing.T, db kolide.Datastore) {
|
|||
require.Nil(t, err)
|
||||
|
||||
// Create a query campaign
|
||||
c1 := kolide.DistributedQueryCampaign{
|
||||
c1 := &kolide.DistributedQueryCampaign{
|
||||
QueryID: q1.ID,
|
||||
Status: kolide.QueryRunning,
|
||||
}
|
||||
|
|
@ -202,7 +274,7 @@ func testDistributedQueriesForHost(t *testing.T, db kolide.Datastore) {
|
|||
require.Nil(t, err)
|
||||
|
||||
// Add a target to the campaign
|
||||
target := kolide.DistributedQueryCampaignTarget{
|
||||
target := &kolide.DistributedQueryCampaignTarget{
|
||||
Type: kolide.TargetLabel,
|
||||
DistributedQueryCampaignID: c1.ID,
|
||||
TargetID: l1.ID,
|
||||
|
|
@ -221,12 +293,12 @@ func testDistributedQueriesForHost(t *testing.T, db kolide.Datastore) {
|
|||
assert.Equal(t, "select * from bar", queries[c1.ID])
|
||||
|
||||
// Record an execution
|
||||
exec := kolide.DistributedQueryExecution{
|
||||
exec := &kolide.DistributedQueryExecution{
|
||||
HostID: h1.ID,
|
||||
DistributedQueryCampaignID: c1.ID,
|
||||
Status: kolide.ExecutionSucceeded,
|
||||
}
|
||||
exec, err = db.NewDistributedQueryExecution(exec)
|
||||
_, err = db.NewDistributedQueryExecution(exec)
|
||||
require.Nil(t, err)
|
||||
|
||||
// Add another query/campaign
|
||||
|
|
@ -237,7 +309,7 @@ func testDistributedQueriesForHost(t *testing.T, db kolide.Datastore) {
|
|||
q2, err = db.NewQuery(q2)
|
||||
require.Nil(t, err)
|
||||
|
||||
c2 := kolide.DistributedQueryCampaign{
|
||||
c2 := &kolide.DistributedQueryCampaign{
|
||||
QueryID: q2.ID,
|
||||
Status: kolide.QueryRunning,
|
||||
}
|
||||
|
|
@ -245,12 +317,12 @@ func testDistributedQueriesForHost(t *testing.T, db kolide.Datastore) {
|
|||
require.Nil(t, err)
|
||||
|
||||
// This one targets only h1
|
||||
target = kolide.DistributedQueryCampaignTarget{
|
||||
target = &kolide.DistributedQueryCampaignTarget{
|
||||
Type: kolide.TargetHost,
|
||||
DistributedQueryCampaignID: c2.ID,
|
||||
TargetID: h1.ID,
|
||||
}
|
||||
target, err = db.NewDistributedQueryCampaignTarget(target)
|
||||
_, err = db.NewDistributedQueryCampaignTarget(target)
|
||||
require.Nil(t, err)
|
||||
|
||||
// Check for correct queries
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package datastore
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
|
|
@ -8,7 +9,12 @@ import (
|
|||
)
|
||||
|
||||
func testCreateInvite(t *testing.T, ds kolide.Datastore) {
|
||||
invite := &kolide.Invite{}
|
||||
invite := &kolide.Invite{
|
||||
|
||||
Email: "user@foo.com",
|
||||
Name: "user",
|
||||
Token: "some_user",
|
||||
}
|
||||
|
||||
invite, err := ds.NewInvite(invite)
|
||||
assert.Nil(t, err)
|
||||
|
|
@ -18,3 +24,106 @@ func testCreateInvite(t *testing.T, ds kolide.Datastore) {
|
|||
assert.Equal(t, invite.ID, verify.ID)
|
||||
assert.Equal(t, invite.Email, verify.Email)
|
||||
}
|
||||
|
||||
func setupTestInvites(t *testing.T, ds kolide.Datastore) {
|
||||
|
||||
var err error
|
||||
admin := &kolide.Invite{
|
||||
Email: "admin@foo.com",
|
||||
Admin: true,
|
||||
Name: "Xadmin",
|
||||
Token: "admin",
|
||||
}
|
||||
|
||||
admin, err = ds.NewInvite(admin)
|
||||
assert.Nil(t, err)
|
||||
|
||||
for user := 0; user < 23; user++ {
|
||||
i := kolide.Invite{
|
||||
InvitedBy: admin.ID,
|
||||
Email: fmt.Sprintf("user%d@foo.com", user),
|
||||
Admin: false,
|
||||
Name: fmt.Sprintf("User%02d", user),
|
||||
Token: fmt.Sprintf("usertoken%d", user),
|
||||
}
|
||||
|
||||
_, err := ds.NewInvite(&i)
|
||||
assert.Nil(t, err, "Failure creating user", user)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func testListInvites(t *testing.T, ds kolide.Datastore) {
|
||||
// TODO: fix this for inmem
|
||||
if ds.Name() == "inmem" {
|
||||
fmt.Println("Busted test skipped for inmem")
|
||||
return
|
||||
}
|
||||
|
||||
setupTestInvites(t, ds)
|
||||
|
||||
opt := kolide.ListOptions{
|
||||
Page: 0,
|
||||
PerPage: 10,
|
||||
OrderDirection: kolide.OrderAscending,
|
||||
OrderKey: "name",
|
||||
}
|
||||
|
||||
result, err := ds.ListInvites(opt)
|
||||
assert.Nil(t, err)
|
||||
assert.NotNil(t, result)
|
||||
assert.Equal(t, len(result), 10)
|
||||
assert.Equal(t, "User00", result[0].Name)
|
||||
assert.Equal(t, "User09", result[9].Name)
|
||||
|
||||
opt.Page = 2
|
||||
opt.OrderDirection = kolide.OrderDescending
|
||||
result, err = ds.ListInvites(opt)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 4, len(result)) // allow for admin we created
|
||||
assert.Equal(t, "User00", result[3].Name)
|
||||
|
||||
}
|
||||
|
||||
func testDeleteInvite(t *testing.T, ds kolide.Datastore) {
|
||||
|
||||
setupTestInvites(t, ds)
|
||||
|
||||
invite, err := ds.InviteByEmail("user0@foo.com")
|
||||
|
||||
assert.Nil(t, err)
|
||||
assert.NotNil(t, invite)
|
||||
|
||||
err = ds.DeleteInvite(invite)
|
||||
assert.Nil(t, err)
|
||||
|
||||
invite, err = ds.InviteByEmail("user0@foo.com")
|
||||
assert.NotNil(t, err)
|
||||
assert.Nil(t, invite)
|
||||
|
||||
}
|
||||
|
||||
func testSaveInvite(t *testing.T, ds kolide.Datastore) {
|
||||
setupTestInvites(t, ds)
|
||||
|
||||
invite, err := ds.InviteByEmail("user0@foo.com")
|
||||
assert.Nil(t, err)
|
||||
assert.NotNil(t, invite)
|
||||
|
||||
invite, err = ds.Invite(invite.ID)
|
||||
assert.Nil(t, err)
|
||||
assert.NotNil(t, invite)
|
||||
|
||||
invite.Name = "Bob"
|
||||
invite.Admin = true
|
||||
|
||||
err = ds.SaveInvite(invite)
|
||||
assert.Nil(t, err)
|
||||
|
||||
invite, err = ds.Invite(invite.ID)
|
||||
assert.Nil(t, err)
|
||||
assert.NotNil(t, invite)
|
||||
assert.Equal(t, "Bob", invite.Name)
|
||||
assert.True(t, invite.Admin)
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,7 +63,8 @@ func testLabels(t *testing.T, db kolide.Datastore) {
|
|||
}
|
||||
|
||||
for _, label := range newLabels {
|
||||
newLabel, err := db.NewLabel(&label)
|
||||
var newLabel *kolide.Label
|
||||
newLabel, err = db.NewLabel(&label)
|
||||
assert.Nil(t, err)
|
||||
assert.NotZero(t, newLabel.ID)
|
||||
}
|
||||
|
|
@ -143,7 +144,7 @@ func testManagingLabelsOnPacks(t *testing.T, ds kolide.Datastore) {
|
|||
monitoringPack := &kolide.Pack{
|
||||
Name: "monitoring",
|
||||
}
|
||||
err := ds.NewPack(monitoringPack)
|
||||
_, err := ds.NewPack(monitoringPack)
|
||||
require.Nil(t, err)
|
||||
|
||||
mysqlLabel := &kolide.Label{
|
||||
|
|
@ -193,16 +194,16 @@ func testSearchLabels(t *testing.T, db kolide.Datastore) {
|
|||
})
|
||||
require.Nil(t, err)
|
||||
|
||||
labels, err := db.SearchLabels("foo", nil)
|
||||
labels, err := db.SearchLabels("foo")
|
||||
assert.Nil(t, err)
|
||||
assert.Len(t, labels, 2)
|
||||
|
||||
label, err := db.SearchLabels("foo", []uint{l3.ID})
|
||||
label, err := db.SearchLabels("foo", l3.ID)
|
||||
assert.Nil(t, err)
|
||||
assert.Len(t, label, 1)
|
||||
assert.Equal(t, "foo", label[0].Name)
|
||||
|
||||
none, err := db.SearchLabels("xxx", nil)
|
||||
none, err := db.SearchLabels("xxx")
|
||||
assert.Nil(t, err)
|
||||
assert.Len(t, none, 0)
|
||||
}
|
||||
|
|
@ -215,7 +216,7 @@ func testSearchLabelsLimit(t *testing.T, db kolide.Datastore) {
|
|||
require.Nil(t, err)
|
||||
}
|
||||
|
||||
labels, err := db.SearchLabels("foo", nil)
|
||||
labels, err := db.SearchLabels("foo")
|
||||
require.Nil(t, err)
|
||||
assert.Len(t, labels, 10)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ func testDeletePack(t *testing.T, ds kolide.Datastore) {
|
|||
pack := &kolide.Pack{
|
||||
Name: "foo",
|
||||
}
|
||||
err := ds.NewPack(pack)
|
||||
_, err := ds.NewPack(pack)
|
||||
assert.Nil(t, err)
|
||||
assert.NotEqual(t, uint(0), pack.ID)
|
||||
|
||||
|
|
@ -31,7 +31,7 @@ func testAddAndRemoveQueryFromPack(t *testing.T, ds kolide.Datastore) {
|
|||
pack := &kolide.Pack{
|
||||
Name: "foo",
|
||||
}
|
||||
err := ds.NewPack(pack)
|
||||
_, err := ds.NewPack(pack)
|
||||
assert.Nil(t, err)
|
||||
assert.NotEqual(t, uint(0), pack.ID)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package datastore
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
|
|
@ -9,8 +10,9 @@ import (
|
|||
|
||||
func testDeleteQuery(t *testing.T, ds kolide.Datastore) {
|
||||
query := &kolide.Query{
|
||||
Name: "foo",
|
||||
Query: "bar",
|
||||
Name: "foo",
|
||||
Query: "bar",
|
||||
Interval: 123,
|
||||
}
|
||||
query, err := ds.NewQuery(query)
|
||||
assert.Nil(t, err)
|
||||
|
|
@ -42,3 +44,18 @@ func testSaveQuery(t *testing.T, ds kolide.Datastore) {
|
|||
assert.Nil(t, err)
|
||||
assert.Equal(t, "baz", queryVerify.Query)
|
||||
}
|
||||
|
||||
func testListQuery(t *testing.T, ds kolide.Datastore) {
|
||||
for i := 0; i < 10; i++ {
|
||||
_, err := ds.NewQuery(&kolide.Query{
|
||||
Name: fmt.Sprintf("name%02d", i),
|
||||
Query: fmt.Sprintf("query%02d", i),
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
opts := kolide.ListOptions{}
|
||||
results, err := ds.ListQueries(opts)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 10, len(results))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,8 +18,12 @@ func functionName(f func(*testing.T, kolide.Datastore)) string {
|
|||
var testFunctions = [...]func(*testing.T, kolide.Datastore){
|
||||
testOrgInfo,
|
||||
testCreateInvite,
|
||||
testListInvites,
|
||||
testDeleteInvite,
|
||||
testSaveInvite,
|
||||
testDeleteQuery,
|
||||
testSaveQuery,
|
||||
testListQuery,
|
||||
testDeletePack,
|
||||
testAddAndRemoveQueryFromPack,
|
||||
testEnrollHost,
|
||||
|
|
@ -38,4 +42,7 @@ var testFunctions = [...]func(*testing.T, kolide.Datastore){
|
|||
testListHostsInLabel,
|
||||
testListUniqueHostsInLabels,
|
||||
testDistributedQueriesForHost,
|
||||
testSaveHosts,
|
||||
testDeleteHost,
|
||||
testListHost,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ func testSaveUser(t *testing.T, ds kolide.Datastore) {
|
|||
|
||||
func testPasswordAttribute(t *testing.T, ds kolide.Datastore, users []*kolide.User) {
|
||||
for _, user := range users {
|
||||
randomText, err := generateRandomText(8)
|
||||
randomText, err := kolide.RandomText(8) //GenerateRandomText(8)
|
||||
assert.Nil(t, err)
|
||||
user.Password = []byte(randomText)
|
||||
err = ds.SaveUser(user)
|
||||
|
|
|
|||
|
|
@ -1,140 +0,0 @@
|
|||
package datastore
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
_ "github.com/go-sql-driver/mysql" // db driver
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
"github.com/kolide/kolide-ose/server/config"
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
)
|
||||
|
||||
var tables = [...]interface{}{
|
||||
&kolide.User{},
|
||||
&kolide.PasswordResetRequest{},
|
||||
&kolide.Session{},
|
||||
&kolide.Pack{},
|
||||
&kolide.PackQuery{},
|
||||
&kolide.PackTarget{},
|
||||
&kolide.Host{},
|
||||
&kolide.Label{},
|
||||
&kolide.LabelQueryExecution{},
|
||||
&kolide.Option{},
|
||||
&kolide.DistributedQueryCampaign{},
|
||||
&kolide.DistributedQueryCampaignTarget{},
|
||||
&kolide.Query{},
|
||||
&kolide.DistributedQueryExecution{},
|
||||
&kolide.AppConfig{},
|
||||
&kolide.Invite{},
|
||||
}
|
||||
|
||||
type gormDB struct {
|
||||
DB *gorm.DB
|
||||
Driver string
|
||||
config config.KolideConfig
|
||||
}
|
||||
|
||||
func (orm gormDB) Name() string {
|
||||
return "gorm"
|
||||
}
|
||||
|
||||
func (orm gormDB) Migrate() error {
|
||||
for _, table := range tables {
|
||||
if err := orm.DB.AutoMigrate(table).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Have to manually add indexes when specific ordering needed.
|
||||
err := orm.DB.Model(&kolide.LabelQueryExecution{}).AddUniqueIndex("idx_lqe_label_host", "label_id", "host_id").Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = orm.DB.Model(&kolide.DistributedQueryExecution{}).AddUniqueIndex("idx_dqe_unique_host_dq_id", "host_id", "distributed_query_campaign_id").Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
indexes := []interface{}{}
|
||||
err = orm.DB.Raw("SELECT * FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_SCHEMA = 'kolide' AND INDEX_NAME = 'hosts_search';").Scan(&indexes).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(indexes) == 0 {
|
||||
err = orm.DB.Exec("CREATE FULLTEXT INDEX hosts_search ON hosts(host_name, primary_ip);").Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
indexes = []interface{}{}
|
||||
err = orm.DB.Raw("SELECT * FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_SCHEMA = 'kolide' AND INDEX_NAME = 'labels_search';").Scan(&indexes).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(indexes) == 0 {
|
||||
err = orm.DB.Exec("CREATE FULLTEXT INDEX labels_search ON labels(name);").Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (orm gormDB) Drop() error {
|
||||
var err error
|
||||
for _, table := range tables {
|
||||
err = orm.DB.DropTableIfExists(table).Error
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// create connection with mysql backend, using a backoff timer and maxAttempts
|
||||
func openGORM(driver, conn string, maxAttempts int) (*gorm.DB, error) {
|
||||
var db *gorm.DB
|
||||
var err error
|
||||
for attempts := 1; attempts <= maxAttempts; attempts++ {
|
||||
db, err = gorm.Open(driver, conn)
|
||||
if err == nil {
|
||||
break
|
||||
} else {
|
||||
if err.Error() == "invalid database source" {
|
||||
return nil, err
|
||||
}
|
||||
// TODO: use a logger
|
||||
fmt.Printf("could not connect to mysql: %v\n", err)
|
||||
time.Sleep(time.Duration(attempts) * time.Second)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to connect to mysql backend, err = %v", err)
|
||||
}
|
||||
return db, nil
|
||||
}
|
||||
|
||||
// applyLimitOffset applies the appropriate limit and offset parameters to the
|
||||
// gorm.DB instance, returning a DB that can be chained as usual with *gorm.DB.
|
||||
func (orm *gormDB) applyListOptions(opt kolide.ListOptions) *gorm.DB {
|
||||
db := orm.DB
|
||||
if opt.PerPage != 0 {
|
||||
// PerPage value of 0 indicates unlimited
|
||||
offset := opt.Page * opt.PerPage
|
||||
db = db.Limit(opt.PerPage).Offset(offset)
|
||||
}
|
||||
|
||||
if opt.OrderKey != "" {
|
||||
var dir string
|
||||
if opt.OrderDirection == kolide.OrderDescending {
|
||||
dir = "DESC"
|
||||
} else {
|
||||
dir = "ASC"
|
||||
}
|
||||
|
||||
db = db.Order(opt.OrderKey + " " + dir)
|
||||
}
|
||||
|
||||
return db
|
||||
}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
package datastore
|
||||
|
||||
import (
|
||||
"github.com/jinzhu/gorm"
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
)
|
||||
|
||||
func (orm gormDB) NewAppConfig(info *kolide.AppConfig) (*kolide.AppConfig, error) {
|
||||
err := orm.DB.First(info).Error
|
||||
switch err {
|
||||
case gorm.ErrRecordNotFound:
|
||||
err = orm.DB.Create(info).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return info, nil
|
||||
case nil:
|
||||
return info, orm.SaveAppConfig(info)
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
func (orm gormDB) AppConfig() (*kolide.AppConfig, error) {
|
||||
info := &kolide.AppConfig{}
|
||||
err := orm.DB.First(info).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return info, nil
|
||||
}
|
||||
|
||||
func (orm gormDB) SaveAppConfig(info *kolide.AppConfig) error {
|
||||
return orm.DB.Save(info).Error
|
||||
}
|
||||
|
|
@ -1,195 +0,0 @@
|
|||
package datastore
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
"github.com/kolide/kolide-ose/server/errors"
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
)
|
||||
|
||||
func (orm gormDB) EnrollHost(uuid, hostname, ip, platform string, nodeKeySize int) (*kolide.Host, error) {
|
||||
if uuid == "" {
|
||||
return nil, errors.New("missing uuid for host enrollment", "programmer error?")
|
||||
}
|
||||
host := kolide.Host{UUID: uuid}
|
||||
err := orm.DB.Where(&host).First(&host).Error
|
||||
if err != nil {
|
||||
switch err {
|
||||
case gorm.ErrRecordNotFound:
|
||||
// Create new Host
|
||||
host = kolide.Host{
|
||||
UUID: uuid,
|
||||
HostName: hostname,
|
||||
PrimaryIP: ip,
|
||||
Platform: platform,
|
||||
DetailUpdateTime: time.Unix(0, 0).Add(24 * time.Hour),
|
||||
}
|
||||
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Generate a new key each enrollment
|
||||
host.NodeKey, err = generateRandomText(nodeKeySize)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Update these fields if provided
|
||||
if hostname != "" {
|
||||
host.HostName = hostname
|
||||
}
|
||||
if ip != "" {
|
||||
host.PrimaryIP = ip
|
||||
}
|
||||
if platform != "" {
|
||||
host.Platform = platform
|
||||
}
|
||||
|
||||
if err := orm.DB.Save(&host).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &host, nil
|
||||
}
|
||||
|
||||
func (orm gormDB) AuthenticateHost(nodeKey string) (*kolide.Host, error) {
|
||||
host := kolide.Host{NodeKey: nodeKey}
|
||||
err := orm.DB.Where("node_key = ?", host.NodeKey).First(&host).Error
|
||||
if err != nil {
|
||||
switch err {
|
||||
case gorm.ErrRecordNotFound:
|
||||
e := errors.NewFromError(
|
||||
err,
|
||||
http.StatusUnauthorized,
|
||||
"invalid node key",
|
||||
)
|
||||
// osqueryd expects the literal string "true" here
|
||||
e.Extra = map[string]interface{}{"node_invalid": "true"}
|
||||
return nil, e
|
||||
default:
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
}
|
||||
|
||||
return &host, nil
|
||||
}
|
||||
|
||||
func (orm gormDB) SaveHost(host *kolide.Host) error {
|
||||
if err := orm.DB.Save(host).Error; err != nil {
|
||||
return errors.DatabaseError(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (orm gormDB) DeleteHost(host *kolide.Host) error {
|
||||
return orm.DB.Delete(host).Error
|
||||
}
|
||||
|
||||
func (orm gormDB) Host(id uint) (*kolide.Host, error) {
|
||||
host := &kolide.Host{
|
||||
ID: id,
|
||||
}
|
||||
err := orm.DB.Where(host).First(host).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return host, nil
|
||||
}
|
||||
|
||||
func (orm gormDB) ListHosts(opt kolide.ListOptions) ([]*kolide.Host, error) {
|
||||
var hosts []*kolide.Host
|
||||
err := orm.applyListOptions(opt).Find(&hosts).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return hosts, nil
|
||||
}
|
||||
|
||||
func (orm gormDB) NewHost(host *kolide.Host) (*kolide.Host, error) {
|
||||
if host == nil {
|
||||
return nil, errors.New(
|
||||
"error creating host",
|
||||
"nil pointer passed to NewHost",
|
||||
)
|
||||
}
|
||||
err := orm.DB.Create(host).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return host, err
|
||||
}
|
||||
|
||||
func (orm gormDB) MarkHostSeen(host *kolide.Host, t time.Time) error {
|
||||
err := orm.DB.Exec("UPDATE hosts SET updated_at=? WHERE node_key=?", t, host.NodeKey).Error
|
||||
if err != nil {
|
||||
return errors.DatabaseError(err)
|
||||
}
|
||||
host.UpdatedAt = t
|
||||
return nil
|
||||
}
|
||||
|
||||
func (orm gormDB) SearchHosts(query string, omit []uint) ([]kolide.Host, error) {
|
||||
sql := `
|
||||
SELECT *
|
||||
FROM hosts
|
||||
WHERE MATCH(host_name, primary_ip)
|
||||
AGAINST(? IN BOOLEAN MODE)
|
||||
`
|
||||
results := []kolide.Host{}
|
||||
|
||||
var db *gorm.DB
|
||||
if len(omit) > 0 {
|
||||
sql += "AND id NOT IN (?) LIMIT 10;"
|
||||
db = orm.DB.Raw(sql, query+"*", omit)
|
||||
} else {
|
||||
sql += "LIMIT 10;"
|
||||
db = orm.DB.Raw(sql, query+"*")
|
||||
}
|
||||
|
||||
err := db.Scan(&results).Error
|
||||
if err != nil && err != gorm.ErrRecordNotFound {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func (orm gormDB) DistributedQueriesForHost(host *kolide.Host) (map[uint]string, error) {
|
||||
sql := `
|
||||
SELECT DISTINCT dqc.id, q.query
|
||||
FROM distributed_query_campaigns dqc
|
||||
JOIN distributed_query_campaign_targets dqct
|
||||
ON (dqc.id = dqct.distributed_query_campaign_id)
|
||||
LEFT JOIN label_query_executions lqe
|
||||
ON (dqct.type = ? AND dqct.target_id = lqe.label_id AND lqe.matches)
|
||||
LEFT JOIN hosts h
|
||||
ON ((dqct.type = ? AND lqe.host_id = h.id) OR (dqct.type = ? AND dqct.target_id = h.id))
|
||||
LEFT JOIN distributed_query_executions dqe
|
||||
ON (h.id = dqe.host_id AND dqc.id = dqe.distributed_query_campaign_id)
|
||||
JOIN queries q
|
||||
ON (dqc.query_id = q.id)
|
||||
WHERE dqe.status IS NULL AND dqc.status = ? AND h.id = ?;
|
||||
`
|
||||
rows, err := orm.DB.Raw(sql, kolide.TargetLabel, kolide.TargetLabel, kolide.TargetHost, kolide.QueryRunning, host.ID).Rows()
|
||||
if err != nil && err != gorm.ErrRecordNotFound {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
results := map[uint]string{}
|
||||
for rows.Next() {
|
||||
var id uint
|
||||
var query string
|
||||
err = rows.Scan(&id, &query)
|
||||
if err != nil {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
results[id] = query
|
||||
}
|
||||
|
||||
return results, nil
|
||||
|
||||
}
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
package datastore
|
||||
|
||||
import "github.com/kolide/kolide-ose/server/kolide"
|
||||
|
||||
func (orm gormDB) NewInvite(invite *kolide.Invite) (*kolide.Invite, error) {
|
||||
err := orm.DB.Create(invite).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return invite, nil
|
||||
}
|
||||
|
||||
func (orm gormDB) InviteByEmail(email string) (*kolide.Invite, error) {
|
||||
invite := &kolide.Invite{
|
||||
Email: email,
|
||||
}
|
||||
err := orm.DB.Where("email = ?", email).First(invite).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return invite, nil
|
||||
}
|
||||
|
||||
func (orm gormDB) ListInvites(opt kolide.ListOptions) ([]*kolide.Invite, error) {
|
||||
var invites []*kolide.Invite
|
||||
err := orm.applyListOptions(opt).Find(&invites).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return invites, nil
|
||||
}
|
||||
|
||||
func (orm gormDB) Invite(id uint) (*kolide.Invite, error) {
|
||||
invite := &kolide.Invite{ID: id}
|
||||
err := orm.DB.Where(invite).First(invite).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return invite, nil
|
||||
}
|
||||
|
||||
func (orm gormDB) SaveInvite(invite *kolide.Invite) error {
|
||||
return orm.DB.Save(invite).Error
|
||||
}
|
||||
|
||||
func (orm gormDB) DeleteInvite(invite *kolide.Invite) error {
|
||||
return orm.DB.Delete(invite).Error
|
||||
}
|
||||
|
|
@ -1,207 +0,0 @@
|
|||
package datastore
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
"github.com/kolide/kolide-ose/server/errors"
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
)
|
||||
|
||||
func (orm gormDB) NewLabel(label *kolide.Label) (*kolide.Label, error) {
|
||||
if label == nil {
|
||||
return nil, errors.New(
|
||||
"error creating label",
|
||||
"nil pointer passed to NewLabel",
|
||||
)
|
||||
}
|
||||
err := orm.DB.Create(label).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return label, nil
|
||||
}
|
||||
|
||||
func (orm gormDB) DeleteLabel(lid uint) error {
|
||||
err := orm.DB.Where("id = ?", lid).Delete(&kolide.Label{}).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return orm.DB.Where("target_id = ? and type = ?", lid, kolide.TargetLabel).Delete(&kolide.PackTarget{}).Error
|
||||
}
|
||||
|
||||
func (orm gormDB) Label(lid uint) (*kolide.Label, error) {
|
||||
label := &kolide.Label{
|
||||
ID: lid,
|
||||
}
|
||||
err := orm.DB.Where("id = ?", label.ID).First(&label).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return label, nil
|
||||
}
|
||||
|
||||
func (orm gormDB) ListLabels(opt kolide.ListOptions) ([]*kolide.Label, error) {
|
||||
var labels []*kolide.Label
|
||||
err := orm.applyListOptions(opt).Find(&labels).Error
|
||||
return labels, err
|
||||
}
|
||||
|
||||
func (orm gormDB) LabelQueriesForHost(host *kolide.Host, cutoff time.Time) (map[string]string, error) {
|
||||
if host == nil {
|
||||
return nil, errors.New(
|
||||
"error finding host queries",
|
||||
"nil pointer passed to LabelQueriesForHost",
|
||||
)
|
||||
}
|
||||
rows, err := orm.DB.Raw(`
|
||||
SELECT l.id, l.query
|
||||
from labels l
|
||||
WHERE l.platform = ?
|
||||
AND l.id NOT IN /* subtract the set of executions that are recent enough */
|
||||
(
|
||||
SELECT l.id
|
||||
FROM labels l
|
||||
JOIN label_query_executions lqe
|
||||
ON lqe.label_id = l.id
|
||||
WHERE lqe.host_id = ? AND lqe.updated_at > ?
|
||||
)`, host.Platform, host.ID, cutoff).Rows()
|
||||
if err != nil && err != gorm.ErrRecordNotFound {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
results := make(map[string]string)
|
||||
for rows.Next() {
|
||||
var id, query string
|
||||
err = rows.Scan(&id, &query)
|
||||
if err != nil {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
results[id] = query
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func (orm gormDB) RecordLabelQueryExecutions(host *kolide.Host, results map[string]bool, t time.Time) error {
|
||||
if host == nil {
|
||||
return errors.New(
|
||||
"error recording host label query execution",
|
||||
"nil pointer passed to RecordLabelQueryExecutions",
|
||||
)
|
||||
}
|
||||
|
||||
insert := new(bytes.Buffer)
|
||||
|
||||
insert.WriteString(
|
||||
"INSERT INTO label_query_executions (updated_at, matches, label_id, host_id) VALUES",
|
||||
)
|
||||
|
||||
// Build up all the values and the query string
|
||||
vals := []interface{}{}
|
||||
for labelId, res := range results {
|
||||
insert.WriteString("(?,?,?,?),")
|
||||
vals = append(vals, t, res, labelId, host.ID)
|
||||
}
|
||||
|
||||
queryString := insert.String()
|
||||
queryString = strings.TrimSuffix(queryString, ",")
|
||||
|
||||
queryString += `
|
||||
ON DUPLICATE KEY UPDATE
|
||||
updated_at = VALUES(updated_at),
|
||||
matches = VALUES(matches)
|
||||
`
|
||||
|
||||
if err := orm.DB.Exec(queryString, vals...).Error; err != nil {
|
||||
return errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (orm gormDB) ListLabelsForHost(hid uint) ([]kolide.Label, error) {
|
||||
results := []kolide.Label{}
|
||||
err := orm.DB.Raw(`
|
||||
SELECT labels.* from labels, label_query_executions lqe
|
||||
WHERE lqe.host_id = ?
|
||||
AND lqe.label_id = labels.id
|
||||
AND lqe.matches
|
||||
`, hid).Scan(&results).Error
|
||||
|
||||
if err != nil && err != gorm.ErrRecordNotFound {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func (orm gormDB) SearchLabels(query string, omit []uint) ([]kolide.Label, error) {
|
||||
sql := `
|
||||
SELECT *
|
||||
FROM labels
|
||||
WHERE MATCH(name)
|
||||
AGAINST(? IN BOOLEAN MODE)
|
||||
`
|
||||
results := []kolide.Label{}
|
||||
|
||||
var db *gorm.DB
|
||||
if len(omit) > 0 {
|
||||
sql += "AND id NOT IN (?) LIMIT 10;"
|
||||
db = orm.DB.Raw(sql, query+"*", omit)
|
||||
} else {
|
||||
sql += "LIMIT 10;"
|
||||
db = orm.DB.Raw(sql, query+"*")
|
||||
}
|
||||
|
||||
err := db.Scan(&results).Error
|
||||
if err != nil && err != gorm.ErrRecordNotFound {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func (orm gormDB) ListHostsInLabel(lid uint) ([]kolide.Host, error) {
|
||||
results := []kolide.Host{}
|
||||
err := orm.DB.Raw(`
|
||||
SELECT h.*
|
||||
FROM label_query_executions lqe
|
||||
JOIN hosts h
|
||||
ON lqe.host_id = h.id
|
||||
WHERE lqe.label_id = ?
|
||||
AND lqe.matches = 1;
|
||||
`, lid).Scan(&results).Error
|
||||
|
||||
if err != nil && err != gorm.ErrRecordNotFound {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func (orm gormDB) ListUniqueHostsInLabels(labels []uint) ([]kolide.Host, error) {
|
||||
if labels == nil || len(labels) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
results := []kolide.Host{}
|
||||
err := orm.DB.Raw(`
|
||||
SELECT h.*
|
||||
FROM label_query_executions lqe
|
||||
JOIN hosts h
|
||||
ON lqe.host_id = h.id
|
||||
WHERE lqe.label_id in (?)
|
||||
AND lqe.matches = 1
|
||||
GROUP BY h.id;
|
||||
`, labels).Scan(&results).Error
|
||||
|
||||
if err != nil && err != gorm.ErrRecordNotFound {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
|
@ -1,164 +0,0 @@
|
|||
package datastore
|
||||
|
||||
import (
|
||||
"github.com/jinzhu/gorm"
|
||||
"github.com/kolide/kolide-ose/server/errors"
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
)
|
||||
|
||||
func (orm gormDB) NewPack(pack *kolide.Pack) error {
|
||||
if pack == nil {
|
||||
return errors.New(
|
||||
"error creating pack",
|
||||
"nil pointer passed to NewPack",
|
||||
)
|
||||
}
|
||||
return orm.DB.Create(pack).Error
|
||||
}
|
||||
|
||||
func (orm gormDB) SavePack(pack *kolide.Pack) error {
|
||||
if pack == nil {
|
||||
return errors.New(
|
||||
"error saving pack",
|
||||
"nil pointer passed to SavePack",
|
||||
)
|
||||
}
|
||||
return orm.DB.Save(pack).Error
|
||||
}
|
||||
|
||||
func (orm gormDB) DeletePack(pid uint) error {
|
||||
err := orm.DB.Where("id = ?", pid).Delete(&kolide.Pack{}).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = orm.DB.Where("pack_id = ?", pid).Delete(&kolide.PackQuery{}).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return orm.DB.Where("pack_id = ?", pid).Delete(&kolide.PackTarget{}).Error
|
||||
}
|
||||
|
||||
func (orm gormDB) Pack(pid uint) (*kolide.Pack, error) {
|
||||
pack := &kolide.Pack{
|
||||
ID: pid,
|
||||
}
|
||||
err := orm.DB.Where(pack).First(pack).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return pack, nil
|
||||
}
|
||||
|
||||
func (orm gormDB) ListPacks(opt kolide.ListOptions) ([]*kolide.Pack, error) {
|
||||
var packs []*kolide.Pack
|
||||
err := orm.applyListOptions(opt).Find(&packs).Error
|
||||
return packs, err
|
||||
}
|
||||
|
||||
func (orm gormDB) AddQueryToPack(qid uint, pid uint) error {
|
||||
pq := &kolide.PackQuery{
|
||||
QueryID: qid,
|
||||
PackID: pid,
|
||||
}
|
||||
return orm.DB.Create(pq).Error
|
||||
}
|
||||
|
||||
func (orm gormDB) ListQueriesInPack(pack *kolide.Pack) ([]*kolide.Query, error) {
|
||||
if pack == nil {
|
||||
return nil, errors.New(
|
||||
"error getting queries in pack",
|
||||
"nil pointer passed to GetQueriesInPack",
|
||||
)
|
||||
}
|
||||
|
||||
results := []*kolide.Query{}
|
||||
err := orm.DB.Raw(`
|
||||
SELECT
|
||||
q.*
|
||||
FROM
|
||||
queries q
|
||||
JOIN
|
||||
pack_queries pq
|
||||
ON
|
||||
pq.query_id = q.id
|
||||
AND
|
||||
pq.pack_id = ?;
|
||||
`, pack.ID).Scan(&results).Error
|
||||
|
||||
if err != nil && err != gorm.ErrRecordNotFound {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func (orm gormDB) RemoveQueryFromPack(query *kolide.Query, pack *kolide.Pack) error {
|
||||
if query == nil || pack == nil {
|
||||
return errors.New(
|
||||
"error removing query from pack",
|
||||
"nil pointer passed to RemoveQueryFromPack",
|
||||
)
|
||||
}
|
||||
pq := &kolide.PackQuery{
|
||||
QueryID: query.ID,
|
||||
PackID: pack.ID,
|
||||
}
|
||||
return orm.DB.Where(pq).Delete(pq).Error
|
||||
}
|
||||
|
||||
func (orm gormDB) AddLabelToPack(lid uint, pid uint) error {
|
||||
pt := &kolide.PackTarget{
|
||||
PackID: pid,
|
||||
Target: kolide.Target{
|
||||
Type: kolide.TargetLabel,
|
||||
TargetID: lid,
|
||||
},
|
||||
}
|
||||
|
||||
return orm.DB.Create(pt).Error
|
||||
}
|
||||
|
||||
func (orm gormDB) ListLabelsForPack(pack *kolide.Pack) ([]*kolide.Label, error) {
|
||||
if pack == nil {
|
||||
return nil, errors.New(
|
||||
"error getting labels for pack",
|
||||
"nil pointer passed to GetLabelsForPack",
|
||||
)
|
||||
}
|
||||
|
||||
results := []*kolide.Label{}
|
||||
err := orm.DB.Raw(`
|
||||
SELECT
|
||||
l.*
|
||||
FROM
|
||||
labels l
|
||||
JOIN
|
||||
pack_targets pt
|
||||
ON
|
||||
pt.target_id = l.id
|
||||
WHERE
|
||||
pt.type = ?
|
||||
AND
|
||||
pt.pack_id = ?;
|
||||
|
||||
`,
|
||||
kolide.TargetLabel, pack.ID).Scan(&results).Error
|
||||
|
||||
if err != nil && err != gorm.ErrRecordNotFound {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func (orm gormDB) RemoveLabelFromPack(label *kolide.Label, pack *kolide.Pack) error {
|
||||
if label == nil || pack == nil {
|
||||
return errors.New(
|
||||
"error removing label from pack",
|
||||
"nil pointer passed to RemoveLabelFromPack",
|
||||
)
|
||||
}
|
||||
|
||||
return orm.DB.Where("pack_id = ? AND type = ? AND target_id = ?", pack.ID, kolide.TargetLabel, label.ID).Delete(&kolide.PackTarget{}).Error
|
||||
}
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
package datastore
|
||||
|
||||
import "github.com/kolide/kolide-ose/server/kolide"
|
||||
|
||||
func (orm gormDB) NewPasswordResetRequest(req *kolide.PasswordResetRequest) (*kolide.PasswordResetRequest, error) {
|
||||
err := orm.DB.Create(req).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func (orm gormDB) SavePasswordResetRequest(req *kolide.PasswordResetRequest) error {
|
||||
return orm.DB.Save(req).Error
|
||||
}
|
||||
|
||||
func (orm gormDB) DeletePasswordResetRequest(req *kolide.PasswordResetRequest) error {
|
||||
err := orm.DB.Delete(req).Error
|
||||
return err
|
||||
}
|
||||
|
||||
func (orm gormDB) DeletePasswordResetRequestsForUser(userID uint) error {
|
||||
err := orm.DB.Where("user_id = ?", userID).Delete(&kolide.PasswordResetRequest{}).Error
|
||||
return err
|
||||
}
|
||||
|
||||
func (orm gormDB) FindPassswordResetByID(id uint) (*kolide.PasswordResetRequest, error) {
|
||||
reset := &kolide.PasswordResetRequest{
|
||||
ID: id,
|
||||
}
|
||||
err := orm.DB.Find(reset).First(reset).Error
|
||||
return reset, err
|
||||
}
|
||||
|
||||
func (orm gormDB) FindPassswordResetsByUserID(userID uint) ([]*kolide.PasswordResetRequest, error) {
|
||||
var requests []*kolide.PasswordResetRequest
|
||||
err := orm.DB.Where("user_id = ?", userID).Find(&requests).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return requests, nil
|
||||
}
|
||||
|
||||
func (orm gormDB) FindPassswordResetByToken(token string) (*kolide.PasswordResetRequest, error) {
|
||||
reset := &kolide.PasswordResetRequest{
|
||||
Token: token,
|
||||
}
|
||||
err := orm.DB.Find(reset).First(reset).Error
|
||||
return reset, err
|
||||
}
|
||||
|
||||
func (orm gormDB) FindPassswordResetByTokenAndUserID(token string, userID uint) (*kolide.PasswordResetRequest, error) {
|
||||
reset := &kolide.PasswordResetRequest{
|
||||
Token: token,
|
||||
UserID: userID,
|
||||
}
|
||||
err := orm.DB.Find(reset).First(reset).Error
|
||||
return reset, err
|
||||
}
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
package datastore
|
||||
|
||||
import (
|
||||
"github.com/kolide/kolide-ose/server/errors"
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
)
|
||||
|
||||
func (orm gormDB) NewQuery(query *kolide.Query) (*kolide.Query, error) {
|
||||
if query == nil {
|
||||
return nil, errors.New(
|
||||
"error creating query",
|
||||
"nil pointer passed to NewQuery",
|
||||
)
|
||||
}
|
||||
err := orm.DB.Create(query).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return query, nil
|
||||
}
|
||||
|
||||
func (orm gormDB) SaveQuery(query *kolide.Query) error {
|
||||
if query == nil {
|
||||
return errors.New(
|
||||
"error saving query",
|
||||
"nil pointer passed to SaveQuery",
|
||||
)
|
||||
}
|
||||
return orm.DB.Save(query).Error
|
||||
}
|
||||
|
||||
func (orm gormDB) DeleteQuery(query *kolide.Query) error {
|
||||
if query == nil {
|
||||
return errors.New(
|
||||
"error deleting query",
|
||||
"nil pointer passed to DeleteQuery",
|
||||
)
|
||||
}
|
||||
return orm.DB.Delete(query).Error
|
||||
}
|
||||
|
||||
func (orm gormDB) Query(id uint) (*kolide.Query, error) {
|
||||
query := &kolide.Query{
|
||||
ID: id,
|
||||
}
|
||||
err := orm.DB.Where(query).First(query).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return query, nil
|
||||
}
|
||||
|
||||
func (orm gormDB) ListQueries(opt kolide.ListOptions) ([]*kolide.Query, error) {
|
||||
var queries []*kolide.Query
|
||||
err := orm.applyListOptions(opt).Find(&queries).Error
|
||||
return queries, err
|
||||
}
|
||||
|
||||
func (orm gormDB) NewDistributedQueryExecution(exec kolide.DistributedQueryExecution) (kolide.DistributedQueryExecution, error) {
|
||||
err := orm.DB.Create(&exec).Error
|
||||
return exec, err
|
||||
}
|
||||
|
||||
func (orm gormDB) NewDistributedQueryCampaign(camp kolide.DistributedQueryCampaign) (kolide.DistributedQueryCampaign, error) {
|
||||
err := orm.DB.Create(&camp).Error
|
||||
return camp, err
|
||||
}
|
||||
|
||||
func (orm gormDB) SaveDistributedQueryCampaign(camp kolide.DistributedQueryCampaign) error {
|
||||
return orm.DB.Save(&camp).Error
|
||||
}
|
||||
|
||||
func (orm gormDB) NewDistributedQueryCampaignTarget(target kolide.DistributedQueryCampaignTarget) (kolide.DistributedQueryCampaignTarget, error) {
|
||||
err := orm.DB.Create(&target).Error
|
||||
return target, err
|
||||
}
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
package datastore
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
)
|
||||
|
||||
func (orm gormDB) SessionByID(id uint) (*kolide.Session, error) {
|
||||
session := &kolide.Session{
|
||||
ID: id,
|
||||
}
|
||||
|
||||
err := orm.DB.Where(session).First(session).Error
|
||||
if err != nil {
|
||||
switch err {
|
||||
case gorm.ErrRecordNotFound:
|
||||
return nil, kolide.ErrNoActiveSession
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return session, nil
|
||||
|
||||
}
|
||||
|
||||
func (orm gormDB) SessionByKey(key string) (*kolide.Session, error) {
|
||||
session := &kolide.Session{
|
||||
Key: key,
|
||||
}
|
||||
|
||||
err := orm.DB.Where(session).First(session).Error
|
||||
if err != nil {
|
||||
switch err {
|
||||
case gorm.ErrRecordNotFound:
|
||||
return nil, kolide.ErrNoActiveSession
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return session, nil
|
||||
}
|
||||
|
||||
func (orm gormDB) ListSessionsForUser(id uint) ([]*kolide.Session, error) {
|
||||
var sessions []*kolide.Session
|
||||
err := orm.DB.Where("user_id = ?", id).Find(&sessions).Error
|
||||
return sessions, err
|
||||
}
|
||||
|
||||
func (orm gormDB) NewSession(session *kolide.Session) (*kolide.Session, error) {
|
||||
err := orm.DB.Create(session).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = orm.MarkSessionAccessed(session)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return session, nil
|
||||
}
|
||||
|
||||
func (orm gormDB) DestroySession(session *kolide.Session) error {
|
||||
return orm.DB.Delete(session).Error
|
||||
}
|
||||
|
||||
func (orm gormDB) DestroyAllSessionsForUser(id uint) error {
|
||||
return orm.DB.Delete(&kolide.Session{}, "user_id = ?", id).Error
|
||||
}
|
||||
|
||||
func (orm gormDB) MarkSessionAccessed(session *kolide.Session) error {
|
||||
session.AccessedAt = time.Now().UTC()
|
||||
return orm.DB.Save(session).Error
|
||||
}
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
package datastore
|
||||
|
||||
import (
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
)
|
||||
|
||||
func (orm gormDB) NewUser(user *kolide.User) (*kolide.User, error) {
|
||||
err := orm.DB.Create(user).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func (orm gormDB) User(username string) (*kolide.User, error) {
|
||||
user := &kolide.User{
|
||||
Username: username,
|
||||
}
|
||||
err := orm.DB.Where("username = ?", username).First(user).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func (orm gormDB) ListUsers(opt kolide.ListOptions) ([]*kolide.User, error) {
|
||||
var users []*kolide.User
|
||||
err := orm.applyListOptions(opt).Find(&users).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return users, nil
|
||||
}
|
||||
|
||||
func (orm gormDB) UserByEmail(email string) (*kolide.User, error) {
|
||||
user := &kolide.User{
|
||||
Email: email,
|
||||
}
|
||||
err := orm.DB.Where("email = ?", email).First(user).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func (orm gormDB) UserByID(id uint) (*kolide.User, error) {
|
||||
user := &kolide.User{ID: id}
|
||||
err := orm.DB.Where(user).First(user).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func (orm gormDB) SaveUser(user *kolide.User) error {
|
||||
return orm.DB.Save(user).Error
|
||||
}
|
||||
34
server/datastore/inmem/app.go
Normal file
34
server/datastore/inmem/app.go
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
package inmem
|
||||
|
||||
import (
|
||||
"github.com/kolide/kolide-ose/server/errors"
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
)
|
||||
|
||||
func (orm *Datastore) NewAppConfig(info *kolide.AppConfig) (*kolide.AppConfig, error) {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
|
||||
info.ID = 1
|
||||
orm.orginfo = info
|
||||
return info, nil
|
||||
}
|
||||
|
||||
func (orm *Datastore) AppConfig() (*kolide.AppConfig, error) {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
|
||||
if orm.orginfo != nil {
|
||||
return orm.orginfo, nil
|
||||
}
|
||||
|
||||
return nil, errors.ErrNotFound
|
||||
}
|
||||
|
||||
func (orm *Datastore) SaveAppConfig(info *kolide.AppConfig) error {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
|
||||
orm.orginfo = info
|
||||
return nil
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package datastore
|
||||
package inmem
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
|
@ -6,16 +6,17 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
kolide_errors "github.com/kolide/kolide-ose/server/errors"
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
)
|
||||
|
||||
func (orm *inmem) NewHost(host *kolide.Host) (*kolide.Host, error) {
|
||||
func (orm *Datastore) NewHost(host *kolide.Host) (*kolide.Host, error) {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
|
||||
for _, h := range orm.hosts {
|
||||
if host.NodeKey == h.NodeKey || host.UUID == h.UUID {
|
||||
return nil, ErrExists
|
||||
return nil, kolide_errors.ErrExists
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -25,43 +26,43 @@ func (orm *inmem) NewHost(host *kolide.Host) (*kolide.Host, error) {
|
|||
return host, nil
|
||||
}
|
||||
|
||||
func (orm *inmem) SaveHost(host *kolide.Host) error {
|
||||
func (orm *Datastore) SaveHost(host *kolide.Host) error {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
|
||||
if _, ok := orm.hosts[host.ID]; !ok {
|
||||
return ErrNotFound
|
||||
return kolide_errors.ErrNotFound
|
||||
}
|
||||
|
||||
orm.hosts[host.ID] = host
|
||||
return nil
|
||||
}
|
||||
|
||||
func (orm *inmem) DeleteHost(host *kolide.Host) error {
|
||||
func (orm *Datastore) DeleteHost(host *kolide.Host) error {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
|
||||
if _, ok := orm.hosts[host.ID]; !ok {
|
||||
return ErrNotFound
|
||||
return kolide_errors.ErrNotFound
|
||||
}
|
||||
|
||||
delete(orm.hosts, host.ID)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (orm *inmem) Host(id uint) (*kolide.Host, error) {
|
||||
func (orm *Datastore) Host(id uint) (*kolide.Host, error) {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
|
||||
host, ok := orm.hosts[id]
|
||||
if !ok {
|
||||
return nil, ErrNotFound
|
||||
return nil, kolide_errors.ErrNotFound
|
||||
}
|
||||
|
||||
return host, nil
|
||||
}
|
||||
|
||||
func (orm *inmem) ListHosts(opt kolide.ListOptions) ([]*kolide.Host, error) {
|
||||
func (orm *Datastore) ListHosts(opt kolide.ListOptions) ([]*kolide.Host, error) {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
|
||||
|
|
@ -106,7 +107,7 @@ func (orm *inmem) ListHosts(opt kolide.ListOptions) ([]*kolide.Host, error) {
|
|||
return hosts, nil
|
||||
}
|
||||
|
||||
func (orm *inmem) EnrollHost(uuid, hostname, ip, platform string, nodeKeySize int) (*kolide.Host, error) {
|
||||
func (orm *Datastore) EnrollHost(uuid, hostname, ip, platform string, nodeKeySize int) (*kolide.Host, error) {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
|
||||
|
|
@ -129,7 +130,7 @@ func (orm *inmem) EnrollHost(uuid, hostname, ip, platform string, nodeKeySize in
|
|||
}
|
||||
|
||||
var err error
|
||||
host.NodeKey, err = generateRandomText(nodeKeySize)
|
||||
host.NodeKey, err = kolide.RandomText(nodeKeySize)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -152,7 +153,7 @@ func (orm *inmem) EnrollHost(uuid, hostname, ip, platform string, nodeKeySize in
|
|||
return &host, nil
|
||||
}
|
||||
|
||||
func (orm *inmem) AuthenticateHost(nodeKey string) (*kolide.Host, error) {
|
||||
func (orm *Datastore) AuthenticateHost(nodeKey string) (*kolide.Host, error) {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
|
||||
|
|
@ -162,10 +163,10 @@ func (orm *inmem) AuthenticateHost(nodeKey string) (*kolide.Host, error) {
|
|||
}
|
||||
}
|
||||
|
||||
return nil, ErrNotFound
|
||||
return nil, kolide_errors.ErrNotFound
|
||||
}
|
||||
|
||||
func (orm *inmem) MarkHostSeen(host *kolide.Host, t time.Time) error {
|
||||
func (orm *Datastore) MarkHostSeen(host *kolide.Host, t time.Time) error {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
|
||||
|
|
@ -180,7 +181,7 @@ func (orm *inmem) MarkHostSeen(host *kolide.Host, t time.Time) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (orm *inmem) SearchHosts(query string, omit []uint) ([]kolide.Host, error) {
|
||||
func (orm *Datastore) SearchHosts(query string, omit ...uint) ([]kolide.Host, error) {
|
||||
omitLookup := map[uint]bool{}
|
||||
for _, o := range omit {
|
||||
omitLookup[o] = true
|
||||
|
|
@ -204,7 +205,7 @@ func (orm *inmem) SearchHosts(query string, omit []uint) ([]kolide.Host, error)
|
|||
return results, nil
|
||||
}
|
||||
|
||||
func (orm *inmem) DistributedQueriesForHost(host *kolide.Host) (map[uint]string, error) {
|
||||
func (orm *Datastore) DistributedQueriesForHost(host *kolide.Host) (map[uint]string, error) {
|
||||
// lookup of executions for this host
|
||||
hostExecutions := map[uint]kolide.DistributedQueryExecutionStatus{}
|
||||
for _, e := range orm.distributedQueryExecutions {
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package datastore
|
||||
package inmem
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
|
@ -9,7 +9,7 @@ import (
|
|||
"github.com/patrickmn/sortutil"
|
||||
)
|
||||
|
||||
type inmem struct {
|
||||
type Datastore struct {
|
||||
Driver string
|
||||
mtx sync.RWMutex
|
||||
nextIDs map[interface{}]uint
|
||||
|
|
@ -32,11 +32,38 @@ type inmem struct {
|
|||
orginfo *kolide.AppConfig
|
||||
}
|
||||
|
||||
func (orm *inmem) Name() string {
|
||||
func New() (*Datastore, error) {
|
||||
ds := &Datastore{
|
||||
Driver: "inmem",
|
||||
}
|
||||
|
||||
if err := ds.Migrate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ds, nil
|
||||
}
|
||||
|
||||
func (orm *Datastore) Name() string {
|
||||
return "inmem"
|
||||
}
|
||||
|
||||
func (orm *inmem) Migrate() error {
|
||||
func sortResults(slice interface{}, opt kolide.ListOptions, fields map[string]string) error {
|
||||
field, ok := fields[opt.OrderKey]
|
||||
if !ok {
|
||||
return errors.New("cannot sort on unknown key: " + opt.OrderKey)
|
||||
}
|
||||
|
||||
if opt.OrderDirection == kolide.OrderDescending {
|
||||
sortutil.DescByField(slice, field)
|
||||
} else {
|
||||
sortutil.AscByField(slice, field)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (orm *Datastore) Migrate() error {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
orm.nextIDs = make(map[interface{}]uint)
|
||||
|
|
@ -57,14 +84,14 @@ func (orm *inmem) Migrate() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (orm *inmem) Drop() error {
|
||||
func (orm *Datastore) Drop() error {
|
||||
return orm.Migrate()
|
||||
}
|
||||
|
||||
// getLimitOffsetSliceBounds returns the bounds that should be used for
|
||||
// re-slicing the results to comply with the requested ListOptions. Lack of
|
||||
// generics forces us to do this rather than reslicing in this method.
|
||||
func (orm *inmem) getLimitOffsetSliceBounds(opt kolide.ListOptions, length int) (low uint, high uint) {
|
||||
func (orm *Datastore) getLimitOffsetSliceBounds(opt kolide.ListOptions, length int) (low uint, high uint) {
|
||||
if opt.PerPage == 0 {
|
||||
// PerPage value of 0 indicates unlimited
|
||||
return 0, uint(length)
|
||||
|
|
@ -81,24 +108,9 @@ func (orm *inmem) getLimitOffsetSliceBounds(opt kolide.ListOptions, length int)
|
|||
return offset, max
|
||||
}
|
||||
|
||||
func sortResults(slice interface{}, opt kolide.ListOptions, fields map[string]string) error {
|
||||
field, ok := fields[opt.OrderKey]
|
||||
if !ok {
|
||||
return errors.New("cannot sort on unknown key: " + opt.OrderKey)
|
||||
}
|
||||
|
||||
if opt.OrderDirection == kolide.OrderDescending {
|
||||
sortutil.DescByField(slice, field)
|
||||
} else {
|
||||
sortutil.AscByField(slice, field)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// nextID returns the next ID value that should be used for a struct of the
|
||||
// given type
|
||||
func (orm *inmem) nextID(val interface{}) uint {
|
||||
func (orm *Datastore) nextID(val interface{}) uint {
|
||||
valType := reflect.TypeOf(reflect.Indirect(reflect.ValueOf(val)).Interface())
|
||||
orm.nextIDs[valType]++
|
||||
return orm.nextIDs[valType]
|
||||
68
server/datastore/inmem/inmem_test.go
Normal file
68
server/datastore/inmem/inmem_test.go
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
package inmem
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestApplyLimitOffset(t *testing.T) {
|
||||
im := Datastore{}
|
||||
data := []int{}
|
||||
|
||||
// should work with empty
|
||||
low, high := im.getLimitOffsetSliceBounds(kolide.ListOptions{}, len(data))
|
||||
result := data[low:high]
|
||||
assert.Len(t, result, 0)
|
||||
low, high = im.getLimitOffsetSliceBounds(kolide.ListOptions{Page: 1, PerPage: 20}, len(data))
|
||||
result = data[low:high]
|
||||
assert.Len(t, result, 0)
|
||||
|
||||
// insert some data
|
||||
for i := 0; i < 100; i++ {
|
||||
data = append(data, i)
|
||||
}
|
||||
|
||||
// unlimited
|
||||
low, high = im.getLimitOffsetSliceBounds(kolide.ListOptions{}, len(data))
|
||||
result = data[low:high]
|
||||
assert.Len(t, result, 100)
|
||||
assert.Equal(t, data, result)
|
||||
|
||||
// reasonable limit page 0
|
||||
low, high = im.getLimitOffsetSliceBounds(kolide.ListOptions{PerPage: 20}, len(data))
|
||||
result = data[low:high]
|
||||
assert.Len(t, result, 20)
|
||||
assert.Equal(t, data[:20], result)
|
||||
|
||||
// too many per page
|
||||
low, high = im.getLimitOffsetSliceBounds(kolide.ListOptions{PerPage: 200}, len(data))
|
||||
result = data[low:high]
|
||||
assert.Len(t, result, 100)
|
||||
assert.Equal(t, data, result)
|
||||
|
||||
// offset should be past end (zero results)
|
||||
low, high = im.getLimitOffsetSliceBounds(kolide.ListOptions{Page: 1, PerPage: 200}, len(data))
|
||||
result = data[low:high]
|
||||
assert.Len(t, result, 0)
|
||||
|
||||
// all pages appended should equal the original data
|
||||
result = []int{}
|
||||
for i := 0; i < 5; i++ { // 5 used intentionally
|
||||
low, high = im.getLimitOffsetSliceBounds(kolide.ListOptions{Page: uint(i), PerPage: 25}, len(data))
|
||||
result = append(result, data[low:high]...)
|
||||
}
|
||||
assert.Len(t, result, 100)
|
||||
assert.Equal(t, data, result)
|
||||
|
||||
// again with different params
|
||||
result = []int{}
|
||||
for i := 0; i < 100; i++ { // 5 used intentionally
|
||||
low, high = im.getLimitOffsetSliceBounds(kolide.ListOptions{Page: uint(i), PerPage: 1}, len(data))
|
||||
result = append(result, data[low:high]...)
|
||||
}
|
||||
assert.Len(t, result, 100)
|
||||
assert.Equal(t, data, result)
|
||||
|
||||
}
|
||||
|
|
@ -1,19 +1,20 @@
|
|||
package datastore
|
||||
package inmem
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"github.com/kolide/kolide-ose/server/errors"
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
)
|
||||
|
||||
// NewInvite creates and stores a new invitation in a DB.
|
||||
func (orm *inmem) NewInvite(invite *kolide.Invite) (*kolide.Invite, error) {
|
||||
func (orm *Datastore) NewInvite(invite *kolide.Invite) (*kolide.Invite, error) {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
|
||||
for _, in := range orm.invites {
|
||||
if in.Email == invite.Email {
|
||||
return nil, ErrExists
|
||||
return nil, errors.ErrExists
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -23,7 +24,7 @@ func (orm *inmem) NewInvite(invite *kolide.Invite) (*kolide.Invite, error) {
|
|||
}
|
||||
|
||||
// Invites lists all invites in the datastore.
|
||||
func (orm *inmem) ListInvites(opt kolide.ListOptions) ([]*kolide.Invite, error) {
|
||||
func (orm *Datastore) ListInvites(opt kolide.ListOptions) ([]*kolide.Invite, error) {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
|
||||
|
|
@ -63,17 +64,17 @@ func (orm *inmem) ListInvites(opt kolide.ListOptions) ([]*kolide.Invite, error)
|
|||
return invites, nil
|
||||
}
|
||||
|
||||
func (orm *inmem) Invite(id uint) (*kolide.Invite, error) {
|
||||
func (orm *Datastore) Invite(id uint) (*kolide.Invite, error) {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
if invite, ok := orm.invites[id]; ok {
|
||||
return invite, nil
|
||||
}
|
||||
return nil, ErrNotFound
|
||||
return nil, errors.ErrNotFound
|
||||
}
|
||||
|
||||
// InviteByEmail retrieves an invite for a specific email address.
|
||||
func (orm *inmem) InviteByEmail(email string) (*kolide.Invite, error) {
|
||||
func (orm *Datastore) InviteByEmail(email string) (*kolide.Invite, error) {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
|
||||
|
|
@ -82,16 +83,16 @@ func (orm *inmem) InviteByEmail(email string) (*kolide.Invite, error) {
|
|||
return invite, nil
|
||||
}
|
||||
}
|
||||
return nil, ErrNotFound
|
||||
return nil, errors.ErrNotFound
|
||||
}
|
||||
|
||||
// SaveInvite saves an invitation in the datastore.
|
||||
func (orm *inmem) SaveInvite(invite *kolide.Invite) error {
|
||||
func (orm *Datastore) SaveInvite(invite *kolide.Invite) error {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
|
||||
if _, ok := orm.invites[invite.ID]; !ok {
|
||||
return ErrNotFound
|
||||
return errors.ErrNotFound
|
||||
}
|
||||
|
||||
orm.invites[invite.ID] = invite
|
||||
|
|
@ -99,12 +100,12 @@ func (orm *inmem) SaveInvite(invite *kolide.Invite) error {
|
|||
}
|
||||
|
||||
// DeleteInvite deletes an invitation.
|
||||
func (orm *inmem) DeleteInvite(invite *kolide.Invite) error {
|
||||
func (orm *Datastore) DeleteInvite(invite *kolide.Invite) error {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
|
||||
if _, ok := orm.invites[invite.ID]; !ok {
|
||||
return ErrNotFound
|
||||
return errors.ErrNotFound
|
||||
}
|
||||
delete(orm.invites, invite.ID)
|
||||
return nil
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package datastore
|
||||
package inmem
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
|
@ -7,16 +7,17 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
kolide_errors "github.com/kolide/kolide-ose/server/errors"
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
)
|
||||
|
||||
func (orm *inmem) NewLabel(label *kolide.Label) (*kolide.Label, error) {
|
||||
func (orm *Datastore) NewLabel(label *kolide.Label) (*kolide.Label, error) {
|
||||
newLabel := *label
|
||||
|
||||
orm.mtx.Lock()
|
||||
for _, l := range orm.labels {
|
||||
if l.Name == label.Name {
|
||||
return nil, ErrExists
|
||||
return nil, kolide_errors.ErrExists
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -27,7 +28,7 @@ func (orm *inmem) NewLabel(label *kolide.Label) (*kolide.Label, error) {
|
|||
return &newLabel, nil
|
||||
}
|
||||
|
||||
func (orm *inmem) ListLabelsForHost(hid uint) ([]kolide.Label, error) {
|
||||
func (orm *Datastore) ListLabelsForHost(hid uint) ([]kolide.Label, error) {
|
||||
// First get IDs of label executions for the host
|
||||
resLabels := []kolide.Label{}
|
||||
|
||||
|
|
@ -44,7 +45,7 @@ func (orm *inmem) ListLabelsForHost(hid uint) ([]kolide.Label, error) {
|
|||
return resLabels, nil
|
||||
}
|
||||
|
||||
func (orm *inmem) LabelQueriesForHost(host *kolide.Host, cutoff time.Time) (map[string]string, error) {
|
||||
func (orm *Datastore) LabelQueriesForHost(host *kolide.Host, cutoff time.Time) (map[string]string, error) {
|
||||
// Get post-cutoff executions for host
|
||||
execedIDs := map[uint]bool{}
|
||||
|
||||
|
|
@ -66,7 +67,7 @@ func (orm *inmem) LabelQueriesForHost(host *kolide.Host, cutoff time.Time) (map[
|
|||
return queries, nil
|
||||
}
|
||||
|
||||
func (orm *inmem) getLabelByIDString(id string) (*kolide.Label, error) {
|
||||
func (orm *Datastore) getLabelByIDString(id string) (*kolide.Label, error) {
|
||||
labelID, err := strconv.Atoi(id)
|
||||
if err != nil {
|
||||
return nil, errors.New("non-int label ID")
|
||||
|
|
@ -83,7 +84,7 @@ func (orm *inmem) getLabelByIDString(id string) (*kolide.Label, error) {
|
|||
return label, nil
|
||||
}
|
||||
|
||||
func (orm *inmem) RecordLabelQueryExecutions(host *kolide.Host, results map[string]bool, t time.Time) error {
|
||||
func (orm *Datastore) RecordLabelQueryExecutions(host *kolide.Host, results map[string]bool, t time.Time) error {
|
||||
// Record executions
|
||||
for strLabelID, matches := range results {
|
||||
label, err := orm.getLabelByIDString(strLabelID)
|
||||
|
|
@ -120,7 +121,7 @@ func (orm *inmem) RecordLabelQueryExecutions(host *kolide.Host, results map[stri
|
|||
return nil
|
||||
}
|
||||
|
||||
func (orm *inmem) DeleteLabel(lid uint) error {
|
||||
func (orm *Datastore) DeleteLabel(lid uint) error {
|
||||
orm.mtx.Lock()
|
||||
delete(orm.labels, lid)
|
||||
orm.mtx.Unlock()
|
||||
|
|
@ -128,7 +129,7 @@ func (orm *inmem) DeleteLabel(lid uint) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (orm *inmem) Label(lid uint) (*kolide.Label, error) {
|
||||
func (orm *Datastore) Label(lid uint) (*kolide.Label, error) {
|
||||
orm.mtx.Lock()
|
||||
label, ok := orm.labels[lid]
|
||||
orm.mtx.Unlock()
|
||||
|
|
@ -139,7 +140,7 @@ func (orm *inmem) Label(lid uint) (*kolide.Label, error) {
|
|||
return label, nil
|
||||
}
|
||||
|
||||
func (orm *inmem) ListLabels(opt kolide.ListOptions) ([]*kolide.Label, error) {
|
||||
func (orm *Datastore) ListLabels(opt kolide.ListOptions) ([]*kolide.Label, error) {
|
||||
// We need to sort by keys to provide reliable ordering
|
||||
keys := []int{}
|
||||
|
||||
|
|
@ -175,7 +176,7 @@ func (orm *inmem) ListLabels(opt kolide.ListOptions) ([]*kolide.Label, error) {
|
|||
return labels, nil
|
||||
}
|
||||
|
||||
func (orm *inmem) SearchLabels(query string, omit []uint) ([]kolide.Label, error) {
|
||||
func (orm *Datastore) SearchLabels(query string, omit ...uint) ([]kolide.Label, error) {
|
||||
omitLookup := map[uint]bool{}
|
||||
for _, o := range omit {
|
||||
omitLookup[o] = true
|
||||
|
|
@ -200,7 +201,7 @@ func (orm *inmem) SearchLabels(query string, omit []uint) ([]kolide.Label, error
|
|||
return results, nil
|
||||
}
|
||||
|
||||
func (orm *inmem) ListHostsInLabel(lid uint) ([]kolide.Host, error) {
|
||||
func (orm *Datastore) ListHostsInLabel(lid uint) ([]kolide.Host, error) {
|
||||
var hosts []kolide.Host
|
||||
|
||||
orm.mtx.Lock()
|
||||
|
|
@ -215,7 +216,7 @@ func (orm *inmem) ListHostsInLabel(lid uint) ([]kolide.Host, error) {
|
|||
return hosts, nil
|
||||
}
|
||||
|
||||
func (orm *inmem) ListUniqueHostsInLabels(labels []uint) ([]kolide.Host, error) {
|
||||
func (orm *Datastore) ListUniqueHostsInLabels(labels []uint) ([]kolide.Host, error) {
|
||||
var hosts []kolide.Host
|
||||
|
||||
labelSet := map[uint]bool{}
|
||||
|
|
@ -1,17 +1,18 @@
|
|||
package datastore
|
||||
package inmem
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"github.com/kolide/kolide-ose/server/errors"
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
)
|
||||
|
||||
func (orm *inmem) NewPack(pack *kolide.Pack) error {
|
||||
func (orm *Datastore) NewPack(pack *kolide.Pack) (*kolide.Pack, error) {
|
||||
newPack := *pack
|
||||
|
||||
for _, q := range orm.packs {
|
||||
if pack.Name == q.Name {
|
||||
return ErrExists
|
||||
return nil, errors.ErrExists
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -20,15 +21,14 @@ func (orm *inmem) NewPack(pack *kolide.Pack) error {
|
|||
orm.packs[newPack.ID] = &newPack
|
||||
orm.mtx.Unlock()
|
||||
|
||||
// TODO NewPack should return (*kolide.Pack, error) and this is a work around
|
||||
pack.ID = newPack.ID
|
||||
|
||||
return nil
|
||||
return pack, nil
|
||||
}
|
||||
|
||||
func (orm *inmem) SavePack(pack *kolide.Pack) error {
|
||||
func (orm *Datastore) SavePack(pack *kolide.Pack) error {
|
||||
if _, ok := orm.packs[pack.ID]; !ok {
|
||||
return ErrNotFound
|
||||
return errors.ErrNotFound
|
||||
}
|
||||
|
||||
orm.mtx.Lock()
|
||||
|
|
@ -38,9 +38,9 @@ func (orm *inmem) SavePack(pack *kolide.Pack) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (orm *inmem) DeletePack(pid uint) error {
|
||||
func (orm *Datastore) DeletePack(pid uint) error {
|
||||
if _, ok := orm.packs[pid]; !ok {
|
||||
return ErrNotFound
|
||||
return errors.ErrNotFound
|
||||
}
|
||||
|
||||
orm.mtx.Lock()
|
||||
|
|
@ -50,18 +50,18 @@ func (orm *inmem) DeletePack(pid uint) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (orm *inmem) Pack(id uint) (*kolide.Pack, error) {
|
||||
func (orm *Datastore) Pack(id uint) (*kolide.Pack, error) {
|
||||
orm.mtx.Lock()
|
||||
pack, ok := orm.packs[id]
|
||||
orm.mtx.Unlock()
|
||||
if !ok {
|
||||
return nil, ErrNotFound
|
||||
return nil, errors.ErrNotFound
|
||||
}
|
||||
|
||||
return pack, nil
|
||||
}
|
||||
|
||||
func (orm *inmem) ListPacks(opt kolide.ListOptions) ([]*kolide.Pack, error) {
|
||||
func (orm *Datastore) ListPacks(opt kolide.ListOptions) ([]*kolide.Pack, error) {
|
||||
// We need to sort by keys to provide reliable ordering
|
||||
keys := []int{}
|
||||
orm.mtx.Lock()
|
||||
|
|
@ -97,7 +97,7 @@ func (orm *inmem) ListPacks(opt kolide.ListOptions) ([]*kolide.Pack, error) {
|
|||
return packs, nil
|
||||
}
|
||||
|
||||
func (orm *inmem) AddQueryToPack(qid uint, pid uint) error {
|
||||
func (orm *Datastore) AddQueryToPack(qid uint, pid uint) error {
|
||||
packQuery := &kolide.PackQuery{
|
||||
PackID: pid,
|
||||
QueryID: qid,
|
||||
|
|
@ -111,7 +111,7 @@ func (orm *inmem) AddQueryToPack(qid uint, pid uint) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (orm *inmem) ListQueriesInPack(pack *kolide.Pack) ([]*kolide.Query, error) {
|
||||
func (orm *Datastore) ListQueriesInPack(pack *kolide.Pack) ([]*kolide.Query, error) {
|
||||
var queries []*kolide.Query
|
||||
|
||||
orm.mtx.Lock()
|
||||
|
|
@ -123,7 +123,7 @@ func (orm *inmem) ListQueriesInPack(pack *kolide.Pack) ([]*kolide.Query, error)
|
|||
return queries, nil
|
||||
}
|
||||
|
||||
func (orm *inmem) RemoveQueryFromPack(query *kolide.Query, pack *kolide.Pack) error {
|
||||
func (orm *Datastore) RemoveQueryFromPack(query *kolide.Query, pack *kolide.Pack) error {
|
||||
var packQueriesToDelete []uint
|
||||
|
||||
orm.mtx.Lock()
|
||||
|
|
@ -141,7 +141,7 @@ func (orm *inmem) RemoveQueryFromPack(query *kolide.Query, pack *kolide.Pack) er
|
|||
return nil
|
||||
}
|
||||
|
||||
func (orm *inmem) AddLabelToPack(lid uint, pid uint) error {
|
||||
func (orm *Datastore) AddLabelToPack(lid uint, pid uint) error {
|
||||
pt := &kolide.PackTarget{
|
||||
PackID: pid,
|
||||
Target: kolide.Target{
|
||||
|
|
@ -158,7 +158,7 @@ func (orm *inmem) AddLabelToPack(lid uint, pid uint) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (orm *inmem) ListLabelsForPack(pack *kolide.Pack) ([]*kolide.Label, error) {
|
||||
func (orm *Datastore) ListLabelsForPack(pack *kolide.Pack) ([]*kolide.Label, error) {
|
||||
var labels []*kolide.Label
|
||||
|
||||
orm.mtx.Lock()
|
||||
|
|
@ -172,7 +172,7 @@ func (orm *inmem) ListLabelsForPack(pack *kolide.Pack) ([]*kolide.Label, error)
|
|||
return labels, nil
|
||||
}
|
||||
|
||||
func (orm *inmem) RemoveLabelFromPack(label *kolide.Label, pack *kolide.Pack) error {
|
||||
func (orm *Datastore) RemoveLabelFromPack(label *kolide.Label, pack *kolide.Pack) error {
|
||||
var labelsToDelete []uint
|
||||
|
||||
orm.mtx.Lock()
|
||||
|
|
@ -1,8 +1,11 @@
|
|||
package datastore
|
||||
package inmem
|
||||
|
||||
import "github.com/kolide/kolide-ose/server/kolide"
|
||||
import (
|
||||
"github.com/kolide/kolide-ose/server/errors"
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
)
|
||||
|
||||
func (orm *inmem) NewPasswordResetRequest(req *kolide.PasswordResetRequest) (*kolide.PasswordResetRequest, error) {
|
||||
func (orm *Datastore) NewPasswordResetRequest(req *kolide.PasswordResetRequest) (*kolide.PasswordResetRequest, error) {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
|
||||
|
|
@ -11,31 +14,31 @@ func (orm *inmem) NewPasswordResetRequest(req *kolide.PasswordResetRequest) (*ko
|
|||
return req, nil
|
||||
}
|
||||
|
||||
func (orm *inmem) SavePasswordResetRequest(req *kolide.PasswordResetRequest) error {
|
||||
func (orm *Datastore) SavePasswordResetRequest(req *kolide.PasswordResetRequest) error {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
|
||||
if _, ok := orm.passwordResets[req.ID]; !ok {
|
||||
return ErrNotFound
|
||||
return errors.ErrNotFound
|
||||
}
|
||||
|
||||
orm.passwordResets[req.ID] = req
|
||||
return nil
|
||||
}
|
||||
|
||||
func (orm *inmem) DeletePasswordResetRequest(req *kolide.PasswordResetRequest) error {
|
||||
func (orm *Datastore) DeletePasswordResetRequest(req *kolide.PasswordResetRequest) error {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
|
||||
if _, ok := orm.passwordResets[req.ID]; !ok {
|
||||
return ErrNotFound
|
||||
return errors.ErrNotFound
|
||||
}
|
||||
|
||||
delete(orm.passwordResets, req.ID)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (orm *inmem) DeletePasswordResetRequestsForUser(userID uint) error {
|
||||
func (orm *Datastore) DeletePasswordResetRequestsForUser(userID uint) error {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
|
||||
|
|
@ -47,7 +50,7 @@ func (orm *inmem) DeletePasswordResetRequestsForUser(userID uint) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (orm *inmem) FindPassswordResetByID(id uint) (*kolide.PasswordResetRequest, error) {
|
||||
func (orm *Datastore) FindPassswordResetByID(id uint) (*kolide.PasswordResetRequest, error) {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
|
||||
|
|
@ -55,10 +58,10 @@ func (orm *inmem) FindPassswordResetByID(id uint) (*kolide.PasswordResetRequest,
|
|||
return req, nil
|
||||
}
|
||||
|
||||
return nil, ErrNotFound
|
||||
return nil, errors.ErrNotFound
|
||||
}
|
||||
|
||||
func (orm *inmem) FindPassswordResetsByUserID(userID uint) ([]*kolide.PasswordResetRequest, error) {
|
||||
func (orm *Datastore) FindPassswordResetsByUserID(userID uint) ([]*kolide.PasswordResetRequest, error) {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
resets := make([]*kolide.PasswordResetRequest, 0)
|
||||
|
|
@ -70,13 +73,13 @@ func (orm *inmem) FindPassswordResetsByUserID(userID uint) ([]*kolide.PasswordRe
|
|||
}
|
||||
|
||||
if len(resets) == 0 {
|
||||
return nil, ErrNotFound
|
||||
return nil, errors.ErrNotFound
|
||||
}
|
||||
|
||||
return resets, nil
|
||||
}
|
||||
|
||||
func (orm *inmem) FindPassswordResetByToken(token string) (*kolide.PasswordResetRequest, error) {
|
||||
func (orm *Datastore) FindPassswordResetByToken(token string) (*kolide.PasswordResetRequest, error) {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
|
||||
|
|
@ -86,10 +89,10 @@ func (orm *inmem) FindPassswordResetByToken(token string) (*kolide.PasswordReset
|
|||
}
|
||||
}
|
||||
|
||||
return nil, ErrNotFound
|
||||
return nil, errors.ErrNotFound
|
||||
}
|
||||
|
||||
func (orm *inmem) FindPassswordResetByTokenAndUserID(token string, userID uint) (*kolide.PasswordResetRequest, error) {
|
||||
func (orm *Datastore) FindPassswordResetByTokenAndUserID(token string, userID uint) (*kolide.PasswordResetRequest, error) {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
|
||||
|
|
@ -99,5 +102,5 @@ func (orm *inmem) FindPassswordResetByTokenAndUserID(token string, userID uint)
|
|||
}
|
||||
}
|
||||
|
||||
return nil, ErrNotFound
|
||||
return nil, errors.ErrNotFound
|
||||
}
|
||||
|
|
@ -1,12 +1,13 @@
|
|||
package datastore
|
||||
package inmem
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"github.com/kolide/kolide-ose/server/errors"
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
)
|
||||
|
||||
func (orm *inmem) NewQuery(query *kolide.Query) (*kolide.Query, error) {
|
||||
func (orm *Datastore) NewQuery(query *kolide.Query) (*kolide.Query, error) {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
|
||||
|
|
@ -14,7 +15,7 @@ func (orm *inmem) NewQuery(query *kolide.Query) (*kolide.Query, error) {
|
|||
|
||||
for _, q := range orm.queries {
|
||||
if query.Name == q.Name {
|
||||
return nil, ErrExists
|
||||
return nil, errors.ErrExists
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -24,43 +25,43 @@ func (orm *inmem) NewQuery(query *kolide.Query) (*kolide.Query, error) {
|
|||
return &newQuery, nil
|
||||
}
|
||||
|
||||
func (orm *inmem) SaveQuery(query *kolide.Query) error {
|
||||
func (orm *Datastore) SaveQuery(query *kolide.Query) error {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
|
||||
if _, ok := orm.queries[query.ID]; !ok {
|
||||
return ErrNotFound
|
||||
return errors.ErrNotFound
|
||||
}
|
||||
|
||||
orm.queries[query.ID] = query
|
||||
return nil
|
||||
}
|
||||
|
||||
func (orm *inmem) DeleteQuery(query *kolide.Query) error {
|
||||
func (orm *Datastore) DeleteQuery(query *kolide.Query) error {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
|
||||
if _, ok := orm.queries[query.ID]; !ok {
|
||||
return ErrNotFound
|
||||
return errors.ErrNotFound
|
||||
}
|
||||
|
||||
delete(orm.queries, query.ID)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (orm *inmem) Query(id uint) (*kolide.Query, error) {
|
||||
func (orm *Datastore) Query(id uint) (*kolide.Query, error) {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
|
||||
query, ok := orm.queries[id]
|
||||
if !ok {
|
||||
return nil, ErrNotFound
|
||||
return nil, errors.ErrNotFound
|
||||
}
|
||||
|
||||
return query, nil
|
||||
}
|
||||
|
||||
func (orm *inmem) ListQueries(opt kolide.ListOptions) ([]*kolide.Query, error) {
|
||||
func (orm *Datastore) ListQueries(opt kolide.ListOptions) ([]*kolide.Query, error) {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
|
||||
|
|
@ -102,50 +103,50 @@ func (orm *inmem) ListQueries(opt kolide.ListOptions) ([]*kolide.Query, error) {
|
|||
return queries, nil
|
||||
}
|
||||
|
||||
func (orm *inmem) NewDistributedQueryExecution(exec kolide.DistributedQueryExecution) (kolide.DistributedQueryExecution, error) {
|
||||
func (orm *Datastore) NewDistributedQueryExecution(exec *kolide.DistributedQueryExecution) (*kolide.DistributedQueryExecution, error) {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
|
||||
for _, e := range orm.distributedQueryExecutions {
|
||||
if exec.HostID == e.ID && exec.DistributedQueryCampaignID == e.DistributedQueryCampaignID {
|
||||
return exec, ErrExists
|
||||
return exec, errors.ErrExists
|
||||
}
|
||||
}
|
||||
|
||||
exec.ID = orm.nextID(exec)
|
||||
orm.distributedQueryExecutions[exec.ID] = exec
|
||||
orm.distributedQueryExecutions[exec.ID] = *exec
|
||||
|
||||
return exec, nil
|
||||
}
|
||||
|
||||
func (orm *inmem) NewDistributedQueryCampaign(camp kolide.DistributedQueryCampaign) (kolide.DistributedQueryCampaign, error) {
|
||||
func (orm *Datastore) NewDistributedQueryCampaign(camp *kolide.DistributedQueryCampaign) (*kolide.DistributedQueryCampaign, error) {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
|
||||
camp.ID = orm.nextID(camp)
|
||||
orm.distributedQueryCampaigns[camp.ID] = camp
|
||||
orm.distributedQueryCampaigns[camp.ID] = *camp
|
||||
|
||||
return camp, nil
|
||||
}
|
||||
|
||||
func (orm *inmem) SaveDistributedQueryCampaign(camp kolide.DistributedQueryCampaign) error {
|
||||
func (orm *Datastore) SaveDistributedQueryCampaign(camp *kolide.DistributedQueryCampaign) error {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
|
||||
if _, ok := orm.distributedQueryCampaigns[camp.ID]; !ok {
|
||||
return ErrNotFound
|
||||
return errors.ErrNotFound
|
||||
}
|
||||
|
||||
orm.distributedQueryCampaigns[camp.ID] = camp
|
||||
orm.distributedQueryCampaigns[camp.ID] = *camp
|
||||
return nil
|
||||
}
|
||||
|
||||
func (orm *inmem) NewDistributedQueryCampaignTarget(target kolide.DistributedQueryCampaignTarget) (kolide.DistributedQueryCampaignTarget, error) {
|
||||
func (orm *Datastore) NewDistributedQueryCampaignTarget(target *kolide.DistributedQueryCampaignTarget) (*kolide.DistributedQueryCampaignTarget, error) {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
|
||||
target.ID = orm.nextID(target)
|
||||
orm.distributedQueryCampaignTargets[target.ID] = target
|
||||
orm.distributedQueryCampaignTargets[target.ID] = *target
|
||||
|
||||
return target, nil
|
||||
}
|
||||
|
|
@ -1,12 +1,13 @@
|
|||
package datastore
|
||||
package inmem
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/kolide/kolide-ose/server/errors"
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
)
|
||||
|
||||
func (orm *inmem) SessionByKey(key string) (*kolide.Session, error) {
|
||||
func (orm *Datastore) SessionByKey(key string) (*kolide.Session, error) {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
|
||||
|
|
@ -15,20 +16,20 @@ func (orm *inmem) SessionByKey(key string) (*kolide.Session, error) {
|
|||
return session, nil
|
||||
}
|
||||
}
|
||||
return nil, ErrNotFound
|
||||
return nil, errors.ErrNotFound
|
||||
}
|
||||
|
||||
func (orm *inmem) SessionByID(id uint) (*kolide.Session, error) {
|
||||
func (orm *Datastore) SessionByID(id uint) (*kolide.Session, error) {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
|
||||
if session, ok := orm.sessions[id]; ok {
|
||||
return session, nil
|
||||
}
|
||||
return nil, ErrNotFound
|
||||
return nil, errors.ErrNotFound
|
||||
}
|
||||
|
||||
func (orm *inmem) ListSessionsForUser(id uint) ([]*kolide.Session, error) {
|
||||
func (orm *Datastore) ListSessionsForUser(id uint) ([]*kolide.Session, error) {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
|
||||
|
|
@ -39,12 +40,12 @@ func (orm *inmem) ListSessionsForUser(id uint) ([]*kolide.Session, error) {
|
|||
}
|
||||
}
|
||||
if len(sessions) == 0 {
|
||||
return nil, ErrNotFound
|
||||
return nil, errors.ErrNotFound
|
||||
}
|
||||
return sessions, nil
|
||||
}
|
||||
|
||||
func (orm *inmem) NewSession(session *kolide.Session) (*kolide.Session, error) {
|
||||
func (orm *Datastore) NewSession(session *kolide.Session) (*kolide.Session, error) {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
|
||||
|
|
@ -58,15 +59,15 @@ func (orm *inmem) NewSession(session *kolide.Session) (*kolide.Session, error) {
|
|||
|
||||
}
|
||||
|
||||
func (orm *inmem) DestroySession(session *kolide.Session) error {
|
||||
func (orm *Datastore) DestroySession(session *kolide.Session) error {
|
||||
if _, ok := orm.sessions[session.ID]; !ok {
|
||||
return ErrNotFound
|
||||
return errors.ErrNotFound
|
||||
}
|
||||
delete(orm.sessions, session.ID)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (orm *inmem) DestroyAllSessionsForUser(id uint) error {
|
||||
func (orm *Datastore) DestroyAllSessionsForUser(id uint) error {
|
||||
for _, session := range orm.sessions {
|
||||
if session.UserID == id {
|
||||
delete(orm.sessions, session.ID)
|
||||
|
|
@ -75,10 +76,10 @@ func (orm *inmem) DestroyAllSessionsForUser(id uint) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (orm *inmem) MarkSessionAccessed(session *kolide.Session) error {
|
||||
func (orm *Datastore) MarkSessionAccessed(session *kolide.Session) error {
|
||||
session.AccessedAt = time.Now().UTC()
|
||||
if _, ok := orm.sessions[session.ID]; !ok {
|
||||
return ErrNotFound
|
||||
return errors.ErrNotFound
|
||||
}
|
||||
orm.sessions[session.ID] = session
|
||||
return nil
|
||||
|
|
@ -1,18 +1,19 @@
|
|||
package datastore
|
||||
package inmem
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"github.com/kolide/kolide-ose/server/errors"
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
)
|
||||
|
||||
func (orm *inmem) NewUser(user *kolide.User) (*kolide.User, error) {
|
||||
func (orm *Datastore) NewUser(user *kolide.User) (*kolide.User, error) {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
|
||||
for _, in := range orm.users {
|
||||
if in.Username == user.Username {
|
||||
return nil, ErrExists
|
||||
return nil, errors.ErrExists
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -22,7 +23,7 @@ func (orm *inmem) NewUser(user *kolide.User) (*kolide.User, error) {
|
|||
return user, nil
|
||||
}
|
||||
|
||||
func (orm *inmem) User(username string) (*kolide.User, error) {
|
||||
func (orm *Datastore) User(username string) (*kolide.User, error) {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
|
||||
|
|
@ -32,10 +33,10 @@ func (orm *inmem) User(username string) (*kolide.User, error) {
|
|||
}
|
||||
}
|
||||
|
||||
return nil, ErrNotFound
|
||||
return nil, errors.ErrNotFound
|
||||
}
|
||||
|
||||
func (orm *inmem) ListUsers(opt kolide.ListOptions) ([]*kolide.User, error) {
|
||||
func (orm *Datastore) ListUsers(opt kolide.ListOptions) ([]*kolide.User, error) {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
|
||||
|
|
@ -76,7 +77,7 @@ func (orm *inmem) ListUsers(opt kolide.ListOptions) ([]*kolide.User, error) {
|
|||
return users, nil
|
||||
}
|
||||
|
||||
func (orm *inmem) UserByEmail(email string) (*kolide.User, error) {
|
||||
func (orm *Datastore) UserByEmail(email string) (*kolide.User, error) {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
|
||||
|
|
@ -86,10 +87,10 @@ func (orm *inmem) UserByEmail(email string) (*kolide.User, error) {
|
|||
}
|
||||
}
|
||||
|
||||
return nil, ErrNotFound
|
||||
return nil, errors.ErrNotFound
|
||||
}
|
||||
|
||||
func (orm *inmem) UserByID(id uint) (*kolide.User, error) {
|
||||
func (orm *Datastore) UserByID(id uint) (*kolide.User, error) {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
|
||||
|
|
@ -97,15 +98,15 @@ func (orm *inmem) UserByID(id uint) (*kolide.User, error) {
|
|||
return user, nil
|
||||
}
|
||||
|
||||
return nil, ErrNotFound
|
||||
return nil, errors.ErrNotFound
|
||||
}
|
||||
|
||||
func (orm *inmem) SaveUser(user *kolide.User) error {
|
||||
func (orm *Datastore) SaveUser(user *kolide.User) error {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
|
||||
if _, ok := orm.users[user.ID]; !ok {
|
||||
return ErrNotFound
|
||||
return errors.ErrNotFound
|
||||
}
|
||||
|
||||
orm.users[user.ID] = user
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
package datastore
|
||||
|
||||
import "github.com/kolide/kolide-ose/server/kolide"
|
||||
|
||||
func (orm *inmem) NewAppConfig(info *kolide.AppConfig) (*kolide.AppConfig, error) {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
|
||||
info.ID = 1
|
||||
orm.orginfo = info
|
||||
return info, nil
|
||||
}
|
||||
|
||||
func (orm *inmem) AppConfig() (*kolide.AppConfig, error) {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
|
||||
if orm.orginfo != nil {
|
||||
return orm.orginfo, nil
|
||||
}
|
||||
|
||||
return nil, ErrNotFound
|
||||
}
|
||||
|
||||
func (orm *inmem) SaveAppConfig(info *kolide.AppConfig) error {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
|
||||
orm.orginfo = info
|
||||
return nil
|
||||
}
|
||||
|
|
@ -3,76 +3,18 @@ package datastore
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/kolide/kolide-ose/server/datastore/inmem"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestInmem(t *testing.T) {
|
||||
|
||||
for _, f := range testFunctions {
|
||||
t.Run(functionName(f), func(t *testing.T) {
|
||||
ds, err := New("inmem", "")
|
||||
assert.Nil(t, err)
|
||||
ds, err := inmem.New()
|
||||
defer func() { require.Nil(t, ds.Drop()) }()
|
||||
require.Nil(t, err)
|
||||
f(t, ds)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyLimitOffset(t *testing.T) {
|
||||
im := inmem{}
|
||||
data := []int{}
|
||||
|
||||
// should work with empty
|
||||
low, high := im.getLimitOffsetSliceBounds(kolide.ListOptions{}, len(data))
|
||||
result := data[low:high]
|
||||
assert.Len(t, result, 0)
|
||||
low, high = im.getLimitOffsetSliceBounds(kolide.ListOptions{Page: 1, PerPage: 20}, len(data))
|
||||
result = data[low:high]
|
||||
assert.Len(t, result, 0)
|
||||
|
||||
// insert some data
|
||||
for i := 0; i < 100; i++ {
|
||||
data = append(data, i)
|
||||
}
|
||||
|
||||
// unlimited
|
||||
low, high = im.getLimitOffsetSliceBounds(kolide.ListOptions{}, len(data))
|
||||
result = data[low:high]
|
||||
assert.Len(t, result, 100)
|
||||
assert.Equal(t, data, result)
|
||||
|
||||
// reasonable limit page 0
|
||||
low, high = im.getLimitOffsetSliceBounds(kolide.ListOptions{PerPage: 20}, len(data))
|
||||
result = data[low:high]
|
||||
assert.Len(t, result, 20)
|
||||
assert.Equal(t, data[:20], result)
|
||||
|
||||
// too many per page
|
||||
low, high = im.getLimitOffsetSliceBounds(kolide.ListOptions{PerPage: 200}, len(data))
|
||||
result = data[low:high]
|
||||
assert.Len(t, result, 100)
|
||||
assert.Equal(t, data, result)
|
||||
|
||||
// offset should be past end (zero results)
|
||||
low, high = im.getLimitOffsetSliceBounds(kolide.ListOptions{Page: 1, PerPage: 200}, len(data))
|
||||
result = data[low:high]
|
||||
assert.Len(t, result, 0)
|
||||
|
||||
// all pages appended should equal the original data
|
||||
result = []int{}
|
||||
for i := 0; i < 5; i++ { // 5 used intentionally
|
||||
low, high = im.getLimitOffsetSliceBounds(kolide.ListOptions{Page: uint(i), PerPage: 25}, len(data))
|
||||
result = append(result, data[low:high]...)
|
||||
}
|
||||
assert.Len(t, result, 100)
|
||||
assert.Equal(t, data, result)
|
||||
|
||||
// again with different params
|
||||
result = []int{}
|
||||
for i := 0; i < 100; i++ { // 5 used intentionally
|
||||
low, high = im.getLimitOffsetSliceBounds(kolide.ListOptions{Page: uint(i), PerPage: 1}, len(data))
|
||||
result = append(result, data[low:high]...)
|
||||
}
|
||||
assert.Len(t, result, 100)
|
||||
assert.Equal(t, data, result)
|
||||
|
||||
}
|
||||
|
|
|
|||
50
server/datastore/mysql/app_configs.go
Normal file
50
server/datastore/mysql/app_configs.go
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
package mysql
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
)
|
||||
|
||||
func (d *Datastore) NewAppConfig(info *kolide.AppConfig) (*kolide.AppConfig, error) {
|
||||
var (
|
||||
err error
|
||||
result sql.Result
|
||||
)
|
||||
|
||||
err = d.db.Get(info, "SELECT * FROM app_configs LIMIT 1")
|
||||
switch err {
|
||||
case sql.ErrNoRows:
|
||||
result, err = d.db.Exec(
|
||||
"INSERT INTO app_configs (org_name, org_logo_url, kolide_server_url) VALUES (?, ?, ?)",
|
||||
info.OrgName, info.OrgLogoURL, info.KolideServerURL,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info.ID, _ = result.LastInsertId()
|
||||
return info, nil
|
||||
case nil:
|
||||
return info, d.SaveAppConfig(info)
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Datastore) AppConfig() (*kolide.AppConfig, error) {
|
||||
info := &kolide.AppConfig{}
|
||||
err := d.db.Get(info, "SELECT * FROM app_configs LIMIT 1")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return info, nil
|
||||
}
|
||||
|
||||
func (d *Datastore) SaveAppConfig(info *kolide.AppConfig) error {
|
||||
_, err := d.db.Exec(
|
||||
"UPDATE app_configs SET org_name = ?, org_logo_url = ?, kolide_server_url = ? WHERE id = ?",
|
||||
info.OrgName, info.OrgLogoURL, info.KolideServerURL, info.ID,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
|
@ -1,10 +1,6 @@
|
|||
package datastore
|
||||
package mysql
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
)
|
||||
import "github.com/go-kit/kit/log"
|
||||
|
||||
const defaultMaxAttempts int = 15
|
||||
|
||||
|
|
@ -14,13 +10,11 @@ type DBOption func(o *dbOptions) error
|
|||
type dbOptions struct {
|
||||
// maxAttempts configures the number of retries to connect to the DB
|
||||
maxAttempts int
|
||||
db kolide.Datastore
|
||||
debug bool // gorm debug
|
||||
logger *log.Logger
|
||||
logger log.Logger
|
||||
}
|
||||
|
||||
// Logger adds a logger to the datastore
|
||||
func Logger(l *log.Logger) DBOption {
|
||||
func Logger(l log.Logger) DBOption {
|
||||
return func(o *dbOptions) error {
|
||||
o.logger = l
|
||||
return nil
|
||||
|
|
@ -36,20 +30,3 @@ func LimitAttempts(attempts int) DBOption {
|
|||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Debug sets the GORM debug level
|
||||
func Debug() DBOption {
|
||||
return func(o *dbOptions) error {
|
||||
o.debug = true
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// datastore allows you to pass your own datastore
|
||||
// this option can be used to pass a specific testing implementation
|
||||
func datastore(db kolide.Datastore) DBOption {
|
||||
return func(o *dbOptions) error {
|
||||
o.db = db
|
||||
return nil
|
||||
}
|
||||
}
|
||||
179
server/datastore/mysql/datastore.go
Normal file
179
server/datastore/mysql/datastore.go
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
package mysql
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/WatchBeam/clock"
|
||||
"github.com/go-kit/kit/log"
|
||||
"github.com/go-sql-driver/mysql" // db driver
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/kolide/kolide-ose/server/config"
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultSelectLimit = 1000
|
||||
)
|
||||
|
||||
// Datastore is an implementation of kolide.Datastore interface backed by
|
||||
// MySQL
|
||||
type Datastore struct {
|
||||
db *sqlx.DB
|
||||
logger log.Logger
|
||||
clock clock.Clock
|
||||
}
|
||||
|
||||
// New creates an MySQL datastore.
|
||||
func New(dbConnectString string, c clock.Clock, opts ...DBOption) (*Datastore, error) {
|
||||
|
||||
options := &dbOptions{
|
||||
maxAttempts: defaultMaxAttempts,
|
||||
logger: log.NewNopLogger(),
|
||||
}
|
||||
|
||||
for _, setOpt := range opts {
|
||||
setOpt(options)
|
||||
}
|
||||
|
||||
db, err := sqlx.Open("mysql", dbConnectString)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var dbError error
|
||||
for attempt := 0; attempt < options.maxAttempts; attempt++ {
|
||||
dbError = db.Ping()
|
||||
if dbError == nil {
|
||||
// we're connected!
|
||||
break
|
||||
}
|
||||
sleep := time.Duration(attempt)
|
||||
options.logger.Log("mysql", fmt.Sprintf(
|
||||
"could not connect to db: %v, sleeping %v", dbError, sleep))
|
||||
time.Sleep(sleep * time.Second)
|
||||
}
|
||||
|
||||
if dbError != nil {
|
||||
return nil, dbError
|
||||
}
|
||||
|
||||
ds := &Datastore{db, options.logger, c}
|
||||
|
||||
return ds, nil
|
||||
|
||||
}
|
||||
|
||||
func (d *Datastore) Name() string {
|
||||
return "mysql"
|
||||
}
|
||||
|
||||
// Migrate creates database
|
||||
func (d *Datastore) Migrate() error {
|
||||
|
||||
sql, err := Asset("db/up.sql")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tx := d.db.MustBegin()
|
||||
|
||||
for _, statement := range strings.SplitAfter(string(sql), ";") {
|
||||
if _, err = tx.Exec(statement); err != nil {
|
||||
if driverErr, ok := err.(*mysql.MySQLError); ok {
|
||||
if driverErr.Number != 1065 { // ignore empty queries
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err = tx.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
// Drop removes database
|
||||
func (d *Datastore) Drop() error {
|
||||
var (
|
||||
sql []byte
|
||||
err error
|
||||
)
|
||||
|
||||
if sql, err = Asset("db/down.sql"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tx := d.db.MustBegin()
|
||||
|
||||
for _, statement := range strings.SplitAfter(string(sql), ";") {
|
||||
if _, err = tx.Exec(statement); err != nil {
|
||||
if driverErr, ok := err.(*mysql.MySQLError); ok {
|
||||
if driverErr.Number != 1065 { // ignore empty queries
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err = tx.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
// Close frees resources associated with underlying mysql connection
|
||||
func (d *Datastore) Close() error {
|
||||
return d.db.Close()
|
||||
}
|
||||
|
||||
func (d *Datastore) log(msg string) {
|
||||
d.logger.Log("comp", d.Name(), "msg", msg)
|
||||
}
|
||||
|
||||
func appendListOptionsToSQL(sql string, opts kolide.ListOptions) string {
|
||||
if opts.OrderKey != "" {
|
||||
direction := "ASC"
|
||||
if opts.OrderDirection == kolide.OrderDescending {
|
||||
direction = "DESC"
|
||||
}
|
||||
|
||||
sql = fmt.Sprintf("%s ORDER BY %s %s", sql, opts.OrderKey, direction)
|
||||
}
|
||||
// REVIEW: If caller doesn't supply a limit apply a default limit of 1000
|
||||
// to insure that an unbounded query with many results doesn't consume too
|
||||
// much memory or hang
|
||||
if opts.PerPage == 0 {
|
||||
opts.PerPage = defaultSelectLimit
|
||||
}
|
||||
|
||||
sql = fmt.Sprintf("%s LIMIT %d", sql, opts.PerPage)
|
||||
|
||||
offset := opts.PerPage * opts.Page
|
||||
|
||||
if offset > 0 {
|
||||
sql = fmt.Sprintf("%s OFFSET %d", sql, offset)
|
||||
}
|
||||
|
||||
return sql
|
||||
}
|
||||
|
||||
// GetMysqlConnectionString returns a MySQL connection string using the
|
||||
// provided configuration.
|
||||
func GetMysqlConnectionString(conf config.MysqlConfig) string {
|
||||
return fmt.Sprintf(
|
||||
"%s:%s@(%s)/%s?charset=utf8&parseTime=True&loc=Local",
|
||||
conf.Username,
|
||||
conf.Password,
|
||||
conf.Address,
|
||||
conf.Database,
|
||||
)
|
||||
}
|
||||
57
server/datastore/mysql/datastore_test.go
Normal file
57
server/datastore/mysql/datastore_test.go
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
package mysql
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
)
|
||||
|
||||
func TestAppendListOptionsToSQL(t *testing.T) {
|
||||
sql := "SELECT * FROM app_configs"
|
||||
opts := kolide.ListOptions{
|
||||
OrderKey: "name",
|
||||
}
|
||||
|
||||
actual := appendListOptionsToSQL(sql, opts)
|
||||
expected := "SELECT * FROM app_configs ORDER BY name ASC LIMIT 1000"
|
||||
if actual != expected {
|
||||
t.Error("Expected", expected, "Actual", actual)
|
||||
}
|
||||
|
||||
sql = "SELECT * FROM app_configs"
|
||||
opts.OrderDirection = kolide.OrderDescending
|
||||
actual = appendListOptionsToSQL(sql, opts)
|
||||
expected = "SELECT * FROM app_configs ORDER BY name DESC LIMIT 1000"
|
||||
if actual != expected {
|
||||
t.Error("Expected", expected, "Actual", actual)
|
||||
}
|
||||
|
||||
opts = kolide.ListOptions{
|
||||
PerPage: 10,
|
||||
}
|
||||
|
||||
sql = "SELECT * FROM app_configs"
|
||||
actual = appendListOptionsToSQL(sql, opts)
|
||||
expected = "SELECT * FROM app_configs LIMIT 10"
|
||||
if actual != expected {
|
||||
t.Error("Expected", expected, "Actual", actual)
|
||||
}
|
||||
|
||||
sql = "SELECT * FROM app_configs"
|
||||
opts.Page = 2
|
||||
actual = appendListOptionsToSQL(sql, opts)
|
||||
expected = "SELECT * FROM app_configs LIMIT 10 OFFSET 20"
|
||||
if actual != expected {
|
||||
t.Error("Expected", expected, "Actual", actual)
|
||||
}
|
||||
|
||||
opts = kolide.ListOptions{}
|
||||
sql = "SELECT * FROM app_configs"
|
||||
actual = appendListOptionsToSQL(sql, opts)
|
||||
expected = "SELECT * FROM app_configs LIMIT 1000"
|
||||
|
||||
if actual != expected {
|
||||
t.Error("Expected", expected, "Actual", actual)
|
||||
}
|
||||
|
||||
}
|
||||
295
server/datastore/mysql/hosts.go
Normal file
295
server/datastore/mysql/hosts.go
Normal file
|
|
@ -0,0 +1,295 @@
|
|||
package mysql
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/kolide/kolide-ose/server/errors"
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
)
|
||||
|
||||
func (d *Datastore) NewHost(host *kolide.Host) (*kolide.Host, error) {
|
||||
sqlStatement := `
|
||||
INSERT INTO hosts (
|
||||
detail_update_time,
|
||||
node_key,
|
||||
host_name,
|
||||
uuid,
|
||||
platform,
|
||||
osquery_version,
|
||||
os_version,
|
||||
uptime,
|
||||
physical_memory,
|
||||
primary_mac,
|
||||
primary_ip
|
||||
)
|
||||
VALUES( ?,?,?,?,?,?,?,?,?,?,?)
|
||||
`
|
||||
result, err := d.db.Exec(sqlStatement, host.DetailUpdateTime,
|
||||
host.NodeKey, host.HostName, host.UUID, host.Platform, host.OsqueryVersion,
|
||||
host.OSVersion, host.Uptime, host.PhysicalMemory, host.PrimaryMAC, host.PrimaryIP)
|
||||
if err != nil {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
id, _ := result.LastInsertId()
|
||||
host.ID = uint(id)
|
||||
return host, nil
|
||||
}
|
||||
|
||||
// TODO needs test
|
||||
func (d *Datastore) SaveHost(host *kolide.Host) error {
|
||||
sqlStatement := `
|
||||
UPDATE hosts SET
|
||||
detail_update_time = ?,
|
||||
node_key = ?,
|
||||
host_name = ?,
|
||||
uuid = ?,
|
||||
platform = ?,
|
||||
osquery_version = ?,
|
||||
os_version = ?,
|
||||
uptime = ?,
|
||||
physical_memory = ?,
|
||||
primary_mac = ?,
|
||||
primary_ip = ?
|
||||
WHERE id = ?
|
||||
`
|
||||
_, err := d.db.Exec(sqlStatement, host.DetailUpdateTime, host.NodeKey,
|
||||
host.HostName, host.UUID, host.Platform, host.OsqueryVersion,
|
||||
host.OSVersion, host.Uptime, host.PhysicalMemory, host.PrimaryMAC,
|
||||
host.PrimaryIP, host.ID)
|
||||
if err != nil {
|
||||
return errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO needs test
|
||||
func (d *Datastore) DeleteHost(host *kolide.Host) error {
|
||||
sqlStatement := `
|
||||
UPDATE hosts SET
|
||||
deleted = TRUE,
|
||||
deleted_at = ?
|
||||
WHERE id = ?
|
||||
`
|
||||
_, err := d.db.Exec(sqlStatement, d.clock.Now(), host.ID)
|
||||
if err != nil {
|
||||
return errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO needs test
|
||||
func (d *Datastore) Host(id uint) (*kolide.Host, error) {
|
||||
sqlStatement := `
|
||||
SELECT * FROM hosts
|
||||
WHERE id = ? AND NOT deleted LIMIT 1
|
||||
`
|
||||
host := &kolide.Host{}
|
||||
err := d.db.Get(host, sqlStatement, id)
|
||||
if err != nil {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
return host, nil
|
||||
|
||||
}
|
||||
|
||||
// TODO needs test
|
||||
func (d *Datastore) ListHosts(opt kolide.ListOptions) ([]*kolide.Host, error) {
|
||||
sqlStatement := `
|
||||
SELECT * FROM hosts
|
||||
WHERE NOT deleted
|
||||
`
|
||||
sqlStatement = appendListOptionsToSQL(sqlStatement, opt)
|
||||
hosts := []*kolide.Host{}
|
||||
if err := d.db.Select(&hosts, sqlStatement); err != nil {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
return hosts, nil
|
||||
}
|
||||
|
||||
// EnrollHost enrolls a host
|
||||
func (d *Datastore) EnrollHost(uuid, hostname, ip, platform string, nodeKeySize int) (*kolide.Host, error) {
|
||||
if uuid == "" {
|
||||
return nil, errors.New("missing uuid for host enrollment", "programmer error")
|
||||
}
|
||||
// REVIEW If a deleted host is enrolled, it is undeleted
|
||||
sqlInsert := `
|
||||
INSERT INTO hosts (
|
||||
detail_update_time,
|
||||
node_key,
|
||||
host_name,
|
||||
uuid,
|
||||
platform,
|
||||
primary_ip
|
||||
) VALUES (?, ?, ?, ?, ?, ? )
|
||||
ON DUPLICATE KEY UPDATE
|
||||
updated_at = VALUES(updated_at),
|
||||
detail_update_time = VALUES(detail_update_time),
|
||||
node_key = VALUES(node_key),
|
||||
host_name = VALUES(host_name),
|
||||
platform = VALUES(platform),
|
||||
primary_ip = VALUES(primary_ip),
|
||||
deleted = FALSE
|
||||
`
|
||||
args := []interface{}{}
|
||||
args = append(args, time.Unix(0, 0).Add(24*time.Hour))
|
||||
|
||||
nodeKey, err := kolide.RandomText(nodeKeySize)
|
||||
|
||||
args = append(args, nodeKey)
|
||||
args = append(args, hostname)
|
||||
args = append(args, uuid)
|
||||
args = append(args, platform)
|
||||
args = append(args, ip)
|
||||
|
||||
var result sql.Result
|
||||
|
||||
result, err = d.db.Exec(sqlInsert, args...)
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
id, _ := result.LastInsertId()
|
||||
sqlSelect := `
|
||||
SELECT * FROM hosts WHERE id = ? LIMIT 1
|
||||
`
|
||||
host := &kolide.Host{}
|
||||
err = d.db.Get(host, sqlSelect, id)
|
||||
if err != nil {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
return host, nil
|
||||
|
||||
}
|
||||
|
||||
func (d *Datastore) AuthenticateHost(nodeKey string) (*kolide.Host, error) {
|
||||
sqlStatement := `
|
||||
SELECT * FROM hosts
|
||||
WHERE node_key = ? AND NOT DELETED LIMIT 1
|
||||
`
|
||||
host := &kolide.Host{}
|
||||
if err := d.db.Get(host, sqlStatement, nodeKey); err != nil {
|
||||
switch err {
|
||||
case sql.ErrNoRows:
|
||||
e := errors.NewFromError(err, http.StatusUnauthorized, "invalid node key")
|
||||
e.Extra = map[string]interface{}{"node_invalid": "true"}
|
||||
return nil, e
|
||||
default:
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
}
|
||||
|
||||
return host, nil
|
||||
|
||||
}
|
||||
|
||||
func (d *Datastore) MarkHostSeen(*kolide.Host, time.Time) error {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func (d *Datastore) searchHostsWithOmits(query string, omits ...uint) ([]kolide.Host, error) {
|
||||
// The reason that string cocantenation is used to include query as opposed to a
|
||||
// bindvar is that sqlx.In has a bug such that, if you have any bindvars other
|
||||
// than those in the IN clause, sqlx.In returns an empty sql statement.
|
||||
// I've submitted an issue https://github.com/jmoiron/sqlx/issues/260 about this
|
||||
sqlStatement := `
|
||||
SELECT *
|
||||
FROM hosts
|
||||
WHERE MATCH(host_name, primary_ip)
|
||||
AGAINST('` + query + "*" + `' IN BOOLEAN MODE)
|
||||
AND NOT deleted
|
||||
AND id NOT IN (?)
|
||||
LIMIT 10
|
||||
`
|
||||
|
||||
sql, args, err := sqlx.In(sqlStatement, omits)
|
||||
if err != nil {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
sql = d.db.Rebind(sql)
|
||||
|
||||
hosts := []kolide.Host{}
|
||||
|
||||
if err = d.db.Select(&hosts, sql, args...); err != nil {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
return hosts, nil
|
||||
}
|
||||
|
||||
// SearchHosts find hosts by query containing an IP address or a host name. Optionally
|
||||
// pass a list of IDs to omit from the search
|
||||
func (d *Datastore) SearchHosts(query string, omit ...uint) ([]kolide.Host, error) {
|
||||
if len(omit) > 0 {
|
||||
return d.searchHostsWithOmits(query, omit...)
|
||||
}
|
||||
|
||||
sqlStatement := `
|
||||
SELECT * FROM hosts
|
||||
WHERE MATCH(host_name, primary_ip)
|
||||
AGAINST(? IN BOOLEAN MODE)
|
||||
AND not deleted
|
||||
LIMIT 10
|
||||
`
|
||||
hosts := []kolide.Host{}
|
||||
|
||||
if err := d.db.Select(&hosts, sqlStatement, query); err != nil {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
return hosts, nil
|
||||
|
||||
}
|
||||
|
||||
func (d *Datastore) DistributedQueriesForHost(host *kolide.Host) (map[uint]string, error) {
|
||||
sqlStatement := `
|
||||
SELECT DISTINCT dqc.id, q.query
|
||||
FROM distributed_query_campaigns dqc
|
||||
JOIN distributed_query_campaign_targets dqct
|
||||
ON (dqc.id = dqct.distributed_query_campaign_id)
|
||||
LEFT JOIN label_query_executions lqe
|
||||
ON (dqct.type = ? AND dqct.target_id = lqe.label_id AND lqe.matches)
|
||||
LEFT JOIN hosts h
|
||||
ON ((dqct.type = ? AND lqe.host_id = h.id) OR (dqct.type = ? AND dqct.target_id = h.id))
|
||||
LEFT JOIN distributed_query_executions dqe
|
||||
ON (h.id = dqe.host_id AND dqc.id = dqe.distributed_query_campaign_id)
|
||||
JOIN queries q
|
||||
ON (dqc.query_id = q.id)
|
||||
WHERE dqe.status IS NULL AND dqc.status = ? AND h.id = ?
|
||||
AND NOT q.deleted
|
||||
AND NOT dqc.deleted
|
||||
`
|
||||
rows, err := d.db.Query(sqlStatement, kolide.TargetLabel, kolide.TargetLabel,
|
||||
kolide.TargetHost, kolide.QueryRunning, host.ID)
|
||||
if err != nil {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
results := map[uint]string{}
|
||||
|
||||
for rows.Next() {
|
||||
var (
|
||||
id uint
|
||||
query string
|
||||
)
|
||||
err = rows.Scan(&id, &query)
|
||||
if err != nil {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
results[id] = query
|
||||
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
92
server/datastore/mysql/invites.go
Normal file
92
server/datastore/mysql/invites.go
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
package mysql
|
||||
|
||||
import (
|
||||
"github.com/kolide/kolide-ose/server/errors"
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
)
|
||||
|
||||
// NewInvite generates a new invitation
|
||||
func (d *Datastore) NewInvite(i *kolide.Invite) (*kolide.Invite, error) {
|
||||
|
||||
sql := `
|
||||
INSERT INTO invites ( invited_by, email, admin, name, position, token)
|
||||
VALUES ( ?, ?, ?, ?, ?, ?)
|
||||
`
|
||||
|
||||
result, err := d.db.Exec(sql, i.InvitedBy, i.Email, i.Admin,
|
||||
i.Name, i.Position, i.Token)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
id, _ := result.LastInsertId()
|
||||
i.ID = uint(id)
|
||||
|
||||
return i, nil
|
||||
|
||||
}
|
||||
|
||||
// ListInvites lists all invites in the Kolide database. Supply query options
|
||||
// using the opt parameter. See kolide.ListOptions
|
||||
func (d *Datastore) ListInvites(opt kolide.ListOptions) ([]*kolide.Invite, error) {
|
||||
|
||||
invites := []*kolide.Invite{}
|
||||
|
||||
sql := appendListOptionsToSQL("SELECT * FROM invites WHERE NOT deleted", opt)
|
||||
err := d.db.Select(&invites, sql)
|
||||
if err != nil {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
return invites, nil
|
||||
}
|
||||
|
||||
// Invite returns Invite identified by id.
|
||||
func (d *Datastore) Invite(id uint) (*kolide.Invite, error) {
|
||||
invite := &kolide.Invite{}
|
||||
err := d.db.Get(invite, "SELECT * FROM invites WHERE id = ? AND NOT deleted", id)
|
||||
if err != nil {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
return invite, nil
|
||||
}
|
||||
|
||||
// InviteByEmail finds an Invite with a particular email, if one exists.
|
||||
func (d *Datastore) InviteByEmail(email string) (*kolide.Invite, error) {
|
||||
invite := &kolide.Invite{}
|
||||
err := d.db.Get(invite, "SELECT * FROM invites WHERE email = ? AND NOT deleted", email)
|
||||
if err != nil {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
return invite, nil
|
||||
}
|
||||
|
||||
// SaveInvite modifies existing Invite
|
||||
func (d *Datastore) SaveInvite(i *kolide.Invite) error {
|
||||
sql := `
|
||||
UPDATE invites SET invited_by = ?, email = ?, admin = ?,
|
||||
name = ?, position = ?, token = ?
|
||||
WHERE id = ? AND NOT deleted
|
||||
`
|
||||
_, err := d.db.Exec(sql, i.InvitedBy, i.Email,
|
||||
i.Admin, i.Name, i.Position, i.Token, i.ID,
|
||||
)
|
||||
if err != nil {
|
||||
return errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
func (d *Datastore) DeleteInvite(i *kolide.Invite) error {
|
||||
i.MarkDeleted(d.clock.Now())
|
||||
sql := `
|
||||
UPDATE invites SET deleted_at = ?, deleted = ?
|
||||
WHERE id = ?
|
||||
`
|
||||
_, err := d.db.Exec(sql, i.DeletedAt, true, i.ID)
|
||||
if err != nil {
|
||||
return errors.DatabaseError(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
258
server/datastore/mysql/labels.go
Normal file
258
server/datastore/mysql/labels.go
Normal file
|
|
@ -0,0 +1,258 @@
|
|||
package mysql
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"time"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/kolide/kolide-ose/server/errors"
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
)
|
||||
|
||||
// NewLabel creates a new kolide.Label
|
||||
func (d *Datastore) NewLabel(label *kolide.Label) (*kolide.Label, error) {
|
||||
|
||||
sql := `
|
||||
INSERT INTO labels (
|
||||
name,
|
||||
description,
|
||||
query,
|
||||
platform
|
||||
) VALUES ( ?, ?, ?, ?)
|
||||
`
|
||||
result, err := d.db.Exec(sql, label.Name, label.Description, label.Query, label.Platform)
|
||||
if err != nil {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
id, _ := result.LastInsertId()
|
||||
label.ID = uint(id)
|
||||
return label, nil
|
||||
|
||||
}
|
||||
|
||||
// DeleteLabel soft deletes a kolide.Label
|
||||
func (d *Datastore) DeleteLabel(lid uint) error {
|
||||
sql := `
|
||||
UPDATE labels
|
||||
SET deleted_at = ?, deleted = TRUE
|
||||
WHERE id = ?
|
||||
`
|
||||
_, err := d.db.Exec(sql, d.clock.Now(), lid)
|
||||
return errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
// Label returns a kolide.Label identified by lid if one exists
|
||||
func (d *Datastore) Label(lid uint) (*kolide.Label, error) {
|
||||
sql := `
|
||||
SELECT * FROM labels
|
||||
WHERE id = ? AND NOT deleted
|
||||
`
|
||||
label := &kolide.Label{}
|
||||
|
||||
if err := d.db.Get(label, sql, lid); err != nil {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
return label, nil
|
||||
}
|
||||
|
||||
// ListLabels returns all labels limited or sorted by kolide.ListOptions
|
||||
func (d *Datastore) ListLabels(opt kolide.ListOptions) ([]*kolide.Label, error) {
|
||||
sql := `
|
||||
SELECT * FROM labels WHERE NOT deleted
|
||||
`
|
||||
sql = appendListOptionsToSQL(sql, opt)
|
||||
labels := []*kolide.Label{}
|
||||
|
||||
if err := d.db.Select(&labels, sql); err != nil {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
return labels, nil
|
||||
}
|
||||
|
||||
func (d *Datastore) LabelQueriesForHost(host *kolide.Host, cutoff time.Time) (map[string]string, error) {
|
||||
sqlStatment := `
|
||||
SELECT l.id, l.query
|
||||
FROM labels l
|
||||
WHERE l.platform = ?
|
||||
AND NOT l.deleted
|
||||
AND l.id NOT IN /* subtract the set of executions that are recent enough */
|
||||
(
|
||||
SELECT l.id
|
||||
FROM labels l
|
||||
JOIN label_query_executions lqe
|
||||
ON lqe.label_id = l.id
|
||||
WHERE lqe.host_id = ? AND lqe.updated_at > ?
|
||||
)
|
||||
`
|
||||
rows, err := d.db.Query(sqlStatment, host.Platform, host.ID, cutoff)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
defer rows.Close()
|
||||
results := map[string]string{}
|
||||
|
||||
for rows.Next() {
|
||||
var id, query string
|
||||
|
||||
if err = rows.Scan(&id, &query); err != nil {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
results[id] = query
|
||||
}
|
||||
|
||||
return results, nil
|
||||
|
||||
}
|
||||
|
||||
func (d *Datastore) RecordLabelQueryExecutions(host *kolide.Host, results map[string]bool, updated time.Time) error {
|
||||
sqlStatement := `
|
||||
INSERT INTO label_query_executions (updated_at, matches, label_id, host_id) VALUES
|
||||
|
||||
`
|
||||
vals := []interface{}{}
|
||||
bindvars := ""
|
||||
|
||||
for labelID, result := range results {
|
||||
if bindvars != "" {
|
||||
bindvars += ","
|
||||
}
|
||||
bindvars += "(?,?,?,?)"
|
||||
vals = append(vals, updated, result, labelID, host.ID)
|
||||
}
|
||||
|
||||
sqlStatement += bindvars
|
||||
sqlStatement += `
|
||||
ON DUPLICATE KEY UPDATE
|
||||
updated_at = VALUES(updated_at),
|
||||
matches = VALUES(matches)
|
||||
`
|
||||
|
||||
_, err := d.db.Exec(sqlStatement, vals...)
|
||||
if err != nil {
|
||||
return errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
// ListLabelsForHost returns a list of kolide.Label for a given host id.
|
||||
func (d *Datastore) ListLabelsForHost(hid uint) ([]kolide.Label, error) {
|
||||
sqlStatement := `
|
||||
SELECT labels.* from labels, label_query_executions lqe
|
||||
WHERE lqe.host_id = ?
|
||||
AND lqe.label_id = labels.id
|
||||
AND lqe.matches
|
||||
AND NOT labels.deleted
|
||||
`
|
||||
|
||||
labels := []kolide.Label{}
|
||||
err := d.db.Select(&labels, sqlStatement, hid)
|
||||
if err != nil {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
return labels, nil
|
||||
|
||||
}
|
||||
|
||||
// ListHostsInLabel returns a list of kolide.Host that are associated
|
||||
// with kolide.Label referened by Label ID
|
||||
func (d *Datastore) ListHostsInLabel(lid uint) ([]kolide.Host, error) {
|
||||
sqlStatement := `
|
||||
SELECT h.*
|
||||
FROM label_query_executions lqe
|
||||
JOIN hosts h
|
||||
ON lqe.host_id = h.id
|
||||
WHERE lqe.label_id = ?
|
||||
AND lqe.matches = 1
|
||||
AND NOT h.deleted
|
||||
`
|
||||
hosts := []kolide.Host{}
|
||||
err := d.db.Select(&hosts, sqlStatement, lid)
|
||||
if err != nil {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
return hosts, nil
|
||||
}
|
||||
|
||||
func (d *Datastore) ListUniqueHostsInLabels(labels []uint) ([]kolide.Host, error) {
|
||||
sqlStatement := `
|
||||
SELECT h.*
|
||||
FROM label_query_executions lqe
|
||||
JOIN hosts h
|
||||
ON lqe.host_id = h.id
|
||||
WHERE lqe.label_id IN (?)
|
||||
AND lqe.matches = 1
|
||||
AND NOT h.deleted
|
||||
GROUP BY h.id;
|
||||
`
|
||||
query, args, err := sqlx.In(sqlStatement, labels)
|
||||
if err != nil {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
query = d.db.Rebind(query)
|
||||
hosts := []kolide.Host{}
|
||||
err = d.db.Select(&hosts, query, args...)
|
||||
if err != nil {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
return hosts, nil
|
||||
|
||||
}
|
||||
|
||||
func (d *Datastore) searchLabelsWithOmits(query string, omit ...uint) ([]kolide.Label, error) {
|
||||
sqlStatement := `
|
||||
SELECT *
|
||||
FROM labels
|
||||
WHERE MATCH(name)
|
||||
AGAINST('` + query + "*" + `' IN BOOLEAN MODE)
|
||||
AND NOT deleted
|
||||
AND id NOT IN (?)
|
||||
LIMIT 10
|
||||
`
|
||||
sql, args, err := sqlx.In(sqlStatement, omit)
|
||||
if err != nil {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
sql = d.db.Rebind(sql)
|
||||
|
||||
matches := []kolide.Label{}
|
||||
err = d.db.Select(&matches, sql, args...)
|
||||
if err != nil {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
return matches, nil
|
||||
}
|
||||
|
||||
// SearchLabels performs wildcard searches on kolide.Label name
|
||||
func (d *Datastore) SearchLabels(query string, omit ...uint) ([]kolide.Label, error) {
|
||||
|
||||
if len(omit) > 0 {
|
||||
return d.searchLabelsWithOmits(query, omit...)
|
||||
}
|
||||
|
||||
sqlStatement := `
|
||||
SELECT *
|
||||
FROM labels
|
||||
WHERE MATCH(name)
|
||||
AGAINST(? IN BOOLEAN MODE)
|
||||
AND NOT deleted
|
||||
LIMIT 10
|
||||
`
|
||||
matches := []kolide.Label{}
|
||||
err := d.db.Select(&matches, sqlStatement, query+"*")
|
||||
if err != nil {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
return matches, nil
|
||||
}
|
||||
200
server/datastore/mysql/packs.go
Normal file
200
server/datastore/mysql/packs.go
Normal file
|
|
@ -0,0 +1,200 @@
|
|||
package mysql
|
||||
|
||||
import (
|
||||
"github.com/kolide/kolide-ose/server/errors"
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
)
|
||||
|
||||
// NewPack creates a new Pack
|
||||
func (d *Datastore) NewPack(pack *kolide.Pack) (*kolide.Pack, error) {
|
||||
|
||||
sql := `
|
||||
INSERT INTO packs ( name, platform )
|
||||
VALUES ( ?, ?)
|
||||
`
|
||||
|
||||
result, err := d.db.Exec(sql, pack.Name, pack.Platform)
|
||||
if err != nil {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
id, _ := result.LastInsertId()
|
||||
pack.ID = uint(id)
|
||||
return pack, nil
|
||||
}
|
||||
|
||||
// SavePack stores changes to pack
|
||||
func (d *Datastore) SavePack(pack *kolide.Pack) error {
|
||||
|
||||
sql := `
|
||||
UPDATE packs
|
||||
SET name = ?, platform = ?
|
||||
WHERE id = ? AND NOT deleted
|
||||
`
|
||||
|
||||
_, err := d.db.Exec(sql, pack.Name, pack.Platform, pack.ID)
|
||||
if err != nil {
|
||||
return errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeletePack soft deletes a kolide.Pack so that it won't show up in results
|
||||
func (d *Datastore) DeletePack(pid uint) error {
|
||||
sql := `
|
||||
UPDATE packs
|
||||
SET deleted_at = ?, deleted = TRUE
|
||||
WHERE id = ?
|
||||
`
|
||||
_, err := d.db.Exec(sql, d.clock.Now(), pid)
|
||||
if err != nil {
|
||||
return errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Pack fetch kolide.Pack with matching ID
|
||||
func (d *Datastore) Pack(pid uint) (*kolide.Pack, error) {
|
||||
sql := `
|
||||
SELECT * FROM packs
|
||||
WHERE id = ? AND NOT deleted
|
||||
`
|
||||
pack := &kolide.Pack{}
|
||||
if err := d.db.Get(pack, sql, pid); err != nil {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
return pack, nil
|
||||
}
|
||||
|
||||
// ListPacks returns all kolide.Pack records limited and sorted by kolide.ListOptions
|
||||
func (d *Datastore) ListPacks(opt kolide.ListOptions) ([]*kolide.Pack, error) {
|
||||
sql := `
|
||||
SELECT * FROM packs
|
||||
WHERE NOT deleted
|
||||
`
|
||||
sql = appendListOptionsToSQL(sql, opt)
|
||||
packs := []*kolide.Pack{}
|
||||
if err := d.db.Select(&packs, sql); err != nil {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
return packs, nil
|
||||
}
|
||||
|
||||
// AddQueryToPack associates a kolide.Query with a kolide.Pack
|
||||
func (d *Datastore) AddQueryToPack(qid uint, pid uint) error {
|
||||
sql := `
|
||||
INSERT INTO pack_queries ( pack_id, query_id)
|
||||
VALUES (?, ?)
|
||||
`
|
||||
if _, err := d.db.Exec(sql, pid, qid); err != nil {
|
||||
return errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListQueriesInPack gets all kolide.Query records associated with a kolide.Pack
|
||||
func (d *Datastore) ListQueriesInPack(pack *kolide.Pack) ([]*kolide.Query, error) {
|
||||
sql := `
|
||||
SELECT
|
||||
q.id,
|
||||
q.created_at,
|
||||
q.updated_at,
|
||||
q.name,
|
||||
q.query,
|
||||
q.interval,
|
||||
q.snapshot,
|
||||
q.differential,
|
||||
q.platform,
|
||||
q.version
|
||||
FROM
|
||||
queries q
|
||||
JOIN
|
||||
pack_queries pq
|
||||
ON
|
||||
pq.query_id = q.id
|
||||
AND
|
||||
pq.pack_id = ?
|
||||
AND NOT q.deleted
|
||||
`
|
||||
queries := []*kolide.Query{}
|
||||
if err := d.db.Select(&queries, sql, pack.ID); err != nil {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
return queries, nil
|
||||
}
|
||||
|
||||
// RemoveQueryFromPack disassociated a kolide.Query from a kolide.Pack
|
||||
func (d *Datastore) RemoveQueryFromPack(query *kolide.Query, pack *kolide.Pack) error {
|
||||
sql := `
|
||||
DELETE FROM pack_queries
|
||||
WHERE pack_id = ? AND query_id = ?
|
||||
`
|
||||
if _, err := d.db.Exec(sql, pack.ID, query.ID); err != nil {
|
||||
return errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
// AddLabelToPack associates a kolide.Label with a kolide.Pack
|
||||
func (d *Datastore) AddLabelToPack(lid uint, pid uint) error {
|
||||
sql := `
|
||||
INSERT INTO pack_targets ( pack_id, type, target_id )
|
||||
VALUES ( ?, ?, ? )
|
||||
`
|
||||
_, err := d.db.Exec(sql, pid, kolide.TargetLabel, lid)
|
||||
if err != nil {
|
||||
return errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListLabelsForPack will return a list of kolide.Label records associated with kolide.Pack
|
||||
func (d *Datastore) ListLabelsForPack(pack *kolide.Pack) ([]*kolide.Label, error) {
|
||||
sql := `
|
||||
SELECT
|
||||
l.id,
|
||||
l.created_at,
|
||||
l.updated_at,
|
||||
l.name
|
||||
FROM
|
||||
labels l
|
||||
JOIN
|
||||
pack_targets pt
|
||||
ON
|
||||
pt.target_id = l.id
|
||||
WHERE
|
||||
pt.type = ?
|
||||
AND
|
||||
pt.pack_id = ?
|
||||
AND NOT l.deleted
|
||||
`
|
||||
|
||||
labels := []*kolide.Label{}
|
||||
|
||||
if err := d.db.Select(&labels, sql, kolide.TargetLabel, pack.ID); err != nil {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
return labels, nil
|
||||
}
|
||||
|
||||
// RemoreLabelFromPack will remove the association between a kolide.Label and
|
||||
// a kolide.Pack
|
||||
func (d *Datastore) RemoveLabelFromPack(label *kolide.Label, pack *kolide.Pack) error {
|
||||
sql := `
|
||||
DELETE FROM pack_labels
|
||||
WHERE target_id = ? AND pack_id = ?
|
||||
`
|
||||
if _, err := d.db.Exec(sql, label.ID, pack.ID); err != nil {
|
||||
return errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
124
server/datastore/mysql/password_reset.go
Normal file
124
server/datastore/mysql/password_reset.go
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
package mysql
|
||||
|
||||
import (
|
||||
"github.com/kolide/kolide-ose/server/errors"
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
)
|
||||
|
||||
func (d *Datastore) NewPasswordResetRequest(req *kolide.PasswordResetRequest) (*kolide.PasswordResetRequest, error) {
|
||||
sqlStatement := `
|
||||
INSERT INTO password_reset_requests
|
||||
( user_id, token)
|
||||
VALUES (?,?)
|
||||
`
|
||||
response, err := d.db.Exec(sqlStatement, req.UserID, req.Token)
|
||||
if err != nil {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
id, _ := response.LastInsertId()
|
||||
req.ID = uint(id)
|
||||
return req, nil
|
||||
|
||||
}
|
||||
|
||||
func (d *Datastore) SavePasswordResetRequest(req *kolide.PasswordResetRequest) error {
|
||||
sqlStatement := `
|
||||
UPDATE password_reset_requests SET
|
||||
expires_at = ?,
|
||||
user_id = ?,
|
||||
token = ?
|
||||
WHERE id = ?
|
||||
`
|
||||
_, err := d.db.Exec(sqlStatement, req.ExpiresAt, req.UserID, req.Token, req.ID)
|
||||
if err != nil {
|
||||
return errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Datastore) DeletePasswordResetRequest(req *kolide.PasswordResetRequest) error {
|
||||
|
||||
sqlStatement := `
|
||||
DELETE FROM password_reset_requests WHERE id = ?
|
||||
`
|
||||
_, err := d.db.Exec(sqlStatement, req.ID)
|
||||
if err != nil {
|
||||
return errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Datastore) DeletePasswordResetRequestsForUser(userID uint) error {
|
||||
sqlStatement := `
|
||||
DELETE FROM password_reset_requests WHERE user_id = ?
|
||||
`
|
||||
_, err := d.db.Exec(sqlStatement, userID)
|
||||
if err != nil {
|
||||
return errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Datastore) FindPassswordResetByID(id uint) (*kolide.PasswordResetRequest, error) {
|
||||
sqlStatement := `
|
||||
SELECT * FROM password_reset_requests
|
||||
WHERE id = ? LIMIT 1
|
||||
`
|
||||
passwordResetRequest := &kolide.PasswordResetRequest{}
|
||||
err := d.db.Get(&passwordResetRequest, sqlStatement, id)
|
||||
if err != nil {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
return passwordResetRequest, nil
|
||||
}
|
||||
|
||||
func (d *Datastore) FindPassswordResetsByUserID(id uint) ([]*kolide.PasswordResetRequest, error) {
|
||||
sqlStatement := `
|
||||
SELECT * FROM password_reset_requests
|
||||
WHERE user_id = ?
|
||||
`
|
||||
|
||||
passwordResetRequests := []*kolide.PasswordResetRequest{}
|
||||
err := d.db.Select(&passwordResetRequests, sqlStatement, id)
|
||||
if err != nil {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
return passwordResetRequests, nil
|
||||
|
||||
}
|
||||
|
||||
func (d *Datastore) FindPassswordResetByToken(token string) (*kolide.PasswordResetRequest, error) {
|
||||
sqlStatement := `
|
||||
SELECT * FROM password_reset_requests
|
||||
WHERE token = ? LIMIT 1
|
||||
`
|
||||
passwordResetRequest := &kolide.PasswordResetRequest{}
|
||||
err := d.db.Get(passwordResetRequest, sqlStatement, token)
|
||||
if err != nil {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
return passwordResetRequest, nil
|
||||
|
||||
}
|
||||
|
||||
func (d *Datastore) FindPassswordResetByTokenAndUserID(token string, id uint) (*kolide.PasswordResetRequest, error) {
|
||||
sqlStatement := `
|
||||
SELECT * FROM password_reset_requests
|
||||
WHERE user_id = ? AND token = ?
|
||||
LIMIT 1
|
||||
`
|
||||
passwordResetRequest := &kolide.PasswordResetRequest{}
|
||||
err := d.db.Get(passwordResetRequest, sqlStatement, id, token)
|
||||
if err != nil {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
return passwordResetRequest, nil
|
||||
}
|
||||
172
server/datastore/mysql/queries.go
Normal file
172
server/datastore/mysql/queries.go
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
package mysql
|
||||
|
||||
import (
|
||||
"github.com/kolide/kolide-ose/server/errors"
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
)
|
||||
|
||||
// NewQuery creates a Query
|
||||
func (d *Datastore) NewQuery(query *kolide.Query) (*kolide.Query, error) {
|
||||
|
||||
sql := `
|
||||
INSERT INTO queries ( name, description, query,
|
||||
snapshot, differential, platform, version, ` + "`interval`" + `)
|
||||
VALUES ( ?, ?, ?, ?, ?, ?, ?, ? )
|
||||
`
|
||||
|
||||
result, err := d.db.Exec(sql, query.Name, query.Description, query.Query, query.Snapshot,
|
||||
query.Differential, query.Platform, query.Version, query.Interval)
|
||||
if err != nil {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
id, _ := result.LastInsertId()
|
||||
query.ID = uint(id)
|
||||
return query, nil
|
||||
}
|
||||
|
||||
// SaveQuery saves changes to a Query.
|
||||
func (d *Datastore) SaveQuery(q *kolide.Query) error {
|
||||
sql := `
|
||||
UPDATE queries
|
||||
SET name = ?, description = ?, query = ?, ` + "`interval`" + ` = ?, snapshot = ?,
|
||||
differential = ?, platform = ?, version = ?
|
||||
WHERE id = ? AND NOT deleted
|
||||
`
|
||||
_, err := d.db.Exec(sql, q.Name, q.Description, q.Query, q.Interval,
|
||||
q.Snapshot, q.Differential, q.Platform, q.Version, q.ID)
|
||||
if err != nil {
|
||||
return errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteQuery soft deletes Query identified by Query.ID
|
||||
func (d *Datastore) DeleteQuery(query *kolide.Query) error {
|
||||
query.MarkDeleted(d.clock.Now())
|
||||
sql := `
|
||||
UPDATE queries
|
||||
SET deleted_at = ?, deleted = ?
|
||||
WHERE id = ?
|
||||
`
|
||||
_, err := d.db.Exec(sql, query.DeletedAt, true, query.ID)
|
||||
if err != nil {
|
||||
return errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Query returns a single Query identified by id, if such
|
||||
// exists
|
||||
func (d *Datastore) Query(id uint) (*kolide.Query, error) {
|
||||
sql := `
|
||||
SELECT * FROM queries WHERE id = ? AND NOT deleted
|
||||
`
|
||||
query := &kolide.Query{}
|
||||
if err := d.db.Get(query, sql, id); err != nil {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
return query, nil
|
||||
}
|
||||
|
||||
// ListQueries returns a list of queries with sort order and results limit
|
||||
// determined by passed in kolide.ListOptions
|
||||
func (d *Datastore) ListQueries(opt kolide.ListOptions) ([]*kolide.Query, error) {
|
||||
sql := `
|
||||
SELECT * FROM queries WHERE NOT deleted
|
||||
`
|
||||
sql = appendListOptionsToSQL(sql, opt)
|
||||
results := []*kolide.Query{}
|
||||
|
||||
if err := d.db.Select(&results, sql); err != nil {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
return results, nil
|
||||
|
||||
}
|
||||
|
||||
func (d *Datastore) SaveDistributedQueryCampaign(camp *kolide.DistributedQueryCampaign) error {
|
||||
|
||||
sqlStatement := `
|
||||
UPDATE distributed_query_campaigns SET
|
||||
query_id = ?,
|
||||
max_duration = ?,
|
||||
status = ?,
|
||||
user_id = ?
|
||||
WHERE id = ?
|
||||
AND NOT deleted
|
||||
`
|
||||
_, err := d.db.Exec(sqlStatement, camp.QueryID, camp.MaxDuration,
|
||||
camp.Status, camp.UserID, camp.ID)
|
||||
if err != nil {
|
||||
return errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Datastore) NewDistributedQueryCampaign(camp *kolide.DistributedQueryCampaign) (*kolide.DistributedQueryCampaign, error) {
|
||||
|
||||
sqlStatement := `
|
||||
INSERT INTO distributed_query_campaigns (
|
||||
query_id,
|
||||
max_duration,
|
||||
status,
|
||||
user_id
|
||||
)
|
||||
VALUES(?,?,?,?)
|
||||
`
|
||||
result, err := d.db.Exec(sqlStatement, camp.QueryID, camp.MaxDuration, camp.Status, camp.UserID)
|
||||
if err != nil {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
id, _ := result.LastInsertId()
|
||||
camp.ID = uint(id)
|
||||
return camp, nil
|
||||
}
|
||||
|
||||
func (d *Datastore) NewDistributedQueryCampaignTarget(target *kolide.DistributedQueryCampaignTarget) (*kolide.DistributedQueryCampaignTarget, error) {
|
||||
sqlStatement := `
|
||||
INSERT into distributed_query_campaign_targets (
|
||||
type,
|
||||
distributed_query_campaign_id,
|
||||
target_id
|
||||
)
|
||||
VALUES (?,?,?)
|
||||
`
|
||||
result, err := d.db.Exec(sqlStatement, target.Type, target.DistributedQueryCampaignID, target.TargetID)
|
||||
if err != nil {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
id, _ := result.LastInsertId()
|
||||
target.ID = uint(id)
|
||||
return target, nil
|
||||
}
|
||||
|
||||
func (d *Datastore) NewDistributedQueryExecution(exec *kolide.DistributedQueryExecution) (*kolide.DistributedQueryExecution, error) {
|
||||
sqlStatement := `
|
||||
INSERT INTO distributed_query_executions (
|
||||
host_id,
|
||||
distributed_query_campaign_id,
|
||||
status,
|
||||
error,
|
||||
execution_duration
|
||||
) VALUES (?,?,?,?,?)
|
||||
`
|
||||
result, err := d.db.Exec(sqlStatement, exec.HostID, exec.DistributedQueryCampaignID,
|
||||
exec.Status, exec.Error, exec.ExecutionDuration)
|
||||
if err != nil {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
id, _ := result.LastInsertId()
|
||||
exec.ID = uint(id)
|
||||
|
||||
return exec, nil
|
||||
}
|
||||
106
server/datastore/mysql/sessions.go
Normal file
106
server/datastore/mysql/sessions.go
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
package mysql
|
||||
|
||||
import (
|
||||
"github.com/kolide/kolide-ose/server/errors"
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
)
|
||||
|
||||
func (d *Datastore) SessionByKey(key string) (*kolide.Session, error) {
|
||||
sqlStatement := `
|
||||
SELECT * FROM sessions
|
||||
WHERE key = ? LIMIT 1
|
||||
`
|
||||
session := &kolide.Session{}
|
||||
err := d.db.Get(session, sqlStatement, key)
|
||||
if err != nil {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
return session, nil
|
||||
}
|
||||
|
||||
func (d *Datastore) SessionByID(id uint) (*kolide.Session, error) {
|
||||
sqlStatement := `
|
||||
SELECT * FROM sessions
|
||||
WHERE id = ?
|
||||
LIMIT 1
|
||||
`
|
||||
session := &kolide.Session{}
|
||||
err := d.db.Get(session, sqlStatement, id)
|
||||
if err != nil {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
return session, nil
|
||||
}
|
||||
|
||||
func (d *Datastore) ListSessionsForUser(id uint) ([]*kolide.Session, error) {
|
||||
sqlStatement := `
|
||||
SELECT * FROM sessions
|
||||
WHERE user_id = ?
|
||||
`
|
||||
sessions := []*kolide.Session{}
|
||||
err := d.db.Select(&sessions, sqlStatement, id)
|
||||
if err != nil {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
return sessions, nil
|
||||
|
||||
}
|
||||
|
||||
func (d *Datastore) NewSession(session *kolide.Session) (*kolide.Session, error) {
|
||||
sqlStatement := `
|
||||
INSERT INTO sessions (
|
||||
user_id,
|
||||
key
|
||||
)
|
||||
VALUES(?,?,?,?)
|
||||
`
|
||||
result, err := d.db.Exec(sqlStatement, session.UserID, session.Key)
|
||||
if err != nil {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
id, _ := result.LastInsertId()
|
||||
session.ID = uint(id)
|
||||
return session, nil
|
||||
}
|
||||
|
||||
func (d *Datastore) DestroySession(session *kolide.Session) error {
|
||||
sqlStatement := `
|
||||
DELETE FROM sessions WHERE id = ?
|
||||
`
|
||||
_, err := d.db.Exec(sqlStatement, session.ID)
|
||||
if err != nil {
|
||||
return errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Datastore) DestroyAllSessionsForUser(id uint) error {
|
||||
sqlStatement := `
|
||||
DELETE FROM sessions WHERE user_id = ?
|
||||
`
|
||||
_, err := d.db.Exec(sqlStatement, id)
|
||||
if err != nil {
|
||||
return errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Datastore) MarkSessionAccessed(session *kolide.Session) error {
|
||||
sqlStatement := `
|
||||
UPDATE sessions SET
|
||||
accessed_at = ?
|
||||
WHERE id = ?
|
||||
`
|
||||
_, err := d.db.Exec(sqlStatement, d.clock.Now(), session.ID)
|
||||
if err != nil {
|
||||
return errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
107
server/datastore/mysql/users.go
Normal file
107
server/datastore/mysql/users.go
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
package mysql
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/kolide/kolide-ose/server/errors"
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
)
|
||||
|
||||
// NewUser creates a new user
|
||||
func (d *Datastore) NewUser(user *kolide.User) (*kolide.User, error) {
|
||||
sqlStatement := `
|
||||
INSERT INTO users (
|
||||
password,
|
||||
salt,
|
||||
name,
|
||||
username,
|
||||
email,
|
||||
admin,
|
||||
enabled,
|
||||
admin_forced_password_reset,
|
||||
gravatar_url,
|
||||
position
|
||||
) VALUES (?,?,?,?,?,?,?,?,?,?)
|
||||
`
|
||||
result, err := d.db.Exec(sqlStatement, user.Password, user.Salt, user.Name,
|
||||
user.Username, user.Email, user.Admin, user.Enabled,
|
||||
user.AdminForcedPasswordReset, user.GravatarURL, user.Position)
|
||||
if err != nil {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
id, _ := result.LastInsertId()
|
||||
user.ID = uint(id)
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func (d *Datastore) findUser(searchCol string, searchVal interface{}) (*kolide.User, error) {
|
||||
sqlStatement := fmt.Sprintf(
|
||||
"SELECT * FROM users "+
|
||||
"WHERE %s = ? AND NOT deleted LIMIT 1",
|
||||
searchCol,
|
||||
)
|
||||
|
||||
user := &kolide.User{}
|
||||
|
||||
if err := d.db.Get(user, sqlStatement, searchVal); err != nil {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
|
||||
// User retrieves a user by name
|
||||
func (d *Datastore) User(username string) (*kolide.User, error) {
|
||||
return d.findUser("username", username)
|
||||
}
|
||||
|
||||
// ListUsers lists all users with limit, sort and offset passed in with
|
||||
// kolide.ListOptions
|
||||
func (d *Datastore) ListUsers(opt kolide.ListOptions) ([]*kolide.User, error) {
|
||||
sqlStatement := `
|
||||
SELECT * FROM USERS WHERE NOT deleted
|
||||
`
|
||||
sqlStatement = appendListOptionsToSQL(sqlStatement, opt)
|
||||
users := []*kolide.User{}
|
||||
|
||||
if err := d.db.Select(&users, sqlStatement); err != nil {
|
||||
return nil, errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
return users, nil
|
||||
|
||||
}
|
||||
|
||||
func (d *Datastore) UserByEmail(email string) (*kolide.User, error) {
|
||||
return d.findUser("email", email)
|
||||
}
|
||||
|
||||
func (d *Datastore) UserByID(id uint) (*kolide.User, error) {
|
||||
return d.findUser("id", id)
|
||||
}
|
||||
|
||||
func (d *Datastore) SaveUser(user *kolide.User) error {
|
||||
sqlStatement := `
|
||||
UPDATE users SET
|
||||
username = ?,
|
||||
password = ?,
|
||||
salt = ?,
|
||||
name = ?,
|
||||
email = ?,
|
||||
admin = ?,
|
||||
enabled = ?,
|
||||
admin_forced_password_reset = ?,
|
||||
gravatar_url = ?,
|
||||
position = ?
|
||||
WHERE id = ?
|
||||
`
|
||||
_, err := d.db.Exec(sqlStatement, user.Username, user.Password,
|
||||
user.Salt, user.Name, user.Email, user.Admin, user.Enabled,
|
||||
user.AdminForcedPasswordReset, user.GravatarURL, user.Position, user.ID)
|
||||
if err != nil {
|
||||
return errors.DatabaseError(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -5,11 +5,13 @@ import (
|
|||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
"github.com/WatchBeam/clock"
|
||||
"github.com/go-kit/kit/log"
|
||||
"github.com/kolide/kolide-ose/server/datastore/mysql"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func setupGorm(t *testing.T) (ds kolide.Datastore, teardown func()) {
|
||||
func setupMySQL(t *testing.T) (ds *mysql.Datastore, teardown func()) {
|
||||
var (
|
||||
user = "kolide"
|
||||
password = "kolide"
|
||||
|
|
@ -17,33 +19,40 @@ func setupGorm(t *testing.T) (ds kolide.Datastore, teardown func()) {
|
|||
host = "127.0.0.1"
|
||||
)
|
||||
|
||||
// use linked container if available.
|
||||
if h, ok := os.LookupEnv("MYSQL_PORT_3306_TCP_ADDR"); ok {
|
||||
host = h
|
||||
}
|
||||
|
||||
connString := fmt.Sprintf("%s:%s@(%s:3306)/%s?charset=utf8&parseTime=True&loc=Local", user, password, host, dbName)
|
||||
ds, err := New("gorm-mysql", connString)
|
||||
|
||||
ds, err := mysql.New(connString, clock.NewMockClock(), mysql.Logger(log.NewNopLogger()), mysql.LimitAttempts(1))
|
||||
require.Nil(t, err)
|
||||
teardown = func() {
|
||||
db, ok := ds.(gormDB)
|
||||
if !ok {
|
||||
panic("expected gormDB datastore")
|
||||
}
|
||||
require.Nil(t, db.Drop())
|
||||
db.DB.Close()
|
||||
ds.Close()
|
||||
}
|
||||
|
||||
return ds, teardown
|
||||
}
|
||||
|
||||
func TestGorm(t *testing.T) {
|
||||
func TestMySQL(t *testing.T) {
|
||||
if _, ok := os.LookupEnv("MYSQL_TEST"); !ok {
|
||||
t.SkipNow()
|
||||
}
|
||||
|
||||
ds, teardown := setupMySQL(t)
|
||||
defer teardown()
|
||||
// get rid of database if it is hanging around
|
||||
err := ds.Drop()
|
||||
require.Nil(t, err)
|
||||
|
||||
for _, f := range testFunctions {
|
||||
|
||||
t.Run(functionName(f), func(t *testing.T) {
|
||||
ds, teardown := setupGorm(t)
|
||||
defer teardown()
|
||||
require.Nil(t, ds.Migrate())
|
||||
defer func() { require.Nil(t, ds.Drop()) }()
|
||||
|
||||
f(t, ds)
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,14 +1,22 @@
|
|||
package errors
|
||||
|
||||
import (
|
||||
goerrs "errors"
|
||||
"net/http"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/jinzhu/gorm"
|
||||
"gopkg.in/go-playground/validator.v8"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrNotFound is returned when the datastore resource cannot be found
|
||||
ErrNotFound = goerrs.New("resource not found")
|
||||
|
||||
// ErrExists is returned when creating a datastore resource that already exists
|
||||
ErrExists = goerrs.New("resource already created")
|
||||
)
|
||||
|
||||
// Kolide's internal representation for errors. It can be used to wrap another
|
||||
// error (stored in Err), and additionally contains fields for public
|
||||
// (PublicMessage) and private (PrivateMessage) error messages as well as the
|
||||
|
|
@ -113,11 +121,6 @@ func baseReturnError(c *gin.Context, err error, messageKey string) {
|
|||
})
|
||||
logrus.WithError(typedErr).Debug("Validation error")
|
||||
|
||||
case gorm.Errors, *gorm.Errors:
|
||||
c.JSON(http.StatusInternalServerError,
|
||||
gin.H{messageKey: "Database error"})
|
||||
logrus.WithError(typedErr).Debug(typedErr.Error())
|
||||
|
||||
default:
|
||||
c.JSON(http.StatusInternalServerError,
|
||||
gin.H{messageKey: "Unspecified error"})
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/jinzhu/gorm"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gopkg.in/go-playground/validator.v8"
|
||||
)
|
||||
|
|
@ -173,21 +173,3 @@ func TestReturnErrorValidationError(t *testing.T) {
|
|||
|
||||
assert.Equal(t, expect, compFields)
|
||||
}
|
||||
|
||||
func TestReturnErrorGormError(t *testing.T) {
|
||||
r := gin.New()
|
||||
|
||||
r.POST("/foo", func(c *gin.Context) {
|
||||
err := gorm.Errors{}
|
||||
err.Add(gorm.ErrInvalidSQL)
|
||||
ReturnError(c, err)
|
||||
})
|
||||
|
||||
req, _ := http.NewRequest("POST", "/foo", nil)
|
||||
resp := httptest.NewRecorder()
|
||||
|
||||
r.ServeHTTP(resp, req)
|
||||
assert.Equal(t, http.StatusInternalServerError, resp.Code)
|
||||
|
||||
assert.JSONEq(t, `{"message": "Database error"}`, resp.Body.String())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,10 +21,10 @@ type AppConfigService interface {
|
|||
// AppConfig holds configuration about the Kolide application.
|
||||
// AppConfig data can be managed by a Kolide API user.
|
||||
type AppConfig struct {
|
||||
ID uint `gorm:"primary_key"`
|
||||
OrgName string
|
||||
OrgLogoURL string
|
||||
KolideServerURL string
|
||||
ID int64
|
||||
OrgName string `db:"org_name"`
|
||||
OrgLogoURL string `db:"org_logo_url"`
|
||||
KolideServerURL string `db:"kolide_server_url"`
|
||||
}
|
||||
|
||||
// AppConfigPayload contains request and response format of
|
||||
|
|
@ -36,8 +36,8 @@ type AppConfigPayload struct {
|
|||
|
||||
// OrgInfo contains general info about the organization using Kolide.
|
||||
type OrgInfo struct {
|
||||
OrgName *string `json:"org_name,omitempty"`
|
||||
OrgLogoURL *string `json:"org_logo_url,omitempty"`
|
||||
OrgName *string `json:"org_name,omitempty" db:"org_name"`
|
||||
OrgLogoURL *string `json:"org_logo_url,omitempty" db:"org_logo_url"`
|
||||
}
|
||||
|
||||
// ServerSettings contains general settings about the kolide App.
|
||||
|
|
|
|||
|
|
@ -38,12 +38,11 @@ type MailService interface {
|
|||
// PasswordResetRequest represents a database table for
|
||||
// Password Reset Requests
|
||||
type PasswordResetRequest struct {
|
||||
ID uint `gorm:"primary_key"`
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
ExpiresAt time.Time
|
||||
UserID uint
|
||||
Token string `gorm:"size:1024"`
|
||||
UpdateCreateTimestamps
|
||||
ID uint
|
||||
ExpiresAt time.Time `db:"expires_at"`
|
||||
UserID uint `db:"user_id"`
|
||||
Token string
|
||||
}
|
||||
|
||||
const passwordResetTemplate = `
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
package kolide
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
|
@ -15,7 +17,7 @@ type HostStore interface {
|
|||
EnrollHost(uuid, hostname, ip, platform string, nodeKeySize int) (*Host, error)
|
||||
AuthenticateHost(nodeKey string) (*Host, error)
|
||||
MarkHostSeen(host *Host, t time.Time) error
|
||||
SearchHosts(query string, omit []uint) ([]Host, error)
|
||||
SearchHosts(query string, omit ...uint) ([]Host, error)
|
||||
// DistributedQueriesForHost retrieves the distributed queries that the
|
||||
// given host should run. The result map is a mapping from campaign ID
|
||||
// to query text.
|
||||
|
|
@ -30,18 +32,30 @@ type HostService interface {
|
|||
}
|
||||
|
||||
type Host struct {
|
||||
ID uint `json:"id" gorm:"primary_key"`
|
||||
CreatedAt time.Time `json:"-"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
DetailUpdateTime time.Time `json:"detail_updated_at"` // Time that the host details were last updated
|
||||
NodeKey string `json:"-" gorm:"unique_index:idx_host_unique_nodekey"`
|
||||
HostName string `json:"hostname"` // there is a fulltext index on this field
|
||||
UUID string `json:"uuid" gorm:"unique_index:idx_host_unique_uuid"`
|
||||
UpdateCreateTimestamps
|
||||
DeleteFields
|
||||
ID uint `json:"id"`
|
||||
DetailUpdateTime time.Time `json:"detail_updated_at" db:"detail_update_time"` // Time that the host details were last updated
|
||||
NodeKey string `json:"-" db:"node_key"`
|
||||
HostName string `json:"hostname" db:"host_name"` // there is a fulltext index on this field
|
||||
UUID string `json:"uuid"`
|
||||
Platform string `json:"platform"`
|
||||
OsqueryVersion string `json:"osquery_version"`
|
||||
OSVersion string `json:"os_version"`
|
||||
OsqueryVersion string `json:"osquery_version" db:"osquery_version"`
|
||||
OSVersion string `json:"os_version" db:"os_version"`
|
||||
Uptime time.Duration `json:"uptime"`
|
||||
PhysicalMemory int `json:"memory" sql:"type:bigint"`
|
||||
PrimaryMAC string `json:"mac"`
|
||||
PrimaryIP string `json:"ip"` // there is a fulltext index on this field
|
||||
PhysicalMemory int `json:"memory" sql:"type:bigint" db:"physical_memory"`
|
||||
PrimaryMAC string `json:"mac" db:"primary_mac"`
|
||||
PrimaryIP string `json:"ip" db:"primary_ip"` // there is a fulltext index on this field
|
||||
}
|
||||
|
||||
// RandomText returns a stdEncoded string of
|
||||
// just what it says
|
||||
func RandomText(keySize int) (string, error) {
|
||||
key := make([]byte, keySize)
|
||||
_, err := rand.Read(key)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return base64.StdEncoding.EncodeToString(key), nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ package kolide
|
|||
import (
|
||||
"bytes"
|
||||
"html/template"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
|
@ -58,14 +57,15 @@ type InvitePayload struct {
|
|||
|
||||
// Invite represents an invitation for a user to join Kolide.
|
||||
type Invite struct {
|
||||
ID uint `json:"id" gorm:"primary_key"`
|
||||
CreatedAt time.Time `json:"-"`
|
||||
InvitedBy uint `json:"invited_by" gorm:"not null"`
|
||||
Email string `json:"email" gorm:"not null;unique_index:idx_invite_unique_email"`
|
||||
Admin bool `json:"admin"`
|
||||
Name string `json:"name"`
|
||||
Position string `json:"position,omitempty"`
|
||||
Token string `json:"-" gorm:"not null;unique_index:idx_invite_unique_key"`
|
||||
UpdateCreateTimestamps
|
||||
DeleteFields
|
||||
ID uint `json:"id" gorm:"primary_key"`
|
||||
InvitedBy uint `json:"invited_by" gorm:"not null" db:"invited_by"`
|
||||
Email string `json:"email" gorm:"not null;unique_index:idx_invite_unique_email"`
|
||||
Admin bool `json:"admin"`
|
||||
Name string `json:"name"`
|
||||
Position string `json:"position,omitempty"`
|
||||
Token string `json:"-" gorm:"not null;unique_index:idx_invite_unique_key"`
|
||||
}
|
||||
|
||||
// TODO: fixme
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ type LabelStore interface {
|
|||
ListHostsInLabel(lid uint) ([]Host, error)
|
||||
ListUniqueHostsInLabels(labels []uint) ([]Host, error)
|
||||
|
||||
SearchLabels(query string, omit []uint) ([]Label, error)
|
||||
SearchLabels(query string, omit ...uint) ([]Label, error)
|
||||
}
|
||||
|
||||
type LabelService interface {
|
||||
|
|
@ -50,19 +50,19 @@ type LabelPayload struct {
|
|||
}
|
||||
|
||||
type Label struct {
|
||||
ID uint `json:"id" gorm:"primary_key"`
|
||||
CreatedAt time.Time `json:"-"`
|
||||
UpdatedAt time.Time `json:"-"`
|
||||
Name string `json:"name" gorm:"not null;unique_index:idx_label_unique_name"` // there is a fulltext index on this field
|
||||
Description string `json:"description"`
|
||||
Query string `json:"query" gorm:"not null"`
|
||||
Platform string `json:"platform"`
|
||||
UpdateCreateTimestamps
|
||||
DeleteFields
|
||||
ID uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Query string `json:"query"`
|
||||
Platform string `json:"platform"`
|
||||
}
|
||||
|
||||
type LabelQueryExecution struct {
|
||||
ID uint `gorm:"primary_key"`
|
||||
ID uint
|
||||
UpdatedAt time.Time
|
||||
Matches bool
|
||||
LabelID uint // Note we manually specify a unique index on these
|
||||
HostID uint // fields in gormDB.Migrate
|
||||
LabelID uint
|
||||
HostID uint
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import (
|
|||
|
||||
type PackStore interface {
|
||||
// Pack methods
|
||||
NewPack(pack *Pack) error
|
||||
NewPack(pack *Pack) (*Pack, error)
|
||||
SavePack(pack *Pack) error
|
||||
DeletePack(pid uint) error
|
||||
Pack(pid uint) (*Pack, error)
|
||||
|
|
@ -44,11 +44,11 @@ type PackService interface {
|
|||
}
|
||||
|
||||
type Pack struct {
|
||||
ID uint `json:"id" gorm:"primary_key"`
|
||||
CreatedAt time.Time `json:"-"`
|
||||
UpdatedAt time.Time `json:"-"`
|
||||
Name string `json:"name" gorm:"not null;unique_index:idx_pack_unique_name"`
|
||||
Platform string `json:"platform"`
|
||||
UpdateCreateTimestamps
|
||||
DeleteFields
|
||||
ID uint `json:"id" gorm:"primary_key"`
|
||||
Name string `json:"name" gorm:"not null;unique_index:idx_pack_unique_name"`
|
||||
Platform string `json:"platform"`
|
||||
}
|
||||
|
||||
type PackQuery struct {
|
||||
|
|
@ -60,7 +60,7 @@ type PackQuery struct {
|
|||
}
|
||||
|
||||
type PackTarget struct {
|
||||
ID uint `gorm:"primary_key"`
|
||||
PackID uint
|
||||
ID uint `gorm:"primary_key"`
|
||||
PackID uint
|
||||
Target
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,16 +15,16 @@ type QueryStore interface {
|
|||
ListQueries(opt ListOptions) ([]*Query, error)
|
||||
|
||||
// NewDistributedQueryCampaign creates a new distributed query campaign
|
||||
NewDistributedQueryCampaign(camp DistributedQueryCampaign) (DistributedQueryCampaign, error)
|
||||
NewDistributedQueryCampaign(camp *DistributedQueryCampaign) (*DistributedQueryCampaign, error)
|
||||
// SaveDistributedQueryCampaign updates an existing distributed query
|
||||
// campaign
|
||||
SaveDistributedQueryCampaign(camp DistributedQueryCampaign) error
|
||||
SaveDistributedQueryCampaign(camp *DistributedQueryCampaign) error
|
||||
// NewDistributedQueryCampaignTarget adds a new target to an existing
|
||||
// distributed query campaign
|
||||
NewDistributedQueryCampaignTarget(target DistributedQueryCampaignTarget) (DistributedQueryCampaignTarget, error)
|
||||
NewDistributedQueryCampaignTarget(target *DistributedQueryCampaignTarget) (*DistributedQueryCampaignTarget, error)
|
||||
// NewDistributedQueryCampaignExecution records a new execution for a
|
||||
// distributed query campaign
|
||||
NewDistributedQueryExecution(exec DistributedQueryExecution) (DistributedQueryExecution, error)
|
||||
NewDistributedQueryExecution(exec *DistributedQueryExecution) (*DistributedQueryExecution, error)
|
||||
}
|
||||
|
||||
type QueryService interface {
|
||||
|
|
@ -52,17 +52,17 @@ type PackPayload struct {
|
|||
}
|
||||
|
||||
type Query struct {
|
||||
ID uint `json:"id" gorm:"primary_key"`
|
||||
CreatedAt time.Time `json:"-"`
|
||||
UpdatedAt time.Time `json:"-"`
|
||||
Name string `json:"name" gorm:"not null;unique_index:idx_query_unique_name"`
|
||||
Description string `json:"description"`
|
||||
Query string `json:"query" gorm:"not null"`
|
||||
Interval uint `json:"interval"`
|
||||
Snapshot bool `json:"snapshot"`
|
||||
Differential bool `json:"differential"`
|
||||
Platform string `json:"platform"`
|
||||
Version string `json:"version"`
|
||||
UpdateCreateTimestamps
|
||||
DeleteFields
|
||||
ID uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Query string `json:"query"`
|
||||
Interval uint `json:"interval"`
|
||||
Snapshot bool `json:"snapshot"`
|
||||
Differential bool `json:"differential"`
|
||||
Platform string `json:"platform"`
|
||||
Version string `json:"version"`
|
||||
}
|
||||
|
||||
type DistributedQueryStatus int
|
||||
|
|
@ -74,20 +74,20 @@ const (
|
|||
)
|
||||
|
||||
type DistributedQueryCampaign struct {
|
||||
ID uint `gorm:"primary_key"`
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
QueryID uint
|
||||
MaxDuration time.Duration
|
||||
UpdateCreateTimestamps
|
||||
DeleteFields
|
||||
ID uint
|
||||
QueryID uint `db:"query_id"`
|
||||
MaxDuration time.Duration `db:"max_duration"`
|
||||
Status DistributedQueryStatus
|
||||
UserID uint
|
||||
}
|
||||
|
||||
type DistributedQueryCampaignTarget struct {
|
||||
ID uint `gorm:"primary_key"`
|
||||
ID uint
|
||||
Type TargetType
|
||||
DistributedQueryCampaignID uint `gorm:"index:idx_dqct_dqc_id"`
|
||||
TargetID uint
|
||||
DistributedQueryCampaignID uint `db:"distributed_query_campaign_id"`
|
||||
TargetID uint `db:"target_id"`
|
||||
}
|
||||
|
||||
type DistributedQueryExecutionStatus int
|
||||
|
|
@ -106,20 +106,20 @@ type DistributedQueryResult struct {
|
|||
}
|
||||
|
||||
type DistributedQueryExecution struct {
|
||||
ID uint `gorm:"primary_key"`
|
||||
HostID uint // unique index added in migrate
|
||||
DistributedQueryCampaignID uint // unique index added in migrate
|
||||
ID uint
|
||||
HostID uint `db:"host_id"`
|
||||
DistributedQueryCampaignID uint `db:"distributed_query_campaign_id"`
|
||||
Status DistributedQueryExecutionStatus
|
||||
Error string `gorm:"size:1024"`
|
||||
ExecutionDuration time.Duration
|
||||
Error string
|
||||
ExecutionDuration time.Duration `db:"execution_duration"`
|
||||
}
|
||||
|
||||
type Option struct {
|
||||
ID uint `gorm:"primary_key"`
|
||||
ID uint
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
Key string `gorm:"not null;unique_index:idx_option_unique_key"`
|
||||
Value string `gorm:"not null"`
|
||||
Key string
|
||||
Value string
|
||||
Platform string
|
||||
}
|
||||
|
||||
|
|
@ -132,10 +132,10 @@ const (
|
|||
)
|
||||
|
||||
type Decorator struct {
|
||||
ID uint `gorm:"primary_key"`
|
||||
ID uint
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
Type DecoratorType `gorm:"not null"`
|
||||
Type DecoratorType
|
||||
Interval int
|
||||
Query string
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,11 +68,11 @@ type SessionService interface {
|
|||
|
||||
// Session is the model object which represents what an active session is
|
||||
type Session struct {
|
||||
ID uint `gorm:"primary_key"`
|
||||
CreatedAt time.Time
|
||||
AccessedAt time.Time
|
||||
UserID uint `gorm:"not null"`
|
||||
Key string `gorm:"not null;unique_index:idx_session_unique_key"`
|
||||
CreateTimestamp
|
||||
ID uint `gorm:"primary_key"`
|
||||
AccessedAt time.Time `db:"accessed_at"`
|
||||
UserID uint `gorm:"not null" db:"user_id"`
|
||||
Key string `gorm:"not null;unique_index:idx_session_unique_key"`
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
33
server/kolide/traits.go
Normal file
33
server/kolide/traits.go
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
package kolide
|
||||
|
||||
import "time"
|
||||
|
||||
// Createable contains common timestamp fields indicating create time
|
||||
type CreateTimestamp struct {
|
||||
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
||||
}
|
||||
|
||||
// Deleteable is used to indicate a record is deleted. We don't actually
|
||||
// delete record in the database. We mark it deleted, records with Deleted
|
||||
// set to true will not normally be included in results
|
||||
type DeleteFields struct {
|
||||
DeletedAt *time.Time `json:"deleted_at" db:"deleted_at" gorm:"-"`
|
||||
Deleted bool `json:"deleted"`
|
||||
}
|
||||
|
||||
// MarkDeleted indicates a record is deleted. It won't actually be removed from
|
||||
// the database, but won't be returned in result sets.
|
||||
func (d *DeleteFields) MarkDeleted(deleted time.Time) {
|
||||
d.DeletedAt = &deleted
|
||||
d.Deleted = true
|
||||
}
|
||||
|
||||
// UpdateTimestamp contains a timestamp that is set whenever an entity is changed
|
||||
type UpdateTimestamp struct {
|
||||
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
|
||||
}
|
||||
|
||||
type UpdateCreateTimestamps struct {
|
||||
CreateTimestamp
|
||||
UpdateTimestamp
|
||||
}
|
||||
|
|
@ -4,7 +4,6 @@ import (
|
|||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"golang.org/x/net/context"
|
||||
|
|
@ -55,19 +54,19 @@ type UserService interface {
|
|||
|
||||
// User is the model struct which represents a kolide user
|
||||
type User struct {
|
||||
ID uint `json:"id" gorm:"primary_key"`
|
||||
CreatedAt time.Time `json:"-"`
|
||||
UpdatedAt time.Time `json:"-"`
|
||||
Username string `json:"username" gorm:"not null;unique_index:idx_user_unique_username"`
|
||||
Password []byte `json:"-" gorm:"not null"`
|
||||
Salt string `json:"-" gorm:"not null"`
|
||||
Name string `json:"name"`
|
||||
Email string `json:"email" gorm:"not null;unique_index:idx_user_unique_email"`
|
||||
Admin bool `json:"admin" gorm:"not null"`
|
||||
Enabled bool `json:"enabled" gorm:"not null"`
|
||||
AdminForcedPasswordReset bool `json:"force_password_reset"`
|
||||
GravatarURL string `json:"gravatar_url"`
|
||||
Position string `json:"position,omitempty"` // job role
|
||||
UpdateCreateTimestamps
|
||||
DeleteFields
|
||||
ID uint `json:"id" gorm:"primary_key"`
|
||||
Username string `json:"username" gorm:"not null;unique_index:idx_user_unique_username"`
|
||||
Password []byte `json:"-" gorm:"not null"`
|
||||
Salt string `json:"-" gorm:"not null"`
|
||||
Name string `json:"name"`
|
||||
Email string `json:"email" gorm:"not null;unique_index:idx_user_unique_email"`
|
||||
Admin bool `json:"admin" gorm:"not null"`
|
||||
Enabled bool `json:"enabled" gorm:"not null"`
|
||||
AdminForcedPasswordReset bool `json:"force_password_reset" db:"admin_forced_password_reset"`
|
||||
GravatarURL string `json:"gravatar_url" db:"gravatar_url"`
|
||||
Position string `json:"position,omitempty"` // job role
|
||||
}
|
||||
|
||||
// UserPayload is used to modify an existing user
|
||||
|
|
|
|||
|
|
@ -97,8 +97,12 @@ func testQueryResultsStoreErrors(t *testing.T, store kolide.QueryResultStore) {
|
|||
DistributedQueryCampaignID: 1,
|
||||
Rows: []map[string]string{{"bing": "fds"}},
|
||||
Host: kolide.Host{
|
||||
ID: 4,
|
||||
UpdatedAt: time.Now().UTC(),
|
||||
ID: 4,
|
||||
UpdateCreateTimestamps: kolide.UpdateCreateTimestamps{
|
||||
UpdateTimestamp: kolide.UpdateTimestamp{
|
||||
UpdatedAt: time.Now().UTC(),
|
||||
},
|
||||
},
|
||||
DetailUpdateTime: time.Now().UTC(),
|
||||
},
|
||||
},
|
||||
|
|
@ -123,7 +127,15 @@ func testQueryResultsStore(t *testing.T, store kolide.QueryResultStore) {
|
|||
// Note these times need to be set to avoid
|
||||
// issues with roundtrip serializing the zero
|
||||
// time value. See https://goo.gl/CCEs8x
|
||||
UpdatedAt: time.Now().UTC(),
|
||||
UpdateCreateTimestamps: kolide.UpdateCreateTimestamps{
|
||||
UpdateTimestamp: kolide.UpdateTimestamp{
|
||||
UpdatedAt: time.Now().UTC(),
|
||||
},
|
||||
CreateTimestamp: kolide.CreateTimestamp{
|
||||
CreatedAt: time.Now().UTC(),
|
||||
},
|
||||
},
|
||||
|
||||
DetailUpdateTime: time.Now().UTC(),
|
||||
},
|
||||
},
|
||||
|
|
@ -131,8 +143,16 @@ func testQueryResultsStore(t *testing.T, store kolide.QueryResultStore) {
|
|||
DistributedQueryCampaignID: 1,
|
||||
Rows: []map[string]string{{"whoo": "wahh"}},
|
||||
Host: kolide.Host{
|
||||
ID: 3,
|
||||
UpdatedAt: time.Now().UTC(),
|
||||
ID: 3,
|
||||
UpdateCreateTimestamps: kolide.UpdateCreateTimestamps{
|
||||
UpdateTimestamp: kolide.UpdateTimestamp{
|
||||
UpdatedAt: time.Now().UTC(),
|
||||
},
|
||||
CreateTimestamp: kolide.CreateTimestamp{
|
||||
CreatedAt: time.Now().UTC(),
|
||||
},
|
||||
},
|
||||
|
||||
DetailUpdateTime: time.Now().UTC(),
|
||||
},
|
||||
},
|
||||
|
|
@ -140,8 +160,16 @@ func testQueryResultsStore(t *testing.T, store kolide.QueryResultStore) {
|
|||
DistributedQueryCampaignID: 1,
|
||||
Rows: []map[string]string{{"bing": "fds"}},
|
||||
Host: kolide.Host{
|
||||
ID: 4,
|
||||
UpdatedAt: time.Now().UTC(),
|
||||
ID: 4,
|
||||
UpdateCreateTimestamps: kolide.UpdateCreateTimestamps{
|
||||
UpdateTimestamp: kolide.UpdateTimestamp{
|
||||
UpdatedAt: time.Now().UTC(),
|
||||
},
|
||||
CreateTimestamp: kolide.CreateTimestamp{
|
||||
CreatedAt: time.Now().UTC(),
|
||||
},
|
||||
},
|
||||
|
||||
DetailUpdateTime: time.Now().UTC(),
|
||||
},
|
||||
},
|
||||
|
|
@ -158,8 +186,16 @@ func testQueryResultsStore(t *testing.T, store kolide.QueryResultStore) {
|
|||
DistributedQueryCampaignID: 2,
|
||||
Rows: []map[string]string{{"tim": "tom"}},
|
||||
Host: kolide.Host{
|
||||
ID: 1,
|
||||
UpdatedAt: time.Now().UTC(),
|
||||
ID: 1,
|
||||
UpdateCreateTimestamps: kolide.UpdateCreateTimestamps{
|
||||
UpdateTimestamp: kolide.UpdateTimestamp{
|
||||
UpdatedAt: time.Now().UTC(),
|
||||
},
|
||||
CreateTimestamp: kolide.CreateTimestamp{
|
||||
CreatedAt: time.Now().UTC(),
|
||||
},
|
||||
},
|
||||
|
||||
DetailUpdateTime: time.Now().UTC(),
|
||||
},
|
||||
},
|
||||
|
|
@ -167,8 +203,16 @@ func testQueryResultsStore(t *testing.T, store kolide.QueryResultStore) {
|
|||
DistributedQueryCampaignID: 2,
|
||||
Rows: []map[string]string{{"slim": "slam"}},
|
||||
Host: kolide.Host{
|
||||
ID: 3,
|
||||
UpdatedAt: time.Now().UTC(),
|
||||
ID: 3,
|
||||
UpdateCreateTimestamps: kolide.UpdateCreateTimestamps{
|
||||
UpdateTimestamp: kolide.UpdateTimestamp{
|
||||
UpdatedAt: time.Now().UTC(),
|
||||
},
|
||||
CreateTimestamp: kolide.CreateTimestamp{
|
||||
CreatedAt: time.Now().UTC(),
|
||||
},
|
||||
},
|
||||
|
||||
DetailUpdateTime: time.Now().UTC(),
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import (
|
|||
|
||||
"github.com/go-kit/kit/endpoint"
|
||||
"github.com/kolide/kolide-ose/server/contexts/viewer"
|
||||
"github.com/kolide/kolide-ose/server/datastore"
|
||||
"github.com/kolide/kolide-ose/server/datastore/inmem"
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
|
@ -17,7 +17,7 @@ import (
|
|||
// permissions to access or modify resources
|
||||
func TestEndpointPermissions(t *testing.T) {
|
||||
req := struct{}{}
|
||||
ds, _ := datastore.New("inmem", "")
|
||||
ds, _ := inmem.New()
|
||||
createTestUsers(t, ds)
|
||||
admin1, _ := ds.User("admin1")
|
||||
user1, _ := ds.User("user1")
|
||||
|
|
@ -184,7 +184,7 @@ func TestGetNodeKey(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestAuthenticatedHost(t *testing.T) {
|
||||
ds, err := datastore.New("inmem", "")
|
||||
ds, err := inmem.New()
|
||||
require.Nil(t, err)
|
||||
svc, err := newTestService(ds, nil)
|
||||
require.Nil(t, err)
|
||||
|
|
|
|||
|
|
@ -6,13 +6,13 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/kolide/kolide-ose/server/datastore"
|
||||
"github.com/kolide/kolide-ose/server/datastore/inmem"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
func TestAPIRoutes(t *testing.T) {
|
||||
ds, err := datastore.New("inmem", "")
|
||||
ds, err := inmem.New()
|
||||
assert.Nil(t, err)
|
||||
|
||||
svc, err := newTestService(ds, nil)
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import (
|
|||
kitlog "github.com/go-kit/kit/log"
|
||||
kithttp "github.com/go-kit/kit/transport/http"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/kolide/kolide-ose/server/datastore"
|
||||
"github.com/kolide/kolide-ose/server/datastore/inmem"
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
|
@ -23,7 +23,7 @@ import (
|
|||
)
|
||||
|
||||
func TestLogin(t *testing.T) {
|
||||
ds, _ := datastore.New("inmem", "")
|
||||
ds, _ := inmem.New()
|
||||
svc, _ := newTestService(ds, nil)
|
||||
users := createTestUsers(t, ds)
|
||||
logger := kitlog.NewLogfmtLogger(os.Stdout)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package service
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/kolide/kolide-ose/server/datastore"
|
||||
"github.com/kolide/kolide-ose/server/datastore/inmem"
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
|
@ -11,7 +11,7 @@ import (
|
|||
)
|
||||
|
||||
func TestCreateAppConfig(t *testing.T) {
|
||||
ds, err := datastore.New("inmem", "")
|
||||
ds, err := inmem.New()
|
||||
require.Nil(t, err)
|
||||
svc, err := newTestService(ds, nil)
|
||||
require.Nil(t, err)
|
||||
|
|
|
|||
|
|
@ -3,14 +3,14 @@ package service
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/kolide/kolide-ose/server/datastore"
|
||||
"github.com/kolide/kolide-ose/server/datastore/inmem"
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
func TestListHosts(t *testing.T) {
|
||||
ds, err := datastore.New("inmem", "")
|
||||
ds, err := inmem.New()
|
||||
assert.Nil(t, err)
|
||||
|
||||
svc, err := newTestService(ds, nil)
|
||||
|
|
@ -33,7 +33,7 @@ func TestListHosts(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestGetHost(t *testing.T) {
|
||||
ds, err := datastore.New("inmem", "")
|
||||
ds, err := inmem.New()
|
||||
assert.Nil(t, err)
|
||||
|
||||
svc, err := newTestService(ds, nil)
|
||||
|
|
@ -54,7 +54,7 @@ func TestGetHost(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestDeleteHost(t *testing.T) {
|
||||
ds, err := datastore.New("inmem", "")
|
||||
ds, err := inmem.New()
|
||||
assert.Nil(t, err)
|
||||
|
||||
svc, err := newTestService(ds, nil)
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import (
|
|||
"errors"
|
||||
|
||||
jwt "github.com/dgrijalva/jwt-go"
|
||||
"github.com/kolide/kolide-ose/server/datastore"
|
||||
kolide_errors "github.com/kolide/kolide-ose/server/errors"
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
|
@ -15,7 +15,7 @@ func (svc service) InviteNewUser(ctx context.Context, payload kolide.InvitePaylo
|
|||
if err == nil {
|
||||
return nil, newInvalidArgumentError("email", "a user with this account already exists")
|
||||
}
|
||||
if err != datastore.ErrNotFound {
|
||||
if err != kolide_errors.ErrNotFound {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
|
@ -34,7 +34,6 @@ func (svc service) InviteNewUser(ctx context.Context, payload kolide.InvitePaylo
|
|||
Email: *payload.Email,
|
||||
Admin: *payload.Admin,
|
||||
InvitedBy: inviter.ID,
|
||||
CreatedAt: svc.clock.Now(),
|
||||
Token: token,
|
||||
}
|
||||
if payload.Position != nil {
|
||||
|
|
|
|||
|
|
@ -1,18 +1,20 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"golang.org/x/net/context"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/WatchBeam/clock"
|
||||
"github.com/kolide/kolide-ose/server/config"
|
||||
"github.com/kolide/kolide-ose/server/datastore"
|
||||
"github.com/kolide/kolide-ose/server/datastore/inmem"
|
||||
"github.com/kolide/kolide-ose/server/errors"
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestInviteNewUser(t *testing.T) {
|
||||
ds, err := datastore.New("inmem", "")
|
||||
ds, err := inmem.New()
|
||||
createTestUsers(t, ds)
|
||||
assert.Nil(t, err)
|
||||
nosuchAdminID := uint(999)
|
||||
|
|
@ -42,7 +44,7 @@ func TestInviteNewUser(t *testing.T) {
|
|||
InvitedBy: &nosuchAdminID,
|
||||
Admin: boolPtr(false),
|
||||
},
|
||||
wantErr: datastore.ErrNotFound,
|
||||
wantErr: errors.ErrNotFound,
|
||||
},
|
||||
{
|
||||
payload: kolide.InvitePayload{
|
||||
|
|
|
|||
|
|
@ -3,14 +3,14 @@ package service
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/kolide/kolide-ose/server/datastore"
|
||||
"github.com/kolide/kolide-ose/server/datastore/inmem"
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
func TestListLabels(t *testing.T) {
|
||||
ds, err := datastore.New("inmem", "")
|
||||
ds, err := inmem.New()
|
||||
assert.Nil(t, err)
|
||||
|
||||
svc, err := newTestService(ds, nil)
|
||||
|
|
@ -35,7 +35,7 @@ func TestListLabels(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestGetLabel(t *testing.T) {
|
||||
ds, err := datastore.New("inmem", "")
|
||||
ds, err := inmem.New()
|
||||
assert.Nil(t, err)
|
||||
|
||||
svc, err := newTestService(ds, nil)
|
||||
|
|
@ -57,7 +57,7 @@ func TestGetLabel(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestNewLabel(t *testing.T) {
|
||||
ds, err := datastore.New("inmem", "")
|
||||
ds, err := inmem.New()
|
||||
assert.Nil(t, err)
|
||||
|
||||
svc, err := newTestService(ds, nil)
|
||||
|
|
@ -82,7 +82,7 @@ func TestNewLabel(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestDeleteLabel(t *testing.T) {
|
||||
ds, err := datastore.New("inmem", "")
|
||||
ds, err := inmem.New()
|
||||
assert.Nil(t, err)
|
||||
|
||||
svc, err := newTestService(ds, nil)
|
||||
|
|
|
|||
|
|
@ -361,7 +361,7 @@ func (svc service) ingestDistributedQuery(host kolide.Host, name string, rows []
|
|||
}
|
||||
|
||||
// Record execution of the query
|
||||
exec := kolide.DistributedQueryExecution{
|
||||
exec := &kolide.DistributedQueryExecution{
|
||||
HostID: host.ID,
|
||||
DistributedQueryCampaignID: uint(campaignID),
|
||||
Status: kolide.ExecutionSucceeded,
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import (
|
|||
|
||||
"github.com/WatchBeam/clock"
|
||||
hostctx "github.com/kolide/kolide-ose/server/contexts/host"
|
||||
"github.com/kolide/kolide-ose/server/datastore"
|
||||
"github.com/kolide/kolide-ose/server/datastore/inmem"
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
"github.com/kolide/kolide-ose/server/pubsub"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
|
@ -22,7 +22,7 @@ import (
|
|||
)
|
||||
|
||||
func TestEnrollAgent(t *testing.T) {
|
||||
ds, err := datastore.New("inmem", "")
|
||||
ds, err := inmem.New()
|
||||
assert.Nil(t, err)
|
||||
|
||||
svc, err := newTestService(ds, nil)
|
||||
|
|
@ -44,7 +44,7 @@ func TestEnrollAgent(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestEnrollAgentIncorrectEnrollSecret(t *testing.T) {
|
||||
ds, err := datastore.New("inmem", "")
|
||||
ds, err := inmem.New()
|
||||
assert.Nil(t, err)
|
||||
|
||||
svc, err := newTestService(ds, nil)
|
||||
|
|
@ -66,7 +66,7 @@ func TestEnrollAgentIncorrectEnrollSecret(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestSubmitStatusLogs(t *testing.T) {
|
||||
ds, err := datastore.New("inmem", "")
|
||||
ds, err := inmem.New()
|
||||
assert.Nil(t, err)
|
||||
|
||||
mockClock := clock.NewMockClock()
|
||||
|
|
@ -138,7 +138,7 @@ func TestSubmitStatusLogs(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestSubmitResultLogs(t *testing.T) {
|
||||
ds, err := datastore.New("inmem", "")
|
||||
ds, err := inmem.New()
|
||||
assert.Nil(t, err)
|
||||
|
||||
mockClock := clock.NewMockClock()
|
||||
|
|
@ -211,9 +211,16 @@ func TestSubmitResultLogs(t *testing.T) {
|
|||
func TestHostDetailQueries(t *testing.T) {
|
||||
mockClock := clock.NewMockClock()
|
||||
host := kolide.Host{
|
||||
ID: 1,
|
||||
CreatedAt: mockClock.Now(),
|
||||
UpdatedAt: mockClock.Now(),
|
||||
ID: 1,
|
||||
UpdateCreateTimestamps: kolide.UpdateCreateTimestamps{
|
||||
UpdateTimestamp: kolide.UpdateTimestamp{
|
||||
UpdatedAt: mockClock.Now(),
|
||||
},
|
||||
CreateTimestamp: kolide.CreateTimestamp{
|
||||
CreatedAt: mockClock.Now(),
|
||||
},
|
||||
},
|
||||
|
||||
DetailUpdateTime: mockClock.Now(),
|
||||
NodeKey: "test_key",
|
||||
HostName: "test_hostname",
|
||||
|
|
@ -239,7 +246,7 @@ func TestHostDetailQueries(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestLabelQueries(t *testing.T) {
|
||||
ds, err := datastore.New("inmem", "")
|
||||
ds, err := inmem.New()
|
||||
assert.Nil(t, err)
|
||||
|
||||
mockClock := clock.NewMockClock()
|
||||
|
|
@ -366,7 +373,7 @@ func TestLabelQueries(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestGetClientConfig(t *testing.T) {
|
||||
ds, err := datastore.New("inmem", "")
|
||||
ds, err := inmem.New()
|
||||
assert.Nil(t, err)
|
||||
|
||||
mockClock := clock.NewMockClock()
|
||||
|
|
@ -415,7 +422,7 @@ func TestGetClientConfig(t *testing.T) {
|
|||
monitoringPack := &kolide.Pack{
|
||||
Name: "monitoring",
|
||||
}
|
||||
err = ds.NewPack(monitoringPack)
|
||||
_, err = ds.NewPack(monitoringPack)
|
||||
assert.Nil(t, err)
|
||||
|
||||
err = ds.AddQueryToPack(infoQuery.ID, monitoringPack.ID)
|
||||
|
|
@ -447,7 +454,7 @@ func TestGetClientConfig(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestDetailQueries(t *testing.T) {
|
||||
ds, err := datastore.New("inmem", "")
|
||||
ds, err := inmem.New()
|
||||
assert.Nil(t, err)
|
||||
|
||||
mockClock := clock.NewMockClock()
|
||||
|
|
@ -589,7 +596,7 @@ func TestDetailQueries(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestDistributedQueries(t *testing.T) {
|
||||
ds, err := datastore.New("inmem", "")
|
||||
ds, err := inmem.New()
|
||||
require.Nil(t, err)
|
||||
|
||||
mockClock := clock.NewMockClock()
|
||||
|
|
@ -633,7 +640,7 @@ func TestDistributedQueries(t *testing.T) {
|
|||
require.Nil(t, err)
|
||||
|
||||
// Create query campaign
|
||||
c1 := kolide.DistributedQueryCampaign{
|
||||
c1 := &kolide.DistributedQueryCampaign{
|
||||
QueryID: query.ID,
|
||||
Status: kolide.QueryRunning,
|
||||
}
|
||||
|
|
@ -642,7 +649,7 @@ func TestDistributedQueries(t *testing.T) {
|
|||
require.Nil(t, err)
|
||||
|
||||
// Add a target to the campaign (targeting the matching label)
|
||||
target := kolide.DistributedQueryCampaignTarget{
|
||||
target := &kolide.DistributedQueryCampaignTarget{
|
||||
Type: kolide.TargetLabel,
|
||||
DistributedQueryCampaignID: c1.ID,
|
||||
TargetID: label.ID,
|
||||
|
|
@ -678,7 +685,7 @@ func TestDistributedQueries(t *testing.T) {
|
|||
assert.NotNil(t, err)
|
||||
|
||||
// TODO use service method
|
||||
readChan, err := rs.ReadChannel(ctx, c1)
|
||||
readChan, err := rs.ReadChannel(ctx, *c1)
|
||||
require.Nil(t, err)
|
||||
|
||||
// We need to listen for the result in a separate thread to prevent the
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ func (svc service) NewPack(ctx context.Context, p kolide.PackPayload) (*kolide.P
|
|||
pack.Platform = *p.Platform
|
||||
}
|
||||
|
||||
err := svc.ds.NewPack(&pack)
|
||||
_, err := svc.ds.NewPack(&pack)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,14 +3,14 @@ package service
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/kolide/kolide-ose/server/datastore"
|
||||
"github.com/kolide/kolide-ose/server/datastore/inmem"
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
func TestListPacks(t *testing.T) {
|
||||
ds, err := datastore.New("inmem", "")
|
||||
ds, err := inmem.New()
|
||||
assert.Nil(t, err)
|
||||
|
||||
svc, err := newTestService(ds, nil)
|
||||
|
|
@ -22,7 +22,7 @@ func TestListPacks(t *testing.T) {
|
|||
assert.Nil(t, err)
|
||||
assert.Len(t, queries, 0)
|
||||
|
||||
err = ds.NewPack(&kolide.Pack{
|
||||
_, err = ds.NewPack(&kolide.Pack{
|
||||
Name: "foo",
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
|
|
@ -33,7 +33,7 @@ func TestListPacks(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestGetPack(t *testing.T) {
|
||||
ds, err := datastore.New("inmem", "")
|
||||
ds, err := inmem.New()
|
||||
assert.Nil(t, err)
|
||||
|
||||
svc, err := newTestService(ds, nil)
|
||||
|
|
@ -44,7 +44,7 @@ func TestGetPack(t *testing.T) {
|
|||
pack := &kolide.Pack{
|
||||
Name: "foo",
|
||||
}
|
||||
err = ds.NewPack(pack)
|
||||
_, err = ds.NewPack(pack)
|
||||
assert.Nil(t, err)
|
||||
assert.NotZero(t, pack.ID)
|
||||
|
||||
|
|
@ -55,7 +55,7 @@ func TestGetPack(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestNewPack(t *testing.T) {
|
||||
ds, err := datastore.New("inmem", "")
|
||||
ds, err := inmem.New()
|
||||
assert.Nil(t, err)
|
||||
|
||||
svc, err := newTestService(ds, nil)
|
||||
|
|
@ -76,7 +76,7 @@ func TestNewPack(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestModifyPack(t *testing.T) {
|
||||
ds, err := datastore.New("inmem", "")
|
||||
ds, err := inmem.New()
|
||||
assert.Nil(t, err)
|
||||
|
||||
svc, err := newTestService(ds, nil)
|
||||
|
|
@ -87,7 +87,7 @@ func TestModifyPack(t *testing.T) {
|
|||
pack := &kolide.Pack{
|
||||
Name: "foo",
|
||||
}
|
||||
err = ds.NewPack(pack)
|
||||
_, err = ds.NewPack(pack)
|
||||
assert.Nil(t, err)
|
||||
assert.NotZero(t, pack.ID)
|
||||
|
||||
|
|
@ -102,7 +102,7 @@ func TestModifyPack(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestDeletePack(t *testing.T) {
|
||||
ds, err := datastore.New("inmem", "")
|
||||
ds, err := inmem.New()
|
||||
assert.Nil(t, err)
|
||||
|
||||
svc, err := newTestService(ds, nil)
|
||||
|
|
@ -113,7 +113,7 @@ func TestDeletePack(t *testing.T) {
|
|||
pack := &kolide.Pack{
|
||||
Name: "foo",
|
||||
}
|
||||
err = ds.NewPack(pack)
|
||||
_, err = ds.NewPack(pack)
|
||||
assert.Nil(t, err)
|
||||
assert.NotZero(t, pack.ID)
|
||||
|
||||
|
|
@ -127,7 +127,7 @@ func TestDeletePack(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestAddQueryToPack(t *testing.T) {
|
||||
ds, err := datastore.New("inmem", "")
|
||||
ds, err := inmem.New()
|
||||
assert.Nil(t, err)
|
||||
|
||||
svc, err := newTestService(ds, nil)
|
||||
|
|
@ -138,7 +138,7 @@ func TestAddQueryToPack(t *testing.T) {
|
|||
pack := &kolide.Pack{
|
||||
Name: "foo",
|
||||
}
|
||||
err = ds.NewPack(pack)
|
||||
_, err = ds.NewPack(pack)
|
||||
assert.Nil(t, err)
|
||||
assert.NotZero(t, pack.ID)
|
||||
|
||||
|
|
@ -163,7 +163,7 @@ func TestAddQueryToPack(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestGetQueriesInPack(t *testing.T) {
|
||||
ds, err := datastore.New("inmem", "")
|
||||
ds, err := inmem.New()
|
||||
assert.Nil(t, err)
|
||||
|
||||
svc, err := newTestService(ds, nil)
|
||||
|
|
@ -174,7 +174,7 @@ func TestGetQueriesInPack(t *testing.T) {
|
|||
pack := &kolide.Pack{
|
||||
Name: "foo",
|
||||
}
|
||||
err = ds.NewPack(pack)
|
||||
_, err = ds.NewPack(pack)
|
||||
assert.Nil(t, err)
|
||||
assert.NotZero(t, pack.ID)
|
||||
|
||||
|
|
@ -195,7 +195,7 @@ func TestGetQueriesInPack(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestRemoveQueryFromPack(t *testing.T) {
|
||||
ds, err := datastore.New("inmem", "")
|
||||
ds, err := inmem.New()
|
||||
assert.Nil(t, err)
|
||||
|
||||
svc, err := newTestService(ds, nil)
|
||||
|
|
@ -206,7 +206,7 @@ func TestRemoveQueryFromPack(t *testing.T) {
|
|||
pack := &kolide.Pack{
|
||||
Name: "foo",
|
||||
}
|
||||
err = ds.NewPack(pack)
|
||||
_, err = ds.NewPack(pack)
|
||||
assert.Nil(t, err)
|
||||
assert.NotZero(t, pack.ID)
|
||||
|
||||
|
|
|
|||
|
|
@ -3,14 +3,14 @@ package service
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/kolide/kolide-ose/server/datastore"
|
||||
"github.com/kolide/kolide-ose/server/datastore/inmem"
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
func TestListQueries(t *testing.T) {
|
||||
ds, err := datastore.New("inmem", "")
|
||||
ds, err := inmem.New()
|
||||
assert.Nil(t, err)
|
||||
|
||||
svc, err := newTestService(ds, nil)
|
||||
|
|
@ -34,7 +34,7 @@ func TestListQueries(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestGetQuery(t *testing.T) {
|
||||
ds, err := datastore.New("inmem", "")
|
||||
ds, err := inmem.New()
|
||||
assert.Nil(t, err)
|
||||
|
||||
svc, err := newTestService(ds, nil)
|
||||
|
|
@ -57,7 +57,7 @@ func TestGetQuery(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestNewQuery(t *testing.T) {
|
||||
ds, err := datastore.New("inmem", "")
|
||||
ds, err := inmem.New()
|
||||
assert.Nil(t, err)
|
||||
|
||||
svc, err := newTestService(ds, nil)
|
||||
|
|
@ -80,7 +80,7 @@ func TestNewQuery(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestModifyQuery(t *testing.T) {
|
||||
ds, err := datastore.New("inmem", "")
|
||||
ds, err := inmem.New()
|
||||
assert.Nil(t, err)
|
||||
|
||||
svc, err := newTestService(ds, nil)
|
||||
|
|
@ -107,7 +107,7 @@ func TestModifyQuery(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestDeleteQuery(t *testing.T) {
|
||||
ds, err := datastore.New("inmem", "")
|
||||
ds, err := inmem.New()
|
||||
assert.Nil(t, err)
|
||||
|
||||
svc, err := newTestService(ds, nil)
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/kolide/kolide-ose/server/contexts/viewer"
|
||||
"github.com/kolide/kolide-ose/server/datastore"
|
||||
"github.com/kolide/kolide-ose/server/errors"
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
|
@ -16,7 +16,7 @@ func (svc service) Login(ctx context.Context, username, password string) (*kolid
|
|||
user, err := svc.userByEmailOrUsername(username)
|
||||
switch err {
|
||||
case nil:
|
||||
case datastore.ErrNotFound:
|
||||
case errors.ErrNotFound:
|
||||
return nil, "", authError{reason: "no such user"}
|
||||
default:
|
||||
return nil, "", err
|
||||
|
|
@ -24,7 +24,7 @@ func (svc service) Login(ctx context.Context, username, password string) (*kolid
|
|||
if !user.Enabled {
|
||||
return nil, "", authError{reason: "account disabled", clientReason: "account disabled"}
|
||||
}
|
||||
if err := user.ValidatePassword(password); err != nil {
|
||||
if err = user.ValidatePassword(password); err != nil {
|
||||
return nil, "", authError{reason: "bad password"}
|
||||
}
|
||||
token, err := svc.makeSession(user.ID)
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/kolide/kolide-ose/server/datastore"
|
||||
"github.com/kolide/kolide-ose/server/datastore/inmem"
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
|
@ -14,7 +14,7 @@ import (
|
|||
const bcryptCost = 6
|
||||
|
||||
func TestAuthenticate(t *testing.T) {
|
||||
ds, err := datastore.New("inmem", "")
|
||||
ds, err := inmem.New()
|
||||
require.Nil(t, err)
|
||||
svc, err := newTestService(ds, nil)
|
||||
require.Nil(t, err)
|
||||
|
|
|
|||
|
|
@ -8,13 +8,13 @@ import (
|
|||
func (svc service) SearchTargets(ctx context.Context, query string, selectedHostIDs []uint, selectedLabelIDs []uint) (*kolide.TargetSearchResults, error) {
|
||||
results := &kolide.TargetSearchResults{}
|
||||
|
||||
hosts, err := svc.ds.SearchHosts(query, selectedHostIDs)
|
||||
hosts, err := svc.ds.SearchHosts(query, selectedHostIDs...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
results.Hosts = hosts
|
||||
|
||||
labels, err := svc.ds.SearchLabels(query, selectedLabelIDs)
|
||||
labels, err := svc.ds.SearchLabels(query, selectedLabelIDs...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/kolide/kolide-ose/server/datastore"
|
||||
"github.com/kolide/kolide-ose/server/datastore/inmem"
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
|
@ -13,7 +13,7 @@ import (
|
|||
)
|
||||
|
||||
func TestSearchTargets(t *testing.T) {
|
||||
ds, err := datastore.New("inmem", "")
|
||||
ds, err := inmem.New()
|
||||
require.Nil(t, err)
|
||||
|
||||
svc, err := newTestService(ds, nil)
|
||||
|
|
@ -44,7 +44,7 @@ func TestSearchTargets(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestCountHostsInTargets(t *testing.T) {
|
||||
ds, err := datastore.New("inmem", "")
|
||||
ds, err := inmem.New()
|
||||
require.Nil(t, err)
|
||||
|
||||
svc, err := newTestService(ds, nil)
|
||||
|
|
@ -140,7 +140,7 @@ func TestCountHostsInTargets(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestSearchWithOmit(t *testing.T) {
|
||||
ds, err := datastore.New("inmem", "")
|
||||
ds, err := inmem.New()
|
||||
require.Nil(t, err)
|
||||
|
||||
svc, err := newTestService(ds, nil)
|
||||
|
|
@ -192,7 +192,7 @@ func TestSearchWithOmit(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestSearchHostsInLabels(t *testing.T) {
|
||||
ds, err := datastore.New("inmem", "")
|
||||
ds, err := inmem.New()
|
||||
require.Nil(t, err)
|
||||
|
||||
svc, err := newTestService(ds, nil)
|
||||
|
|
@ -245,7 +245,7 @@ func TestSearchHostsInLabels(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestSearchResultsLimit(t *testing.T) {
|
||||
ds, err := datastore.New("inmem", "")
|
||||
ds, err := inmem.New()
|
||||
require.Nil(t, err)
|
||||
|
||||
svc, err := newTestService(ds, nil)
|
||||
|
|
|
|||
|
|
@ -186,8 +186,14 @@ func (svc service) RequestPasswordReset(ctx context.Context, email string) error
|
|||
}
|
||||
|
||||
request := &kolide.PasswordResetRequest{
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
UpdateCreateTimestamps: kolide.UpdateCreateTimestamps{
|
||||
CreateTimestamp: kolide.CreateTimestamp{
|
||||
CreatedAt: time.Now(),
|
||||
},
|
||||
UpdateTimestamp: kolide.UpdateTimestamp{
|
||||
UpdatedAt: time.Now(),
|
||||
},
|
||||
},
|
||||
ExpiresAt: time.Now().Add(time.Hour * 24),
|
||||
UserID: user.ID,
|
||||
Token: token,
|
||||
|
|
|
|||
|
|
@ -8,15 +8,17 @@ import (
|
|||
"github.com/WatchBeam/clock"
|
||||
"github.com/kolide/kolide-ose/server/config"
|
||||
"github.com/kolide/kolide-ose/server/contexts/viewer"
|
||||
"github.com/kolide/kolide-ose/server/datastore"
|
||||
"github.com/kolide/kolide-ose/server/datastore/inmem"
|
||||
kolide_errors "github.com/kolide/kolide-ose/server/errors"
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
func TestAuthenticatedUser(t *testing.T) {
|
||||
ds, err := datastore.New("inmem", "")
|
||||
ds, err := inmem.New()
|
||||
assert.Nil(t, err)
|
||||
createTestUsers(t, ds)
|
||||
svc, err := newTestService(ds, nil)
|
||||
|
|
@ -32,7 +34,7 @@ func TestAuthenticatedUser(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestRequestPasswordReset(t *testing.T) {
|
||||
ds, err := datastore.New("inmem", "")
|
||||
ds, err := inmem.New()
|
||||
assert.Nil(t, err)
|
||||
createTestUsers(t, ds)
|
||||
admin1, err := ds.User("admin1")
|
||||
|
|
@ -112,7 +114,7 @@ func TestRequestPasswordReset(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestCreateUser(t *testing.T) {
|
||||
ds, _ := datastore.New("inmem", "")
|
||||
ds, _ := inmem.New()
|
||||
svc, _ := newTestService(ds, nil)
|
||||
invites := setupInvites(t, ds, []string{"admin2@example.com"})
|
||||
ctx := context.Background()
|
||||
|
|
@ -154,7 +156,7 @@ func TestCreateUser(t *testing.T) {
|
|||
NeedsPasswordReset: boolPtr(true),
|
||||
Admin: boolPtr(false),
|
||||
InviteToken: &invites["admin2@example.com"].Token,
|
||||
wantErr: datastore.ErrNotFound,
|
||||
wantErr: kolide_errors.ErrNotFound,
|
||||
},
|
||||
{
|
||||
Username: stringPtr("admin3"),
|
||||
|
|
@ -217,7 +219,11 @@ func setupInvites(t *testing.T, ds kolide.Datastore, emails []string) map[string
|
|||
InvitedBy: users["admin1"].ID,
|
||||
Token: e,
|
||||
Email: e,
|
||||
CreatedAt: mockClock.Now(),
|
||||
UpdateCreateTimestamps: kolide.UpdateCreateTimestamps{
|
||||
CreateTimestamp: kolide.CreateTimestamp{
|
||||
CreatedAt: mockClock.Now(),
|
||||
},
|
||||
},
|
||||
})
|
||||
require.Nil(t, err)
|
||||
invites[e] = invite
|
||||
|
|
@ -227,7 +233,11 @@ func setupInvites(t *testing.T, ds kolide.Datastore, emails []string) map[string
|
|||
InvitedBy: users["admin1"].ID,
|
||||
Token: "expired",
|
||||
Email: "expiredinvite@gmail.com",
|
||||
CreatedAt: mockClock.Now().AddDate(-1, 0, 0),
|
||||
UpdateCreateTimestamps: kolide.UpdateCreateTimestamps{
|
||||
CreateTimestamp: kolide.CreateTimestamp{
|
||||
CreatedAt: mockClock.Now().AddDate(-1, 0, 0),
|
||||
},
|
||||
},
|
||||
})
|
||||
require.Nil(t, err)
|
||||
invites["expired"] = invite
|
||||
|
|
@ -235,7 +245,7 @@ func setupInvites(t *testing.T, ds kolide.Datastore, emails []string) map[string
|
|||
}
|
||||
|
||||
func TestChangeUserPassword(t *testing.T) {
|
||||
ds, _ := datastore.New("inmem", "")
|
||||
ds, _ := inmem.New()
|
||||
svc, _ := newTestService(ds, nil)
|
||||
createTestUsers(t, ds)
|
||||
var passwordChangeTests = []struct {
|
||||
|
|
@ -250,7 +260,7 @@ func TestChangeUserPassword(t *testing.T) {
|
|||
{ // bad token
|
||||
token: "dcbaz",
|
||||
newPassword: "123cat!",
|
||||
wantErr: datastore.ErrNotFound,
|
||||
wantErr: kolide_errors.ErrNotFound,
|
||||
},
|
||||
{ // missing token
|
||||
newPassword: "123cat!",
|
||||
|
|
@ -266,8 +276,14 @@ func TestChangeUserPassword(t *testing.T) {
|
|||
t.Run("", func(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
request := &kolide.PasswordResetRequest{
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
UpdateCreateTimestamps: kolide.UpdateCreateTimestamps{
|
||||
CreateTimestamp: kolide.CreateTimestamp{
|
||||
CreatedAt: time.Now(),
|
||||
},
|
||||
UpdateTimestamp: kolide.UpdateTimestamp{
|
||||
UpdatedAt: time.Now(),
|
||||
},
|
||||
},
|
||||
ExpiresAt: time.Now().Add(time.Hour * 24),
|
||||
UserID: 1,
|
||||
Token: "abcd",
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import (
|
|||
"net/http"
|
||||
|
||||
kithttp "github.com/go-kit/kit/transport/http"
|
||||
"github.com/kolide/kolide-ose/server/datastore"
|
||||
"github.com/kolide/kolide-ose/server/errors"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
|
|
@ -112,9 +112,9 @@ func encodeError(ctx context.Context, err error, w http.ResponseWriter) {
|
|||
|
||||
func codeFromErr(err error) int {
|
||||
switch err {
|
||||
case datastore.ErrNotFound:
|
||||
case errors.ErrNotFound:
|
||||
return http.StatusNotFound
|
||||
case datastore.ErrExists:
|
||||
case errors.ErrExists:
|
||||
return http.StatusConflict
|
||||
default:
|
||||
return http.StatusInternalServerError
|
||||
|
|
|
|||
Loading…
Reference in a new issue