diff --git a/db/up.sql b/db/up.sql index 272f9fc986..12b4d311ef 100644 --- a/db/up.sql +++ b/db/up.sql @@ -36,7 +36,6 @@ CREATE TABLE `distributed_query_campaigns` ( `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`) diff --git a/server/datastore/mysql/queries.go b/server/datastore/mysql/queries.go index 7cd844419b..d7bd0d9a8f 100644 --- a/server/datastore/mysql/queries.go +++ b/server/datastore/mysql/queries.go @@ -90,18 +90,15 @@ func (d *Datastore) ListQueries(opt kolide.ListOptions) ([]*kolide.Query, error) } 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) + _, err := d.db.Exec(sqlStatement, camp.QueryID, camp.Status, camp.UserID, camp.ID) if err != nil { return errors.DatabaseError(err) } @@ -114,13 +111,12 @@ func (d *Datastore) NewDistributedQueryCampaign(camp *kolide.DistributedQueryCam sqlStatement := ` INSERT INTO distributed_query_campaigns ( query_id, - max_duration, status, user_id ) - VALUES(?,?,?,?) + VALUES(?,?,?) ` - result, err := d.db.Exec(sqlStatement, camp.QueryID, camp.MaxDuration, camp.Status, camp.UserID) + result, err := d.db.Exec(sqlStatement, camp.QueryID, camp.Status, camp.UserID) if err != nil { return nil, errors.DatabaseError(err) } diff --git a/server/kolide/queries.go b/server/kolide/queries.go index 3ed0b52e44..93878b3fcd 100644 --- a/server/kolide/queries.go +++ b/server/kolide/queries.go @@ -33,6 +33,7 @@ type QueryService interface { NewQuery(ctx context.Context, p QueryPayload) (*Query, error) ModifyQuery(ctx context.Context, id uint, p QueryPayload) (*Query, error) DeleteQuery(ctx context.Context, id uint) error + NewDistributedQueryCampaign(ctx context.Context, userID uint, queryString string, hosts []uint, labels []uint) (*DistributedQueryCampaign, error) } type QueryPayload struct { @@ -76,11 +77,10 @@ const ( type DistributedQueryCampaign struct { UpdateCreateTimestamps DeleteFields - ID uint - QueryID uint `db:"query_id"` - MaxDuration time.Duration `db:"max_duration"` - Status DistributedQueryStatus - UserID uint + ID uint `json:"id"` + QueryID uint `json:"query_id" db:"query_id"` + Status DistributedQueryStatus `json:"status"` + UserID uint `json:"user_id"` } type DistributedQueryCampaignTarget struct { diff --git a/server/service/endpoint_queries.go b/server/service/endpoint_queries.go index f92278e4b5..25e58310b9 100644 --- a/server/service/endpoint_queries.go +++ b/server/service/endpoint_queries.go @@ -2,6 +2,7 @@ package service import ( "github.com/go-kit/kit/endpoint" + "github.com/kolide/kolide-ose/server/contexts/viewer" "github.com/kolide/kolide-ose/server/kolide" "golang.org/x/net/context" ) @@ -139,3 +140,39 @@ func makeDeleteQueryEndpoint(svc kolide.Service) endpoint.Endpoint { return deleteQueryResponse{}, nil } } + +//////////////////////////////////////////////////////////////////////////////// +// Create Distributed Query Campaign +//////////////////////////////////////////////////////////////////////////////// + +type createDistributedQueryCampaignRequest struct { + UserID uint + Query string `json:"query"` + Selected struct { + Labels []uint `json:"labels"` + Hosts []uint `json:"hosts"` + } `json:"selected"` +} + +type createDistributedQueryCampaignResponse struct { + Campaign *kolide.DistributedQueryCampaign `json:"campaign,omitempty"` + Err error `json:"error,omitempty"` +} + +func (r createDistributedQueryCampaignResponse) error() error { return r.Err } + +func makeCreateDistributedQueryCampaignEndpoint(svc kolide.Service) endpoint.Endpoint { + return func(ctx context.Context, request interface{}) (interface{}, error) { + vc, ok := viewer.FromContext(ctx) + if !ok { + return nil, errNoContext + } + + req := request.(createDistributedQueryCampaignRequest) + campaign, err := svc.NewDistributedQueryCampaign(ctx, vc.UserID(), req.Query, req.Selected.Hosts, req.Selected.Labels) + if err != nil { + return createQueryResponse{Err: err}, nil + } + return createDistributedQueryCampaignResponse{campaign, nil}, nil + } +} diff --git a/server/service/endpoint_targets.go b/server/service/endpoint_targets.go index 3628e7a28b..bdc84a79db 100644 --- a/server/service/endpoint_targets.go +++ b/server/service/endpoint_targets.go @@ -7,7 +7,7 @@ import ( ) //////////////////////////////////////////////////////////////////////////////// -// Search Targrets +// Search Targets //////////////////////////////////////////////////////////////////////////////// type searchTargetsRequest struct { diff --git a/server/service/handler.go b/server/service/handler.go index 3e431f1c21..8f041db997 100644 --- a/server/service/handler.go +++ b/server/service/handler.go @@ -14,53 +14,54 @@ import ( // KolideEndpoints is a collection of RPC endpoints implemented by the Kolide API. type KolideEndpoints struct { - Login endpoint.Endpoint - Logout endpoint.Endpoint - ForgotPassword endpoint.Endpoint - ResetPassword endpoint.Endpoint - Me endpoint.Endpoint - CreateUser endpoint.Endpoint - GetUser endpoint.Endpoint - ListUsers endpoint.Endpoint - ModifyUser endpoint.Endpoint - GetSessionsForUserInfo endpoint.Endpoint - DeleteSessionsForUser endpoint.Endpoint - GetSessionInfo endpoint.Endpoint - DeleteSession endpoint.Endpoint - GetAppConfig endpoint.Endpoint - ModifyAppConfig endpoint.Endpoint - CreateInvite endpoint.Endpoint - ListInvites endpoint.Endpoint - DeleteInvite endpoint.Endpoint - GetQuery endpoint.Endpoint - ListQueries endpoint.Endpoint - CreateQuery endpoint.Endpoint - ModifyQuery endpoint.Endpoint - DeleteQuery endpoint.Endpoint - GetPack endpoint.Endpoint - ListPacks endpoint.Endpoint - CreatePack endpoint.Endpoint - ModifyPack endpoint.Endpoint - DeletePack endpoint.Endpoint - AddQueryToPack endpoint.Endpoint - GetQueriesInPack endpoint.Endpoint - DeleteQueryFromPack endpoint.Endpoint - EnrollAgent endpoint.Endpoint - GetClientConfig endpoint.Endpoint - GetDistributedQueries endpoint.Endpoint - SubmitDistributedQueryResults endpoint.Endpoint - SubmitLogs endpoint.Endpoint - GetLabel endpoint.Endpoint - ListLabels endpoint.Endpoint - CreateLabel endpoint.Endpoint - DeleteLabel endpoint.Endpoint - AddLabelToPack endpoint.Endpoint - GetLabelsForPack endpoint.Endpoint - DeleteLabelFromPack endpoint.Endpoint - GetHost endpoint.Endpoint - DeleteHost endpoint.Endpoint - ListHosts endpoint.Endpoint - SearchTargets endpoint.Endpoint + Login endpoint.Endpoint + Logout endpoint.Endpoint + ForgotPassword endpoint.Endpoint + ResetPassword endpoint.Endpoint + Me endpoint.Endpoint + CreateUser endpoint.Endpoint + GetUser endpoint.Endpoint + ListUsers endpoint.Endpoint + ModifyUser endpoint.Endpoint + GetSessionsForUserInfo endpoint.Endpoint + DeleteSessionsForUser endpoint.Endpoint + GetSessionInfo endpoint.Endpoint + DeleteSession endpoint.Endpoint + GetAppConfig endpoint.Endpoint + ModifyAppConfig endpoint.Endpoint + CreateInvite endpoint.Endpoint + ListInvites endpoint.Endpoint + DeleteInvite endpoint.Endpoint + GetQuery endpoint.Endpoint + ListQueries endpoint.Endpoint + CreateQuery endpoint.Endpoint + ModifyQuery endpoint.Endpoint + DeleteQuery endpoint.Endpoint + CreateDistributedQueryCampaign endpoint.Endpoint + GetPack endpoint.Endpoint + ListPacks endpoint.Endpoint + CreatePack endpoint.Endpoint + ModifyPack endpoint.Endpoint + DeletePack endpoint.Endpoint + AddQueryToPack endpoint.Endpoint + GetQueriesInPack endpoint.Endpoint + DeleteQueryFromPack endpoint.Endpoint + EnrollAgent endpoint.Endpoint + GetClientConfig endpoint.Endpoint + GetDistributedQueries endpoint.Endpoint + SubmitDistributedQueryResults endpoint.Endpoint + SubmitLogs endpoint.Endpoint + GetLabel endpoint.Endpoint + ListLabels endpoint.Endpoint + CreateLabel endpoint.Endpoint + DeleteLabel endpoint.Endpoint + AddLabelToPack endpoint.Endpoint + GetLabelsForPack endpoint.Endpoint + DeleteLabelFromPack endpoint.Endpoint + GetHost endpoint.Endpoint + DeleteHost endpoint.Endpoint + ListHosts endpoint.Endpoint + SearchTargets endpoint.Endpoint } // MakeKolideServerEndpoints creates the Kolide API endpoints. @@ -73,43 +74,44 @@ func MakeKolideServerEndpoints(svc kolide.Service, jwtKey string) KolideEndpoint CreateUser: makeCreateUserEndpoint(svc), // Authenticated user endpoints - Me: authenticatedUser(jwtKey, svc, makeGetSessionUserEndpoint(svc)), - GetUser: authenticatedUser(jwtKey, svc, canReadUser(makeGetUserEndpoint(svc))), - ListUsers: authenticatedUser(jwtKey, svc, canPerformActions(makeListUsersEndpoint(svc))), - ModifyUser: authenticatedUser(jwtKey, svc, validateModifyUserRequest(makeModifyUserEndpoint(svc))), - GetSessionsForUserInfo: authenticatedUser(jwtKey, svc, canReadUser(makeGetInfoAboutSessionsForUserEndpoint(svc))), - DeleteSessionsForUser: authenticatedUser(jwtKey, svc, canModifyUser(makeDeleteSessionsForUserEndpoint(svc))), - GetSessionInfo: authenticatedUser(jwtKey, svc, mustBeAdmin(makeGetInfoAboutSessionEndpoint(svc))), - DeleteSession: authenticatedUser(jwtKey, svc, mustBeAdmin(makeDeleteSessionEndpoint(svc))), - GetAppConfig: authenticatedUser(jwtKey, svc, makeGetAppConfigEndpoint(svc)), - ModifyAppConfig: authenticatedUser(jwtKey, svc, mustBeAdmin(makeModifyAppConfigRequest(svc))), - CreateInvite: authenticatedUser(jwtKey, svc, mustBeAdmin(makeCreateInviteEndpoint(svc))), - ListInvites: authenticatedUser(jwtKey, svc, mustBeAdmin(makeListInvitesEndpoint(svc))), - DeleteInvite: authenticatedUser(jwtKey, svc, mustBeAdmin(makeDeleteInviteEndpoint(svc))), - GetQuery: authenticatedUser(jwtKey, svc, makeGetQueryEndpoint(svc)), - ListQueries: authenticatedUser(jwtKey, svc, makeListQueriesEndpoint(svc)), - CreateQuery: authenticatedUser(jwtKey, svc, makeCreateQueryEndpoint(svc)), - ModifyQuery: authenticatedUser(jwtKey, svc, makeModifyQueryEndpoint(svc)), - DeleteQuery: authenticatedUser(jwtKey, svc, makeDeleteQueryEndpoint(svc)), - GetPack: authenticatedUser(jwtKey, svc, makeGetPackEndpoint(svc)), - ListPacks: authenticatedUser(jwtKey, svc, makeListPacksEndpoint(svc)), - CreatePack: authenticatedUser(jwtKey, svc, makeCreatePackEndpoint(svc)), - ModifyPack: authenticatedUser(jwtKey, svc, makeModifyPackEndpoint(svc)), - DeletePack: authenticatedUser(jwtKey, svc, makeDeletePackEndpoint(svc)), - AddQueryToPack: authenticatedUser(jwtKey, svc, makeAddQueryToPackEndpoint(svc)), - GetQueriesInPack: authenticatedUser(jwtKey, svc, makeGetQueriesInPackEndpoint(svc)), - DeleteQueryFromPack: authenticatedUser(jwtKey, svc, makeDeleteQueryFromPackEndpoint(svc)), - GetHost: authenticatedUser(jwtKey, svc, makeGetHostEndpoint(svc)), - ListHosts: authenticatedUser(jwtKey, svc, makeListHostsEndpoint(svc)), - DeleteHost: authenticatedUser(jwtKey, svc, makeDeleteHostEndpoint(svc)), - GetLabel: authenticatedUser(jwtKey, svc, makeGetLabelEndpoint(svc)), - ListLabels: authenticatedUser(jwtKey, svc, makeListLabelsEndpoint(svc)), - CreateLabel: authenticatedUser(jwtKey, svc, makeCreateLabelEndpoint(svc)), - DeleteLabel: authenticatedUser(jwtKey, svc, makeDeleteLabelEndpoint(svc)), - AddLabelToPack: authenticatedUser(jwtKey, svc, makeAddLabelToPackEndpoint(svc)), - GetLabelsForPack: authenticatedUser(jwtKey, svc, makeGetLabelsForPackEndpoint(svc)), - DeleteLabelFromPack: authenticatedUser(jwtKey, svc, makeDeleteLabelFromPackEndpoint(svc)), - SearchTargets: authenticatedUser(jwtKey, svc, makeSearchTargetsEndpoint(svc)), + Me: authenticatedUser(jwtKey, svc, makeGetSessionUserEndpoint(svc)), + GetUser: authenticatedUser(jwtKey, svc, canReadUser(makeGetUserEndpoint(svc))), + ListUsers: authenticatedUser(jwtKey, svc, canPerformActions(makeListUsersEndpoint(svc))), + ModifyUser: authenticatedUser(jwtKey, svc, validateModifyUserRequest(makeModifyUserEndpoint(svc))), + GetSessionsForUserInfo: authenticatedUser(jwtKey, svc, canReadUser(makeGetInfoAboutSessionsForUserEndpoint(svc))), + DeleteSessionsForUser: authenticatedUser(jwtKey, svc, canModifyUser(makeDeleteSessionsForUserEndpoint(svc))), + GetSessionInfo: authenticatedUser(jwtKey, svc, mustBeAdmin(makeGetInfoAboutSessionEndpoint(svc))), + DeleteSession: authenticatedUser(jwtKey, svc, mustBeAdmin(makeDeleteSessionEndpoint(svc))), + GetAppConfig: authenticatedUser(jwtKey, svc, makeGetAppConfigEndpoint(svc)), + ModifyAppConfig: authenticatedUser(jwtKey, svc, mustBeAdmin(makeModifyAppConfigRequest(svc))), + CreateInvite: authenticatedUser(jwtKey, svc, mustBeAdmin(makeCreateInviteEndpoint(svc))), + ListInvites: authenticatedUser(jwtKey, svc, mustBeAdmin(makeListInvitesEndpoint(svc))), + DeleteInvite: authenticatedUser(jwtKey, svc, mustBeAdmin(makeDeleteInviteEndpoint(svc))), + GetQuery: authenticatedUser(jwtKey, svc, makeGetQueryEndpoint(svc)), + ListQueries: authenticatedUser(jwtKey, svc, makeListQueriesEndpoint(svc)), + CreateQuery: authenticatedUser(jwtKey, svc, makeCreateQueryEndpoint(svc)), + ModifyQuery: authenticatedUser(jwtKey, svc, makeModifyQueryEndpoint(svc)), + DeleteQuery: authenticatedUser(jwtKey, svc, makeDeleteQueryEndpoint(svc)), + CreateDistributedQueryCampaign: authenticatedUser(jwtKey, svc, makeCreateDistributedQueryCampaignEndpoint(svc)), + GetPack: authenticatedUser(jwtKey, svc, makeGetPackEndpoint(svc)), + ListPacks: authenticatedUser(jwtKey, svc, makeListPacksEndpoint(svc)), + CreatePack: authenticatedUser(jwtKey, svc, makeCreatePackEndpoint(svc)), + ModifyPack: authenticatedUser(jwtKey, svc, makeModifyPackEndpoint(svc)), + DeletePack: authenticatedUser(jwtKey, svc, makeDeletePackEndpoint(svc)), + AddQueryToPack: authenticatedUser(jwtKey, svc, makeAddQueryToPackEndpoint(svc)), + GetQueriesInPack: authenticatedUser(jwtKey, svc, makeGetQueriesInPackEndpoint(svc)), + DeleteQueryFromPack: authenticatedUser(jwtKey, svc, makeDeleteQueryFromPackEndpoint(svc)), + GetHost: authenticatedUser(jwtKey, svc, makeGetHostEndpoint(svc)), + ListHosts: authenticatedUser(jwtKey, svc, makeListHostsEndpoint(svc)), + DeleteHost: authenticatedUser(jwtKey, svc, makeDeleteHostEndpoint(svc)), + GetLabel: authenticatedUser(jwtKey, svc, makeGetLabelEndpoint(svc)), + ListLabels: authenticatedUser(jwtKey, svc, makeListLabelsEndpoint(svc)), + CreateLabel: authenticatedUser(jwtKey, svc, makeCreateLabelEndpoint(svc)), + DeleteLabel: authenticatedUser(jwtKey, svc, makeDeleteLabelEndpoint(svc)), + AddLabelToPack: authenticatedUser(jwtKey, svc, makeAddLabelToPackEndpoint(svc)), + GetLabelsForPack: authenticatedUser(jwtKey, svc, makeGetLabelsForPackEndpoint(svc)), + DeleteLabelFromPack: authenticatedUser(jwtKey, svc, makeDeleteLabelFromPackEndpoint(svc)), + SearchTargets: authenticatedUser(jwtKey, svc, makeSearchTargetsEndpoint(svc)), // Osquery endpoints EnrollAgent: makeEnrollAgentEndpoint(svc), @@ -121,53 +123,54 @@ func MakeKolideServerEndpoints(svc kolide.Service, jwtKey string) KolideEndpoint } type kolideHandlers struct { - Login *kithttp.Server - Logout *kithttp.Server - ForgotPassword *kithttp.Server - ResetPassword *kithttp.Server - Me *kithttp.Server - CreateUser *kithttp.Server - GetUser *kithttp.Server - ListUsers *kithttp.Server - ModifyUser *kithttp.Server - GetSessionsForUserInfo *kithttp.Server - DeleteSessionsForUser *kithttp.Server - GetSessionInfo *kithttp.Server - DeleteSession *kithttp.Server - GetAppConfig *kithttp.Server - ModifyAppConfig *kithttp.Server - CreateInvite *kithttp.Server - ListInvites *kithttp.Server - DeleteInvite *kithttp.Server - GetQuery *kithttp.Server - ListQueries *kithttp.Server - CreateQuery *kithttp.Server - ModifyQuery *kithttp.Server - DeleteQuery *kithttp.Server - GetPack *kithttp.Server - ListPacks *kithttp.Server - CreatePack *kithttp.Server - ModifyPack *kithttp.Server - DeletePack *kithttp.Server - AddQueryToPack *kithttp.Server - GetQueriesInPack *kithttp.Server - DeleteQueryFromPack *kithttp.Server - EnrollAgent *kithttp.Server - GetClientConfig *kithttp.Server - GetDistributedQueries *kithttp.Server - SubmitDistributedQueryResults *kithttp.Server - SubmitLogs *kithttp.Server - GetLabel *kithttp.Server - ListLabels *kithttp.Server - CreateLabel *kithttp.Server - DeleteLabel *kithttp.Server - AddLabelToPack *kithttp.Server - GetLabelsForPack *kithttp.Server - DeleteLabelFromPack *kithttp.Server - GetHost *kithttp.Server - DeleteHost *kithttp.Server - ListHosts *kithttp.Server - SearchTargets *kithttp.Server + Login *kithttp.Server + Logout *kithttp.Server + ForgotPassword *kithttp.Server + ResetPassword *kithttp.Server + Me *kithttp.Server + CreateUser *kithttp.Server + GetUser *kithttp.Server + ListUsers *kithttp.Server + ModifyUser *kithttp.Server + GetSessionsForUserInfo *kithttp.Server + DeleteSessionsForUser *kithttp.Server + GetSessionInfo *kithttp.Server + DeleteSession *kithttp.Server + GetAppConfig *kithttp.Server + ModifyAppConfig *kithttp.Server + CreateInvite *kithttp.Server + ListInvites *kithttp.Server + DeleteInvite *kithttp.Server + GetQuery *kithttp.Server + ListQueries *kithttp.Server + CreateQuery *kithttp.Server + ModifyQuery *kithttp.Server + DeleteQuery *kithttp.Server + CreateDistributedQueryCampaign *kithttp.Server + GetPack *kithttp.Server + ListPacks *kithttp.Server + CreatePack *kithttp.Server + ModifyPack *kithttp.Server + DeletePack *kithttp.Server + AddQueryToPack *kithttp.Server + GetQueriesInPack *kithttp.Server + DeleteQueryFromPack *kithttp.Server + EnrollAgent *kithttp.Server + GetClientConfig *kithttp.Server + GetDistributedQueries *kithttp.Server + SubmitDistributedQueryResults *kithttp.Server + SubmitLogs *kithttp.Server + GetLabel *kithttp.Server + ListLabels *kithttp.Server + CreateLabel *kithttp.Server + DeleteLabel *kithttp.Server + AddLabelToPack *kithttp.Server + GetLabelsForPack *kithttp.Server + DeleteLabelFromPack *kithttp.Server + GetHost *kithttp.Server + DeleteHost *kithttp.Server + ListHosts *kithttp.Server + SearchTargets *kithttp.Server } func makeKolideKitHandlers(ctx context.Context, e KolideEndpoints, opts []kithttp.ServerOption) kolideHandlers { @@ -175,29 +178,30 @@ func makeKolideKitHandlers(ctx context.Context, e KolideEndpoints, opts []kithtt return kithttp.NewServer(ctx, e, decodeFn, encodeResponse, opts...) } return kolideHandlers{ - Login: newServer(e.Login, decodeLoginRequest), - Logout: newServer(e.Logout, decodeNoParamsRequest), - ForgotPassword: newServer(e.ForgotPassword, decodeForgotPasswordRequest), - ResetPassword: newServer(e.ResetPassword, decodeResetPasswordRequest), - Me: newServer(e.Me, decodeNoParamsRequest), - CreateUser: newServer(e.CreateUser, decodeCreateUserRequest), - GetUser: newServer(e.GetUser, decodeGetUserRequest), - ListUsers: newServer(e.ListUsers, decodeListUsersRequest), - ModifyUser: newServer(e.ModifyUser, decodeModifyUserRequest), - GetSessionsForUserInfo: newServer(e.GetSessionsForUserInfo, decodeGetInfoAboutSessionsForUserRequest), - DeleteSessionsForUser: newServer(e.DeleteSessionsForUser, decodeDeleteSessionsForUserRequest), - GetSessionInfo: newServer(e.GetSessionInfo, decodeGetInfoAboutSessionRequest), - DeleteSession: newServer(e.DeleteSession, decodeDeleteSessionRequest), - GetAppConfig: newServer(e.GetAppConfig, decodeNoParamsRequest), - ModifyAppConfig: newServer(e.ModifyAppConfig, decodeModifyAppConfigRequest), - CreateInvite: newServer(e.CreateInvite, decodeCreateInviteRequest), - ListInvites: newServer(e.ListInvites, decodeListInvitesRequest), - DeleteInvite: newServer(e.DeleteInvite, decodeDeleteInviteRequest), - GetQuery: newServer(e.GetQuery, decodeGetQueryRequest), - ListQueries: newServer(e.ListQueries, decodeListQueriesRequest), - CreateQuery: newServer(e.CreateQuery, decodeCreateQueryRequest), - ModifyQuery: newServer(e.ModifyQuery, decodeModifyQueryRequest), - DeleteQuery: newServer(e.DeleteQuery, decodeDeleteQueryRequest), + Login: newServer(e.Login, decodeLoginRequest), + Logout: newServer(e.Logout, decodeNoParamsRequest), + ForgotPassword: newServer(e.ForgotPassword, decodeForgotPasswordRequest), + ResetPassword: newServer(e.ResetPassword, decodeResetPasswordRequest), + Me: newServer(e.Me, decodeNoParamsRequest), + CreateUser: newServer(e.CreateUser, decodeCreateUserRequest), + GetUser: newServer(e.GetUser, decodeGetUserRequest), + ListUsers: newServer(e.ListUsers, decodeListUsersRequest), + ModifyUser: newServer(e.ModifyUser, decodeModifyUserRequest), + GetSessionsForUserInfo: newServer(e.GetSessionsForUserInfo, decodeGetInfoAboutSessionsForUserRequest), + DeleteSessionsForUser: newServer(e.DeleteSessionsForUser, decodeDeleteSessionsForUserRequest), + GetSessionInfo: newServer(e.GetSessionInfo, decodeGetInfoAboutSessionRequest), + DeleteSession: newServer(e.DeleteSession, decodeDeleteSessionRequest), + GetAppConfig: newServer(e.GetAppConfig, decodeNoParamsRequest), + ModifyAppConfig: newServer(e.ModifyAppConfig, decodeModifyAppConfigRequest), + CreateInvite: newServer(e.CreateInvite, decodeCreateInviteRequest), + ListInvites: newServer(e.ListInvites, decodeListInvitesRequest), + DeleteInvite: newServer(e.DeleteInvite, decodeDeleteInviteRequest), + GetQuery: newServer(e.GetQuery, decodeGetQueryRequest), + ListQueries: newServer(e.ListQueries, decodeListQueriesRequest), + CreateQuery: newServer(e.CreateQuery, decodeCreateQueryRequest), + ModifyQuery: newServer(e.ModifyQuery, decodeModifyQueryRequest), + DeleteQuery: newServer(e.DeleteQuery, decodeDeleteQueryRequest), + CreateDistributedQueryCampaign: newServer(e.CreateDistributedQueryCampaign, decodeCreateDistributedQueryCampaignRequest), GetPack: newServer(e.GetPack, decodeGetPackRequest), ListPacks: newServer(e.ListPacks, decodeListPacksRequest), CreatePack: newServer(e.CreatePack, decodeCreatePackRequest), @@ -275,6 +279,7 @@ func attachKolideAPIRoutes(r *mux.Router, h kolideHandlers) { r.Handle("/api/v1/kolide/queries", h.CreateQuery).Methods("POST") r.Handle("/api/v1/kolide/queries/{id}", h.ModifyQuery).Methods("PATCH") r.Handle("/api/v1/kolide/queries/{id}", h.DeleteQuery).Methods("DELETE") + r.Handle("/api/v1/kolide/queries/run", h.CreateDistributedQueryCampaign).Methods("POST") r.Handle("/api/v1/kolide/packs/{id}", h.GetPack).Methods("GET") r.Handle("/api/v1/kolide/packs", h.ListPacks).Methods("GET") diff --git a/server/service/handler_test.go b/server/service/handler_test.go index b343b70cdb..c6d21365e6 100644 --- a/server/service/handler_test.go +++ b/server/service/handler_test.go @@ -103,6 +103,10 @@ func TestAPIRoutes(t *testing.T) { verb: "DELETE", uri: "/api/v1/kolide/queries/1", }, + { + verb: "POST", + uri: "/api/v1/kolide/queries/run", + }, { verb: "GET", uri: "/api/v1/kolide/packs/1", diff --git a/server/service/service_osquery_test.go b/server/service/service_osquery_test.go index 54eb4ecb3b..f5c0ac8909 100644 --- a/server/service/service_osquery_test.go +++ b/server/service/service_osquery_test.go @@ -630,35 +630,11 @@ func TestDistributedQueries(t *testing.T) { err = ds.RecordLabelQueryExecutions(host, map[string]bool{labelId: true}, mockClock.Now()) require.Nil(t, err) - // Create query - n = "time" q = "select year, month, day, hour, minutes, seconds from time" - query, err := svc.NewQuery(ctx, kolide.QueryPayload{ - Name: &n, - Query: &q, - }) + campaign, err := svc.NewDistributedQueryCampaign(ctx, 0, q, []uint{}, []uint{label.ID}) require.Nil(t, err) - // Create query campaign - c1 := &kolide.DistributedQueryCampaign{ - QueryID: query.ID, - Status: kolide.QueryRunning, - } - // TODO use service method - c1, err = ds.NewDistributedQueryCampaign(c1) - require.Nil(t, err) - - // Add a target to the campaign (targeting the matching label) - target := &kolide.DistributedQueryCampaignTarget{ - Type: kolide.TargetLabel, - DistributedQueryCampaignID: c1.ID, - TargetID: label.ID, - } - // TODO use service method - target, err = ds.NewDistributedQueryCampaignTarget(target) - require.Nil(t, err) - - queryKey := fmt.Sprintf("%s%d", hostDistributedQueryPrefix, c1.ID) + queryKey := fmt.Sprintf("%s%d", hostDistributedQueryPrefix, campaign.ID) // Now we should get the active distributed query queries, err := svc.GetDistributedQueries(ctx) @@ -685,7 +661,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, *campaign) require.Nil(t, err) // We need to listen for the result in a separate thread to prevent the @@ -698,7 +674,7 @@ func TestDistributedQueries(t *testing.T) { select { case val := <-readChan: if res, ok := val.(kolide.DistributedQueryResult); ok { - assert.Equal(t, c1.ID, res.DistributedQueryCampaignID) + assert.Equal(t, campaign.ID, res.DistributedQueryCampaignID) assert.Equal(t, expectedRows, res.Rows) assert.Equal(t, *host, res.Host) } else { diff --git a/server/service/service_queries.go b/server/service/service_queries.go index 46be376078..4cc4bbf2a9 100644 --- a/server/service/service_queries.go +++ b/server/service/service_queries.go @@ -114,3 +114,48 @@ func (svc service) DeleteQuery(ctx context.Context, id uint) error { return nil } + +func (svc service) NewDistributedQueryCampaign(ctx context.Context, userID uint, queryString string, hosts []uint, labels []uint) (*kolide.DistributedQueryCampaign, error) { + query, err := svc.NewQuery(ctx, kolide.QueryPayload{ + Name: &queryString, + Query: &queryString, + }) + if err != nil { + return nil, err + } + + campaign, err := svc.ds.NewDistributedQueryCampaign(&kolide.DistributedQueryCampaign{ + QueryID: query.ID, + Status: kolide.QueryRunning, + UserID: userID, + }) + if err != nil { + return nil, err + } + + // Add host targets + for _, hid := range hosts { + _, err = svc.ds.NewDistributedQueryCampaignTarget(&kolide.DistributedQueryCampaignTarget{ + Type: kolide.TargetHost, + DistributedQueryCampaignID: campaign.ID, + TargetID: hid, + }) + if err != nil { + return nil, err + } + } + + // Add label targets + for _, lid := range labels { + _, err = svc.ds.NewDistributedQueryCampaignTarget(&kolide.DistributedQueryCampaignTarget{ + Type: kolide.TargetLabel, + DistributedQueryCampaignID: campaign.ID, + TargetID: lid, + }) + if err != nil { + return nil, err + } + } + + return campaign, nil +} diff --git a/server/service/transport_queries.go b/server/service/transport_queries.go index f5c1c3ef38..7cc436f848 100644 --- a/server/service/transport_queries.go +++ b/server/service/transport_queries.go @@ -55,3 +55,11 @@ func decodeListQueriesRequest(ctx context.Context, r *http.Request) (interface{} } return listQueriesRequest{ListOptions: opt}, nil } + +func decodeCreateDistributedQueryCampaignRequest(ctx context.Context, r *http.Request) (interface{}, error) { + var req createDistributedQueryCampaignRequest + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + return nil, err + } + return req, nil +}