diff --git a/server/kolide/teams.go b/server/kolide/teams.go index 3642aa3a58..c7ff55187c 100644 --- a/server/kolide/teams.go +++ b/server/kolide/teams.go @@ -25,8 +25,10 @@ type TeamStore interface { type TeamService interface { // NewTeam creates a new team. NewTeam(ctx context.Context, p TeamPayload) (*Team, error) - // ModifyTeam modifies an existing team. + // ModifyTeam modifies an existing team (besides agent options). ModifyTeam(ctx context.Context, id uint, payload TeamPayload) (*Team, error) + // ModifyTeam modifies agent options for a team. + ModifyTeamAgentOptions(ctx context.Context, id uint, options json.RawMessage) (*Team, error) // AddTeamUsers adds users to an existing team. AddTeamUsers(ctx context.Context, teamID uint, users []TeamUser) (*Team, error) // DeleteTeamUsers deletes users from an existing team. @@ -41,9 +43,9 @@ type TeamService interface { } type TeamPayload struct { - Name *string `json:"name"` - Description *string `json:"description"` - AgentOptions *json.RawMessage `json:"agent_options"` + Name *string `json:"name"` + Description *string `json:"description"` + // Note AgentOptions must be set by a separate endpoint. } // Team is the data representation for the "Team" concept (group of hosts and diff --git a/server/service/endpoint_teams.go b/server/service/endpoint_teams.go index 95bc9235c6..ef1364ef7e 100644 --- a/server/service/endpoint_teams.go +++ b/server/service/endpoint_teams.go @@ -2,6 +2,7 @@ package service import ( "context" + "encoding/json" "github.com/fleetdm/fleet/server/kolide" "github.com/go-kit/kit/endpoint" @@ -15,12 +16,12 @@ type createTeamRequest struct { payload kolide.TeamPayload } -type createTeamResponse struct { +type teamResponse struct { Team *kolide.Team `json:"team,omitempty"` Err error `json:"error,omitempty"` } -func (r createTeamResponse) error() error { return r.Err } +func (r teamResponse) error() error { return r.Err } func makeCreateTeamEndpoint(svc kolide.Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { @@ -28,10 +29,10 @@ func makeCreateTeamEndpoint(svc kolide.Service) endpoint.Endpoint { team, err := svc.NewTeam(ctx, req.payload) if err != nil { - return createTeamResponse{Err: err}, nil + return teamResponse{Err: err}, nil } - return createTeamResponse{Team: team}, nil + return teamResponse{Team: team}, nil } } @@ -44,22 +45,36 @@ type modifyTeamRequest struct { payload kolide.TeamPayload } -type modifyTeamResponse struct { - Team *kolide.Team `json:"team,omitempty"` - Err error `json:"error,omitempty"` -} - -func (r modifyTeamResponse) error() error { return r.Err } - func makeModifyTeamEndpoint(svc kolide.Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(modifyTeamRequest) team, err := svc.ModifyTeam(ctx, req.ID, req.payload) if err != nil { - return modifyTeamResponse{Err: err}, nil + return teamResponse{Err: err}, nil } - return modifyTeamResponse{Team: team}, err + return teamResponse{Team: team}, err + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Modify Team Agent Options +//////////////////////////////////////////////////////////////////////////////// + +type modifyTeamAgentOptionsRequest struct { + ID uint + options json.RawMessage +} + +func makeModifyTeamAgentOptionsEndpoint(svc kolide.Service) endpoint.Endpoint { + return func(ctx context.Context, request interface{}) (interface{}, error) { + req := request.(modifyTeamAgentOptionsRequest) + team, err := svc.ModifyTeamAgentOptions(ctx, req.ID, req.options) + if err != nil { + return teamResponse{Err: err}, nil + } + + return teamResponse{Team: team}, err } } @@ -160,10 +175,10 @@ func makeAddTeamUsersEndpoint(svc kolide.Service) endpoint.Endpoint { req := request.(modifyTeamUsersRequest) team, err := svc.AddTeamUsers(ctx, req.TeamID, req.Users) if err != nil { - return modifyTeamResponse{Err: err}, nil + return teamResponse{Err: err}, nil } - return modifyTeamResponse{Team: team}, err + return teamResponse{Team: team}, err } } @@ -172,9 +187,9 @@ func makeDeleteTeamUsersEndpoint(svc kolide.Service) endpoint.Endpoint { req := request.(modifyTeamUsersRequest) team, err := svc.DeleteTeamUsers(ctx, req.TeamID, req.Users) if err != nil { - return modifyTeamResponse{Err: err}, nil + return teamResponse{Err: err}, nil } - return modifyTeamResponse{Team: team}, err + return teamResponse{Team: team}, err } } diff --git a/server/service/handler.go b/server/service/handler.go index b5d155753b..0687e44692 100644 --- a/server/service/handler.go +++ b/server/service/handler.go @@ -110,6 +110,7 @@ type KolideEndpoints struct { Version endpoint.Endpoint CreateTeam endpoint.Endpoint ModifyTeam endpoint.Endpoint + ModifyTeamAgentOptions endpoint.Endpoint DeleteTeam endpoint.Endpoint ListTeams endpoint.Endpoint ListTeamUsers endpoint.Endpoint @@ -216,13 +217,14 @@ func MakeKolideServerEndpoints(svc kolide.Service, jwtKey, urlPrefix string, lim GetCarveBlock: authenticatedUser(jwtKey, svc, makeGetCarveBlockEndpoint(svc)), Version: authenticatedUser(jwtKey, svc, makeVersionEndpoint(svc)), // TODO permissions for teams endpoints - CreateTeam: authenticatedUser(jwtKey, svc, makeCreateTeamEndpoint(svc)), - ModifyTeam: authenticatedUser(jwtKey, svc, makeModifyTeamEndpoint(svc)), - DeleteTeam: authenticatedUser(jwtKey, svc, makeDeleteTeamEndpoint(svc)), - ListTeams: authenticatedUser(jwtKey, svc, makeListTeamsEndpoint(svc)), - ListTeamUsers: authenticatedUser(jwtKey, svc, makeListTeamUsersEndpoint(svc)), - AddTeamUsers: authenticatedUser(jwtKey, svc, makeAddTeamUsersEndpoint(svc)), - DeleteTeamUsers: authenticatedUser(jwtKey, svc, makeDeleteTeamUsersEndpoint(svc)), + CreateTeam: authenticatedUser(jwtKey, svc, makeCreateTeamEndpoint(svc)), + ModifyTeam: authenticatedUser(jwtKey, svc, makeModifyTeamEndpoint(svc)), + ModifyTeamAgentOptions: authenticatedUser(jwtKey, svc, makeModifyTeamAgentOptionsEndpoint(svc)), + DeleteTeam: authenticatedUser(jwtKey, svc, makeDeleteTeamEndpoint(svc)), + ListTeams: authenticatedUser(jwtKey, svc, makeListTeamsEndpoint(svc)), + ListTeamUsers: authenticatedUser(jwtKey, svc, makeListTeamUsersEndpoint(svc)), + AddTeamUsers: authenticatedUser(jwtKey, svc, makeAddTeamUsersEndpoint(svc)), + DeleteTeamUsers: authenticatedUser(jwtKey, svc, makeDeleteTeamUsersEndpoint(svc)), // Authenticated status endpoints StatusResultStore: authenticatedUser(jwtKey, svc, makeStatusResultStoreEndpoint(svc)), @@ -332,6 +334,7 @@ type kolideHandlers struct { Version http.Handler CreateTeam http.Handler ModifyTeam http.Handler + ModifyTeamAgentOptions http.Handler DeleteTeam http.Handler ListTeams http.Handler ListTeamUsers http.Handler @@ -433,6 +436,7 @@ func makeKolideKitHandlers(e KolideEndpoints, opts []kithttp.ServerOption) *koli Version: newServer(e.Version, decodeNoParamsRequest), CreateTeam: newServer(e.CreateTeam, decodeCreateTeamRequest), ModifyTeam: newServer(e.ModifyTeam, decodeModifyTeamRequest), + ModifyTeamAgentOptions: newServer(e.ModifyTeamAgentOptions, decodeModifyTeamAgentOptionsRequest), DeleteTeam: newServer(e.DeleteTeam, decodeDeleteTeamRequest), ListTeams: newServer(e.ListTeams, decodeListTeamsRequest), ListTeamUsers: newServer(e.ListTeamUsers, decodeListTeamUsersRequest), @@ -651,6 +655,7 @@ func attachKolideAPIRoutes(r *mux.Router, h *kolideHandlers) { r.Handle("/api/v1/fleet/teams", h.ListTeams).Methods("GET").Name("list_teams") r.Handle("/api/v1/fleet/teams/{id}", h.ModifyTeam).Methods("PATCH").Name("modify_team") r.Handle("/api/v1/fleet/teams/{id}", h.DeleteTeam).Methods("DELETE").Name("delete_team") + r.Handle("/api/v1/fleet/teams/{id}/agent_options", h.ModifyTeamAgentOptions).Methods("POST").Name("modify_team_agent_options") r.Handle("/api/v1/fleet/teams/{id}/users", h.ListTeamUsers).Methods("GET").Name("team_users") r.Handle("/api/v1/fleet/teams/{id}/users", h.AddTeamUsers).Methods("PATCH").Name("add_team_users") r.Handle("/api/v1/fleet/teams/{id}/users", h.DeleteTeamUsers).Methods("DELETE").Name("delete_team_users") diff --git a/server/service/service_teams.go b/server/service/service_teams.go index 68fb17d70b..918443e6a8 100644 --- a/server/service/service_teams.go +++ b/server/service/service_teams.go @@ -2,13 +2,14 @@ package service import ( "context" + "encoding/json" "fmt" "github.com/fleetdm/fleet/server/kolide" ) func (svc service) NewTeam(ctx context.Context, p kolide.TeamPayload) (*kolide.Team, error) { - team := &kolide.Team{AgentOptions: p.AgentOptions} + team := &kolide.Team{} if p.Name == nil { return nil, newInvalidArgumentError("name", "missing required argument") @@ -43,8 +44,20 @@ func (svc service) ModifyTeam(ctx context.Context, id uint, payload kolide.TeamP if payload.Description != nil { team.Description = *payload.Description } - if payload.AgentOptions != nil { - team.AgentOptions = payload.AgentOptions + + return svc.ds.SaveTeam(team) +} + +func (svc service) ModifyTeamAgentOptions(ctx context.Context, id uint, options json.RawMessage) (*kolide.Team, error) { + team, err := svc.ds.Team(id) + if err != nil { + return nil, err + } + + if options != nil { + team.AgentOptions = &options + } else { + team.AgentOptions = nil } return svc.ds.SaveTeam(team) diff --git a/server/service/transport_teams.go b/server/service/transport_teams.go index b9edec25ee..ff4856027e 100644 --- a/server/service/transport_teams.go +++ b/server/service/transport_teams.go @@ -19,13 +19,26 @@ func decodeModifyTeamRequest(ctx context.Context, r *http.Request) (interface{}, if err != nil { return nil, err } - var resp modifyTeamRequest - err = json.NewDecoder(r.Body).Decode(&resp.payload) + req := modifyTeamRequest{ID: id} + err = json.NewDecoder(r.Body).Decode(&req.payload) if err != nil { return nil, err } - resp.ID = id - return resp, nil + req.ID = id + return req, nil +} + +func decodeModifyTeamAgentOptionsRequest(ctx context.Context, r *http.Request) (interface{}, error) { + id, err := idFromRequest(r, "id") + if err != nil { + return nil, err + } + req := modifyTeamAgentOptionsRequest{ID: id} + err = json.NewDecoder(r.Body).Decode(&req.options) + if err != nil { + return nil, err + } + return req, nil } func decodeListTeamsRequest(ctx context.Context, r *http.Request) (interface{}, error) { @@ -61,11 +74,10 @@ func decodeModifyTeamUsersRequest(ctx context.Context, r *http.Request) (interfa if err != nil { return nil, err } - var req modifyTeamUsersRequest + req := modifyTeamUsersRequest{TeamID: id} err = json.NewDecoder(r.Body).Decode(&req) if err != nil { return nil, err } - req.TeamID = id return req, nil }