mirror of
https://github.com/fleetdm/fleet
synced 2026-05-24 01:18:42 +00:00
Migrate global scheduled queries endpoints to new pattern (#3235)
This commit is contained in:
parent
aabb962e21
commit
af42a0850e
9 changed files with 239 additions and 277 deletions
|
|
@ -157,6 +157,9 @@ func (d *Datastore) ScheduledQuery(ctx context.Context, id uint) (*fleet.Schedul
|
|||
`
|
||||
sq := &fleet.ScheduledQuery{}
|
||||
if err := sqlx.GetContext(ctx, d.reader, sq, query, id); err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, ctxerr.Wrap(ctx, notFound("ScheduledQuery").WithID(id))
|
||||
}
|
||||
return nil, ctxerr.Wrap(ctx, err, "select scheduled query")
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,136 +0,0 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/fleetdm/fleet/v4/server/fleet"
|
||||
"github.com/go-kit/kit/endpoint"
|
||||
)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Get Global Schedule
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
type getGlobalScheduleRequest struct {
|
||||
ListOptions fleet.ListOptions
|
||||
}
|
||||
|
||||
type getGlobalScheduleResponse struct {
|
||||
GlobalSchedule []*fleet.ScheduledQuery `json:"global_schedule"`
|
||||
Err error `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (r getGlobalScheduleResponse) error() error { return r.Err }
|
||||
|
||||
func makeGetGlobalScheduleEndpoint(svc fleet.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(getGlobalScheduleRequest)
|
||||
|
||||
gp, err := svc.GetGlobalScheduledQueries(ctx, req.ListOptions)
|
||||
if err != nil {
|
||||
return getGlobalScheduleResponse{Err: err}, nil
|
||||
}
|
||||
|
||||
return getGlobalScheduleResponse{
|
||||
GlobalSchedule: gp,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Modify Global Schedule
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
type modifyGlobalScheduleRequest struct {
|
||||
ID uint
|
||||
payload fleet.ScheduledQueryPayload
|
||||
}
|
||||
|
||||
type modifyGlobalScheduleResponse struct {
|
||||
Scheduled *fleet.ScheduledQuery `json:"scheduled,omitempty"`
|
||||
Err error `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (r modifyGlobalScheduleResponse) error() error { return r.Err }
|
||||
|
||||
func makeModifyGlobalScheduleEndpoint(svc fleet.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(modifyGlobalScheduleRequest)
|
||||
|
||||
sq, err := svc.ModifyGlobalScheduledQueries(ctx, req.ID, req.payload)
|
||||
if err != nil {
|
||||
return modifyGlobalScheduleResponse{Err: err}, nil
|
||||
}
|
||||
|
||||
return modifyGlobalScheduleResponse{
|
||||
Scheduled: sq,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Delete Global Schedule
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
type deleteGlobalScheduleRequest struct {
|
||||
ID uint
|
||||
}
|
||||
|
||||
type deleteGlobalScheduleResponse struct {
|
||||
Err error `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (r deleteGlobalScheduleResponse) error() error { return r.Err }
|
||||
|
||||
func makeDeleteGlobalScheduleEndpoint(svc fleet.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(deleteGlobalScheduleRequest)
|
||||
err := svc.DeleteGlobalScheduledQueries(ctx, req.ID)
|
||||
if err != nil {
|
||||
return deleteGlobalScheduleResponse{Err: err}, nil
|
||||
}
|
||||
|
||||
return deleteGlobalScheduleResponse{}, nil
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Global Schedule Query
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
type globalScheduleQueryRequest struct {
|
||||
QueryID uint `json:"query_id"`
|
||||
Interval uint `json:"interval"`
|
||||
Snapshot *bool `json:"snapshot"`
|
||||
Removed *bool `json:"removed"`
|
||||
Platform *string `json:"platform"`
|
||||
Version *string `json:"version"`
|
||||
Shard *uint `json:"shard"`
|
||||
}
|
||||
|
||||
type globalScheduleQueryResponse struct {
|
||||
Scheduled *fleet.ScheduledQuery `json:"scheduled,omitempty"`
|
||||
Err error `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (r globalScheduleQueryResponse) error() error { return r.Err }
|
||||
|
||||
func makeGlobalScheduleQueryEndpoint(svc fleet.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(globalScheduleQueryRequest)
|
||||
|
||||
scheduled, err := svc.GlobalScheduleQuery(ctx, &fleet.ScheduledQuery{
|
||||
QueryID: req.QueryID,
|
||||
Interval: req.Interval,
|
||||
Snapshot: req.Snapshot,
|
||||
Removed: req.Removed,
|
||||
Platform: req.Platform,
|
||||
Version: req.Version,
|
||||
Shard: req.Shard,
|
||||
})
|
||||
if err != nil {
|
||||
return globalScheduleQueryResponse{Err: err}, nil
|
||||
}
|
||||
return globalScheduleQueryResponse{Scheduled: scheduled}, nil
|
||||
}
|
||||
}
|
||||
|
|
@ -64,12 +64,18 @@ func allFields(ifv reflect.Value) []reflect.StructField {
|
|||
return fields
|
||||
}
|
||||
|
||||
// makeDecoder creates a decoder for the type for the struct passed on. If the struct has at least 1 json tag
|
||||
// it'll unmarshall the body. If the struct has a `url` tag with value list-options it'll gather fleet.ListOptions
|
||||
// from the URL. And finally, any other `url` tag will be treated as an ID from the URL path pattern, and it'll
|
||||
// be decoded and set accordingly.
|
||||
// IDs are expected to be uint, and can be optional by setting the tag as follows: `url:"some-id,optional"`
|
||||
// list-options are optional by default and it'll ignore the optional portion of the tag.
|
||||
// makeDecoder creates a decoder for the type for the struct passed on. If the
|
||||
// struct has at least 1 json tag it'll unmarshall the body. If the struct has
|
||||
// a `url` tag with value list_options it'll gather fleet.ListOptions from the
|
||||
// URL (similarly for host_options, carve_options that derive from the common
|
||||
// list_options).
|
||||
//
|
||||
// Finally, any other `url` tag will be treated as a path variable (of the form
|
||||
// /path/{name} in the route's path) from the URL path pattern, and it'll be
|
||||
// decoded and set accordingly. Variables can be optional by setting the tag as
|
||||
// follows: `url:"some-id,optional"`.
|
||||
// The "list_options" are optional by default and it'll ignore the optional
|
||||
// portion of the tag.
|
||||
func makeDecoder(iface interface{}) kithttp.DecodeRequestFunc {
|
||||
if iface == nil {
|
||||
return func(ctx context.Context, r *http.Request) (interface{}, error) {
|
||||
|
|
|
|||
178
server/service/global_schedule.go
Normal file
178
server/service/global_schedule.go
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/fleetdm/fleet/v4/server/fleet"
|
||||
"github.com/fleetdm/fleet/v4/server/ptr"
|
||||
)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Get Global Schedule
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
type getGlobalScheduleRequest struct {
|
||||
ListOptions fleet.ListOptions `url:"list_options"`
|
||||
}
|
||||
|
||||
type getGlobalScheduleResponse struct {
|
||||
GlobalSchedule []*fleet.ScheduledQuery `json:"global_schedule"`
|
||||
Err error `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (r getGlobalScheduleResponse) error() error { return r.Err }
|
||||
|
||||
func getGlobalScheduleEndpoint(ctx context.Context, request interface{}, svc fleet.Service) (interface{}, error) {
|
||||
req := request.(*getGlobalScheduleRequest)
|
||||
|
||||
gp, err := svc.GetGlobalScheduledQueries(ctx, req.ListOptions)
|
||||
if err != nil {
|
||||
return getGlobalScheduleResponse{Err: err}, nil
|
||||
}
|
||||
|
||||
return getGlobalScheduleResponse{
|
||||
GlobalSchedule: gp,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (svc *Service) GetGlobalScheduledQueries(ctx context.Context, opts fleet.ListOptions) ([]*fleet.ScheduledQuery, error) {
|
||||
if err := svc.authz.Authorize(ctx, &fleet.Pack{}, fleet.ActionRead); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
gp, err := svc.ds.EnsureGlobalPack(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return svc.ds.ListScheduledQueriesInPack(ctx, gp.ID, opts)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Global Schedule Query
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
type globalScheduleQueryRequest struct {
|
||||
QueryID uint `json:"query_id"`
|
||||
Interval uint `json:"interval"`
|
||||
Snapshot *bool `json:"snapshot"`
|
||||
Removed *bool `json:"removed"`
|
||||
Platform *string `json:"platform"`
|
||||
Version *string `json:"version"`
|
||||
Shard *uint `json:"shard"`
|
||||
}
|
||||
|
||||
type globalScheduleQueryResponse struct {
|
||||
Scheduled *fleet.ScheduledQuery `json:"scheduled,omitempty"`
|
||||
Err error `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (r globalScheduleQueryResponse) error() error { return r.Err }
|
||||
|
||||
func globalScheduleQueryEndpoint(ctx context.Context, request interface{}, svc fleet.Service) (interface{}, error) {
|
||||
req := request.(*globalScheduleQueryRequest)
|
||||
|
||||
scheduled, err := svc.GlobalScheduleQuery(ctx, &fleet.ScheduledQuery{
|
||||
QueryID: req.QueryID,
|
||||
Interval: req.Interval,
|
||||
Snapshot: req.Snapshot,
|
||||
Removed: req.Removed,
|
||||
Platform: req.Platform,
|
||||
Version: req.Version,
|
||||
Shard: req.Shard,
|
||||
})
|
||||
if err != nil {
|
||||
return globalScheduleQueryResponse{Err: err}, nil
|
||||
}
|
||||
return globalScheduleQueryResponse{Scheduled: scheduled}, nil
|
||||
}
|
||||
|
||||
func (svc *Service) GlobalScheduleQuery(ctx context.Context, sq *fleet.ScheduledQuery) (*fleet.ScheduledQuery, error) {
|
||||
if err := svc.authz.Authorize(ctx, &fleet.Pack{}, fleet.ActionRead); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
gp, err := svc.ds.EnsureGlobalPack(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sq.PackID = gp.ID
|
||||
|
||||
return svc.ScheduleQuery(ctx, sq)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Modify Global Schedule
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
type modifyGlobalScheduleRequest struct {
|
||||
ID uint `json:"-" url:"id"`
|
||||
fleet.ScheduledQueryPayload
|
||||
}
|
||||
|
||||
type modifyGlobalScheduleResponse struct {
|
||||
Scheduled *fleet.ScheduledQuery `json:"scheduled,omitempty"`
|
||||
Err error `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (r modifyGlobalScheduleResponse) error() error { return r.Err }
|
||||
|
||||
func modifyGlobalScheduleEndpoint(ctx context.Context, request interface{}, svc fleet.Service) (interface{}, error) {
|
||||
req := request.(*modifyGlobalScheduleRequest)
|
||||
|
||||
sq, err := svc.ModifyGlobalScheduledQueries(ctx, req.ID, req.ScheduledQueryPayload)
|
||||
if err != nil {
|
||||
return modifyGlobalScheduleResponse{Err: err}, nil
|
||||
}
|
||||
|
||||
return modifyGlobalScheduleResponse{
|
||||
Scheduled: sq,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (svc *Service) ModifyGlobalScheduledQueries(ctx context.Context, id uint, query fleet.ScheduledQueryPayload) (*fleet.ScheduledQuery, error) {
|
||||
if err := svc.authz.Authorize(ctx, &fleet.Pack{}, fleet.ActionWrite); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
gp, err := svc.ds.EnsureGlobalPack(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
query.PackID = ptr.Uint(gp.ID)
|
||||
|
||||
return svc.ModifyScheduledQuery(ctx, id, query)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Delete Global Schedule
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
type deleteGlobalScheduleRequest struct {
|
||||
ID uint `url:"id"`
|
||||
}
|
||||
|
||||
type deleteGlobalScheduleResponse struct {
|
||||
Err error `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (r deleteGlobalScheduleResponse) error() error { return r.Err }
|
||||
|
||||
func deleteGlobalScheduleEndpoint(ctx context.Context, request interface{}, svc fleet.Service) (interface{}, error) {
|
||||
req := request.(*deleteGlobalScheduleRequest)
|
||||
err := svc.DeleteGlobalScheduledQueries(ctx, req.ID)
|
||||
if err != nil {
|
||||
return deleteGlobalScheduleResponse{Err: err}, nil
|
||||
}
|
||||
|
||||
return deleteGlobalScheduleResponse{}, nil
|
||||
}
|
||||
|
||||
func (svc *Service) DeleteGlobalScheduledQueries(ctx context.Context, id uint) error {
|
||||
if err := svc.authz.Authorize(ctx, &fleet.Pack{}, fleet.ActionWrite); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return svc.DeleteScheduledQuery(ctx, id)
|
||||
}
|
||||
|
|
@ -20,6 +20,18 @@ func TestGlobalScheduleAuth(t *testing.T) {
|
|||
ds.EnsureGlobalPackFunc = func(ctx context.Context) (*fleet.Pack, error) {
|
||||
return &fleet.Pack{}, nil
|
||||
}
|
||||
ds.NewScheduledQueryFunc = func(ctx context.Context, sq *fleet.ScheduledQuery, opts ...fleet.OptionalArg) (*fleet.ScheduledQuery, error) {
|
||||
return sq, nil
|
||||
}
|
||||
ds.ScheduledQueryFunc = func(ctx context.Context, id uint) (*fleet.ScheduledQuery, error) {
|
||||
return &fleet.ScheduledQuery{}, nil
|
||||
}
|
||||
ds.SaveScheduledQueryFunc = func(ctx context.Context, sq *fleet.ScheduledQuery) (*fleet.ScheduledQuery, error) {
|
||||
return sq, nil
|
||||
}
|
||||
ds.DeleteScheduledQueryFunc = func(ctx context.Context, id uint) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
var testCases = []struct {
|
||||
name string
|
||||
|
|
@ -70,6 +82,15 @@ func TestGlobalScheduleAuth(t *testing.T) {
|
|||
|
||||
_, err := svc.GetGlobalScheduledQueries(ctx, fleet.ListOptions{})
|
||||
checkAuthErr(t, tt.shouldFailRead, err)
|
||||
|
||||
_, err = svc.GlobalScheduleQuery(ctx, &fleet.ScheduledQuery{Name: "query", QueryName: "query"})
|
||||
checkAuthErr(t, tt.shouldFailWrite, err)
|
||||
|
||||
_, err = svc.ModifyGlobalScheduledQueries(ctx, 1, fleet.ScheduledQueryPayload{})
|
||||
checkAuthErr(t, tt.shouldFailWrite, err)
|
||||
|
||||
err = svc.DeleteGlobalScheduledQueries(ctx, 1)
|
||||
checkAuthErr(t, tt.shouldFailWrite, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -73,10 +73,6 @@ type FleetEndpoints struct {
|
|||
ApplyPackSpecs endpoint.Endpoint
|
||||
GetPackSpecs endpoint.Endpoint
|
||||
GetPackSpec endpoint.Endpoint
|
||||
GlobalScheduleQuery endpoint.Endpoint
|
||||
GetGlobalSchedule endpoint.Endpoint
|
||||
ModifyGlobalSchedule endpoint.Endpoint
|
||||
DeleteGlobalSchedule endpoint.Endpoint
|
||||
EnrollAgent endpoint.Endpoint
|
||||
GetClientConfig endpoint.Endpoint
|
||||
GetDistributedQueries endpoint.Endpoint
|
||||
|
|
@ -184,10 +180,6 @@ func MakeFleetServerEndpoints(svc fleet.Service, urlPrefix string, limitStore th
|
|||
ApplyPackSpecs: authenticatedUser(svc, makeApplyPackSpecsEndpoint(svc)),
|
||||
GetPackSpecs: authenticatedUser(svc, makeGetPackSpecsEndpoint(svc)),
|
||||
GetPackSpec: authenticatedUser(svc, makeGetPackSpecEndpoint(svc)),
|
||||
GlobalScheduleQuery: authenticatedUser(svc, makeGlobalScheduleQueryEndpoint(svc)),
|
||||
GetGlobalSchedule: authenticatedUser(svc, makeGetGlobalScheduleEndpoint(svc)),
|
||||
ModifyGlobalSchedule: authenticatedUser(svc, makeModifyGlobalScheduleEndpoint(svc)),
|
||||
DeleteGlobalSchedule: authenticatedUser(svc, makeDeleteGlobalScheduleEndpoint(svc)),
|
||||
CreateLabel: authenticatedUser(svc, makeCreateLabelEndpoint(svc)),
|
||||
ModifyLabel: authenticatedUser(svc, makeModifyLabelEndpoint(svc)),
|
||||
GetLabel: authenticatedUser(svc, makeGetLabelEndpoint(svc)),
|
||||
|
|
@ -283,10 +275,6 @@ type fleetHandlers struct {
|
|||
ApplyPackSpecs http.Handler
|
||||
GetPackSpecs http.Handler
|
||||
GetPackSpec http.Handler
|
||||
GlobalScheduleQuery http.Handler
|
||||
GetGlobalSchedule http.Handler
|
||||
ModifyGlobalSchedule http.Handler
|
||||
DeleteGlobalSchedule http.Handler
|
||||
EnrollAgent http.Handler
|
||||
GetClientConfig http.Handler
|
||||
GetDistributedQueries http.Handler
|
||||
|
|
@ -381,10 +369,6 @@ func makeKitHandlers(e FleetEndpoints, opts []kithttp.ServerOption) *fleetHandle
|
|||
ApplyPackSpecs: newServer(e.ApplyPackSpecs, decodeApplyPackSpecsRequest),
|
||||
GetPackSpecs: newServer(e.GetPackSpecs, decodeNoParamsRequest),
|
||||
GetPackSpec: newServer(e.GetPackSpec, decodeGetGenericSpecRequest),
|
||||
GlobalScheduleQuery: newServer(e.GlobalScheduleQuery, decodeGlobalScheduleQueryRequest),
|
||||
GetGlobalSchedule: newServer(e.GetGlobalSchedule, decodeGetGlobalScheduleRequest),
|
||||
ModifyGlobalSchedule: newServer(e.ModifyGlobalSchedule, decodeModifyGlobalScheduleRequest),
|
||||
DeleteGlobalSchedule: newServer(e.DeleteGlobalSchedule, decodeDeleteGlobalScheduleRequest),
|
||||
EnrollAgent: newServer(e.EnrollAgent, decodeEnrollAgentRequest),
|
||||
GetClientConfig: newServer(e.GetClientConfig, decodeGetClientConfigRequest),
|
||||
GetDistributedQueries: newServer(e.GetDistributedQueries, decodeGetDistributedQueriesRequest),
|
||||
|
|
@ -581,11 +565,6 @@ func attachFleetAPIRoutes(r *mux.Router, h *fleetHandlers) {
|
|||
r.Handle("/api/v1/fleet/spec/packs", h.GetPackSpecs).Methods("GET").Name("get_pack_specs")
|
||||
r.Handle("/api/v1/fleet/spec/packs/{name}", h.GetPackSpec).Methods("GET").Name("get_pack_spec")
|
||||
|
||||
r.Handle("/api/v1/fleet/global/schedule", h.GetGlobalSchedule).Methods("GET").Name("set_global_schedule")
|
||||
r.Handle("/api/v1/fleet/global/schedule", h.GlobalScheduleQuery).Methods("POST").Name("add_to_global_schedule")
|
||||
r.Handle("/api/v1/fleet/global/schedule/{id:[0-9]+}", h.ModifyGlobalSchedule).Methods("PATCH").Name("modify_global_schedule")
|
||||
r.Handle("/api/v1/fleet/global/schedule/{id:[0-9]+}", h.DeleteGlobalSchedule).Methods("DELETE").Name("delete_global_schedule")
|
||||
|
||||
r.Handle("/api/v1/fleet/labels", h.CreateLabel).Methods("POST").Name("create_label")
|
||||
r.Handle("/api/v1/fleet/labels/{id:[0-9]+}", h.ModifyLabel).Methods("PATCH").Name("modify_label")
|
||||
r.Handle("/api/v1/fleet/labels/{id:[0-9]+}", h.GetLabel).Methods("GET").Name("get_label")
|
||||
|
|
@ -684,6 +663,11 @@ func attachNewStyleFleetAPIRoutes(r *mux.Router, svc fleet.Service, opts []kitht
|
|||
|
||||
e.GET("/api/v1/fleet/activities", listActivitiesEndpoint, listActivitiesRequest{})
|
||||
|
||||
e.GET("/api/v1/fleet/global/schedule", getGlobalScheduleEndpoint, getGlobalScheduleRequest{})
|
||||
e.POST("/api/v1/fleet/global/schedule", globalScheduleQueryEndpoint, globalScheduleQueryRequest{})
|
||||
e.PATCH("/api/v1/fleet/global/schedule/{id:[0-9]+}", modifyGlobalScheduleEndpoint, modifyGlobalScheduleRequest{})
|
||||
e.DELETE("/api/v1/fleet/global/schedule/{id:[0-9]+}", deleteGlobalScheduleEndpoint, deleteGlobalScheduleRequest{})
|
||||
|
||||
e.GET("/api/v1/fleet/carves", listCarvesEndpoint, listCarvesRequest{})
|
||||
e.GET("/api/v1/fleet/carves/{id:[0-9]+}", getCarveEndpoint, getCarveRequest{})
|
||||
e.GET("/api/v1/fleet/carves/{id:[0-9]+}/block/{block_id}", getCarveBlockEndpoint, getCarveBlockRequest{})
|
||||
|
|
|
|||
|
|
@ -226,10 +226,12 @@ func (s *integrationTestSuite) TestUserRolesSpec() {
|
|||
func (s *integrationTestSuite) TestGlobalSchedule() {
|
||||
t := s.T()
|
||||
|
||||
// list the existing global schedules (none yet)
|
||||
gs := fleet.GlobalSchedulePayload{}
|
||||
s.DoJSON("GET", "/api/v1/fleet/global/schedule", nil, http.StatusOK, &gs)
|
||||
require.Len(t, gs.GlobalSchedule, 0)
|
||||
|
||||
// create a query that can be scheduled
|
||||
qr, err := s.ds.NewQuery(context.Background(), &fleet.Query{
|
||||
Name: "TestQuery1",
|
||||
Description: "Some description",
|
||||
|
|
@ -238,10 +240,12 @@ func (s *integrationTestSuite) TestGlobalSchedule() {
|
|||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
// schedule that query
|
||||
gsParams := fleet.ScheduledQueryPayload{QueryID: ptr.Uint(qr.ID), Interval: ptr.Uint(42)}
|
||||
r := globalScheduleQueryResponse{}
|
||||
s.DoJSON("POST", "/api/v1/fleet/global/schedule", gsParams, http.StatusOK, &r)
|
||||
|
||||
// list the scheduled queries, get the one just created
|
||||
gs = fleet.GlobalSchedulePayload{}
|
||||
s.DoJSON("GET", "/api/v1/fleet/global/schedule", nil, http.StatusOK, &gs)
|
||||
require.Len(t, gs.GlobalSchedule, 1)
|
||||
|
|
@ -249,18 +253,34 @@ func (s *integrationTestSuite) TestGlobalSchedule() {
|
|||
assert.Equal(t, "TestQuery1", gs.GlobalSchedule[0].Name)
|
||||
id := gs.GlobalSchedule[0].ID
|
||||
|
||||
// list page 2, should be empty
|
||||
s.DoJSON("GET", "/api/v1/fleet/global/schedule", nil, http.StatusOK, &gs, "page", "2", "per_page", "4")
|
||||
require.Len(t, gs.GlobalSchedule, 0)
|
||||
|
||||
// update the scheduled query
|
||||
gs = fleet.GlobalSchedulePayload{}
|
||||
gsParams = fleet.ScheduledQueryPayload{Interval: ptr.Uint(55)}
|
||||
s.DoJSON("PATCH", fmt.Sprintf("/api/v1/fleet/global/schedule/%d", id), gsParams, http.StatusOK, &gs)
|
||||
|
||||
// update a non-existing schedule
|
||||
gsParams = fleet.ScheduledQueryPayload{Interval: ptr.Uint(66)}
|
||||
s.DoJSON("PATCH", fmt.Sprintf("/api/v1/fleet/global/schedule/%d", id+1), gsParams, http.StatusNotFound, &gs)
|
||||
|
||||
// read back that updated scheduled query
|
||||
gs = fleet.GlobalSchedulePayload{}
|
||||
s.DoJSON("GET", "/api/v1/fleet/global/schedule", nil, http.StatusOK, &gs)
|
||||
require.Len(t, gs.GlobalSchedule, 1)
|
||||
assert.Equal(t, id, gs.GlobalSchedule[0].ID)
|
||||
assert.Equal(t, uint(55), gs.GlobalSchedule[0].Interval)
|
||||
|
||||
// delete the scheduled query
|
||||
r = globalScheduleQueryResponse{}
|
||||
s.DoJSON("DELETE", fmt.Sprintf("/api/v1/fleet/global/schedule/%d", id), nil, http.StatusOK, &r)
|
||||
|
||||
// delete a non-existing schedule
|
||||
s.DoJSON("DELETE", fmt.Sprintf("/api/v1/fleet/global/schedule/%d", id+1), nil, http.StatusNotFound, &r)
|
||||
|
||||
// list the scheduled queries, back to none
|
||||
gs = fleet.GlobalSchedulePayload{}
|
||||
s.DoJSON("GET", "/api/v1/fleet/global/schedule", nil, http.StatusOK, &gs)
|
||||
require.Len(t, gs.GlobalSchedule, 0)
|
||||
|
|
|
|||
|
|
@ -1,62 +0,0 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/fleetdm/fleet/v4/server/fleet"
|
||||
"github.com/fleetdm/fleet/v4/server/ptr"
|
||||
)
|
||||
|
||||
func (svc *Service) GlobalScheduleQuery(ctx context.Context, sq *fleet.ScheduledQuery) (*fleet.ScheduledQuery, error) {
|
||||
if err := svc.authz.Authorize(ctx, &fleet.Pack{}, fleet.ActionRead); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
gp, err := svc.ds.EnsureGlobalPack(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sq.PackID = gp.ID
|
||||
|
||||
return svc.ScheduleQuery(ctx, sq)
|
||||
}
|
||||
|
||||
func (svc *Service) GetGlobalScheduledQueries(ctx context.Context, opts fleet.ListOptions) ([]*fleet.ScheduledQuery, error) {
|
||||
if err := svc.authz.Authorize(ctx, &fleet.Pack{}, fleet.ActionRead); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
gp, err := svc.ds.EnsureGlobalPack(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return svc.ds.ListScheduledQueriesInPack(ctx, gp.ID, opts)
|
||||
}
|
||||
|
||||
func (svc *Service) ModifyGlobalScheduledQueries(
|
||||
ctx context.Context,
|
||||
id uint,
|
||||
query fleet.ScheduledQueryPayload,
|
||||
) (*fleet.ScheduledQuery, error) {
|
||||
if err := svc.authz.Authorize(ctx, &fleet.Pack{}, fleet.ActionWrite); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
gp, err := svc.ds.EnsureGlobalPack(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
query.PackID = ptr.Uint(gp.ID)
|
||||
|
||||
return svc.ModifyScheduledQuery(ctx, id, query)
|
||||
}
|
||||
|
||||
func (svc *Service) DeleteGlobalScheduledQueries(ctx context.Context, id uint) error {
|
||||
if err := svc.authz.Authorize(ctx, &fleet.Pack{}, fleet.ActionWrite); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return svc.DeleteScheduledQuery(ctx, id)
|
||||
}
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func decodeGetGlobalScheduleRequest(ctx context.Context, r *http.Request) (interface{}, error) {
|
||||
opts, err := listOptionsFromRequest(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var req getGlobalScheduleRequest
|
||||
req.ListOptions = opts
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func decodeModifyGlobalScheduleRequest(ctx context.Context, r *http.Request) (interface{}, error) {
|
||||
id, err := uintFromRequest(r, "id")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var req modifyGlobalScheduleRequest
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(&req.payload); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req.ID = uint(id)
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func decodeDeleteGlobalScheduleRequest(ctx context.Context, r *http.Request) (interface{}, error) {
|
||||
id, err := uintFromRequest(r, "id")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var req deleteGlobalScheduleRequest
|
||||
req.ID = uint(id)
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func decodeGlobalScheduleQueryRequest(ctx context.Context, r *http.Request) (interface{}, error) {
|
||||
var req globalScheduleQueryRequest
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return req, nil
|
||||
}
|
||||
Loading…
Reference in a new issue