diff --git a/server/service/client.go b/server/service/client.go index fa3bedebe9..1737eedd87 100644 --- a/server/service/client.go +++ b/server/service/client.go @@ -26,7 +26,7 @@ func NewClient(addr string, insecureSkipVerify bool) (*Client, error) { baseURL, err := url.Parse(addr) if err != nil { - return nil, errors.Wrap(err, "error parsing URL") + return nil, errors.Wrap(err, "parsing URL") } httpClient := &http.Client{ @@ -43,18 +43,22 @@ func NewClient(addr string, insecureSkipVerify bool) (*Client, error) { } func (c *Client) doWithHeaders(verb, path string, params interface{}, headers map[string]string) (*http.Response, error) { - b, err := json.Marshal(params) - if err != nil { - return nil, errors.Wrap(err, "error marshaling json") + var bodyBytes []byte + var err error + if params != nil { + bodyBytes, err = json.Marshal(params) + if err != nil { + return nil, errors.Wrap(err, "marshaling json") + } } request, err := http.NewRequest( verb, c.url(path).String(), - bytes.NewBuffer(b), + bytes.NewBuffer(bodyBytes), ) if err != nil { - return nil, errors.Wrap(err, "error creating request object") + return nil, errors.Wrap(err, "creating request object") } for k, v := range headers { request.Header.Set(k, v) diff --git a/server/service/client_labels.go b/server/service/client_labels.go new file mode 100644 index 0000000000..83ee41ace0 --- /dev/null +++ b/server/service/client_labels.go @@ -0,0 +1,89 @@ +package service + +import ( + "encoding/json" + "net/http" + "net/url" + + "github.com/kolide/fleet/server/kolide" + "github.com/pkg/errors" +) + +// ApplyLabelSpecs sends the list of Labels to be applied (upserted) to the +// Fleet instance. +func (c *Client) ApplyLabelSpecs(specs []*kolide.LabelSpec) error { + req := applyLabelSpecsRequest{Specs: specs} + response, err := c.Do("POST", "/api/v1/kolide/spec/labels", req) + if err != nil { + return errors.Wrap(err, "POST /api/v1/kolide/spec/labels") + } + defer response.Body.Close() + + if response.StatusCode != http.StatusOK { + return errors.Errorf("apply label spec got HTTP %d, expected 200", response.StatusCode) + } + + var responseBody applyLabelSpecsResponse + err = json.NewDecoder(response.Body).Decode(&responseBody) + if err != nil { + return errors.Wrap(err, "decode apply label spec response") + } + + if responseBody.Err != nil { + return errors.Errorf("apply label spec: %s", responseBody.Err) + } + + return nil +} + +// GetLabelSpecs retrieves the list of all Labels. +func (c *Client) GetLabelSpecs(specs []*kolide.LabelSpec) ([]*kolide.LabelSpec, error) { + req := applyLabelSpecsRequest{Specs: specs} + response, err := c.Do("GET", "/api/v1/kolide/spec/labels", req) + if err != nil { + return nil, errors.Wrap(err, "GET /api/v1/kolide/spec/labels") + } + defer response.Body.Close() + + if response.StatusCode != http.StatusOK { + return nil, errors.Errorf("get label spec got HTTP %d, expected 200", response.StatusCode) + } + + var responseBody getLabelSpecsResponse + err = json.NewDecoder(response.Body).Decode(&responseBody) + if err != nil { + return nil, errors.Wrap(err, "decode get label spec response") + } + + if responseBody.Err != nil { + return nil, errors.Errorf("get label spec: %s", responseBody.Err) + } + + return responseBody.Specs, nil +} + +// DeleteLabel deletes the label with the matching name. +func (c *Client) DeleteLabel(name string) error { + verb, path := "DELETE", "/api/v1/kolide/labels/"+url.QueryEscape(name) + response, err := c.Do(verb, path, nil) + if err != nil { + return errors.Wrapf(err, "%s %s", verb, path) + } + defer response.Body.Close() + + if response.StatusCode != http.StatusOK { + return errors.Errorf("get label spec got HTTP %d, expected 200", response.StatusCode) + } + + var responseBody deleteLabelResponse + err = json.NewDecoder(response.Body).Decode(&responseBody) + if err != nil { + return errors.Wrap(err, "decode get label spec response") + } + + if responseBody.Err != nil { + return errors.Errorf("get label spec: %s", responseBody.Err) + } + + return nil +} diff --git a/server/service/client_packs.go b/server/service/client_packs.go new file mode 100644 index 0000000000..93975330f2 --- /dev/null +++ b/server/service/client_packs.go @@ -0,0 +1,89 @@ +package service + +import ( + "encoding/json" + "net/http" + "net/url" + + "github.com/kolide/fleet/server/kolide" + "github.com/pkg/errors" +) + +// ApplyPackSpecs sends the list of Packs to be applied (upserted) to the +// Fleet instance. +func (c *Client) ApplyPackSpecs(specs []*kolide.PackSpec) error { + req := applyPackSpecsRequest{Specs: specs} + response, err := c.Do("POST", "/api/v1/kolide/spec/packs", req) + if err != nil { + return errors.Wrap(err, "POST /api/v1/kolide/spec/packs") + } + defer response.Body.Close() + + if response.StatusCode != http.StatusOK { + return errors.Errorf("apply pack spec got HTTP %d, expected 200", response.StatusCode) + } + + var responseBody applyPackSpecsResponse + err = json.NewDecoder(response.Body).Decode(&responseBody) + if err != nil { + return errors.Wrap(err, "decode apply pack spec response") + } + + if responseBody.Err != nil { + return errors.Errorf("apply pack spec: %s", responseBody.Err) + } + + return nil +} + +// GetPackSpecs retrieves the list of all Packs. +func (c *Client) GetPackSpecs(specs []*kolide.PackSpec) ([]*kolide.PackSpec, error) { + req := applyPackSpecsRequest{Specs: specs} + response, err := c.Do("GET", "/api/v1/kolide/spec/packs", req) + if err != nil { + return nil, errors.Wrap(err, "GET /api/v1/kolide/spec/packs") + } + defer response.Body.Close() + + if response.StatusCode != http.StatusOK { + return nil, errors.Errorf("get pack spec got HTTP %d, expected 200", response.StatusCode) + } + + var responseBody getPackSpecsResponse + err = json.NewDecoder(response.Body).Decode(&responseBody) + if err != nil { + return nil, errors.Wrap(err, "decode get pack spec response") + } + + if responseBody.Err != nil { + return nil, errors.Errorf("get pack spec: %s", responseBody.Err) + } + + return responseBody.Specs, nil +} + +// DeletePack deletes the pack with the matching name. +func (c *Client) DeletePack(name string) error { + verb, path := "DELETE", "/api/v1/kolide/packs/"+url.QueryEscape(name) + response, err := c.Do(verb, path, nil) + if err != nil { + return errors.Wrapf(err, "%s %s", verb, path) + } + defer response.Body.Close() + + if response.StatusCode != http.StatusOK { + return errors.Errorf("get pack spec got HTTP %d, expected 200", response.StatusCode) + } + + var responseBody deletePackResponse + err = json.NewDecoder(response.Body).Decode(&responseBody) + if err != nil { + return errors.Wrap(err, "decode get pack spec response") + } + + if responseBody.Err != nil { + return errors.Errorf("get pack spec: %s", responseBody.Err) + } + + return nil +} diff --git a/server/service/client_queries.go b/server/service/client_queries.go new file mode 100644 index 0000000000..b71fe86124 --- /dev/null +++ b/server/service/client_queries.go @@ -0,0 +1,89 @@ +package service + +import ( + "encoding/json" + "net/http" + "net/url" + + "github.com/kolide/fleet/server/kolide" + "github.com/pkg/errors" +) + +// ApplyQuerySpecs sends the list of Queries to be applied (upserted) to the +// Fleet instance. +func (c *Client) ApplyQuerySpecs(specs []*kolide.QuerySpec) error { + req := applyQuerySpecsRequest{Specs: specs} + response, err := c.Do("POST", "/api/v1/kolide/spec/queries", req) + if err != nil { + return errors.Wrap(err, "POST /api/v1/kolide/spec/queries") + } + defer response.Body.Close() + + if response.StatusCode != http.StatusOK { + return errors.Errorf("apply query spec got HTTP %d, expected 200", response.StatusCode) + } + + var responseBody applyQuerySpecsResponse + err = json.NewDecoder(response.Body).Decode(&responseBody) + if err != nil { + return errors.Wrap(err, "decode apply query spec response") + } + + if responseBody.Err != nil { + return errors.Errorf("apply query spec: %s", responseBody.Err) + } + + return nil +} + +// GetQuerySpecs retrieves the list of all Queries. +func (c *Client) GetQuerySpecs(specs []*kolide.QuerySpec) ([]*kolide.QuerySpec, error) { + req := applyQuerySpecsRequest{Specs: specs} + response, err := c.Do("GET", "/api/v1/kolide/spec/queries", req) + if err != nil { + return nil, errors.Wrap(err, "GET /api/v1/kolide/spec/queries") + } + defer response.Body.Close() + + if response.StatusCode != http.StatusOK { + return nil, errors.Errorf("get query spec got HTTP %d, expected 200", response.StatusCode) + } + + var responseBody getQuerySpecsResponse + err = json.NewDecoder(response.Body).Decode(&responseBody) + if err != nil { + return nil, errors.Wrap(err, "decode get query spec response") + } + + if responseBody.Err != nil { + return nil, errors.Errorf("get query spec: %s", responseBody.Err) + } + + return responseBody.Specs, nil +} + +// DeleteQuery deletes the query with the matching name. +func (c *Client) DeleteQuery(name string) error { + verb, path := "DELETE", "/api/v1/kolide/queries/"+url.QueryEscape(name) + response, err := c.Do(verb, path, nil) + if err != nil { + return errors.Wrapf(err, "%s %s", verb, path) + } + defer response.Body.Close() + + if response.StatusCode != http.StatusOK { + return errors.Errorf("get query spec got HTTP %d, expected 200", response.StatusCode) + } + + var responseBody deleteQueryResponse + err = json.NewDecoder(response.Body).Decode(&responseBody) + if err != nil { + return errors.Wrap(err, "decode get query spec response") + } + + if responseBody.Err != nil { + return errors.Errorf("get query spec: %s", responseBody.Err) + } + + return nil +} diff --git a/server/service/handler.go b/server/service/handler.go index 6880f163ae..c2b0f42e5f 100644 --- a/server/service/handler.go +++ b/server/service/handler.go @@ -388,22 +388,22 @@ func attachKolideAPIRoutes(r *mux.Router, h *kolideHandlers) { r.Handle("/api/v1/kolide/queries/{id}", h.ModifyQuery).Methods("PATCH").Name("modify_query") r.Handle("/api/v1/kolide/queries/{name}", h.DeleteQuery).Methods("DELETE").Name("delete_query") r.Handle("/api/v1/kolide/queries/delete", h.DeleteQueries).Methods("POST").Name("delete_queries") - r.Handle("/api/v1/kolide/queries/spec", h.ApplyQuerySpecs).Methods("POST").Name("apply_query_specs") - r.Handle("/api/v1/kolide/queries/spec", h.GetQuerySpecs).Methods("GET").Name("get_query_specs") + r.Handle("/api/v1/kolide/spec/queries", h.ApplyQuerySpecs).Methods("POST").Name("apply_query_specs") + r.Handle("/api/v1/kolide/spec/queries", h.GetQuerySpecs).Methods("GET").Name("get_query_specs") r.Handle("/api/v1/kolide/queries/run", h.CreateDistributedQueryCampaign).Methods("POST").Name("create_distributed_query_campaign") r.Handle("/api/v1/kolide/packs/{id}", h.GetPack).Methods("GET").Name("get_pack") r.Handle("/api/v1/kolide/packs", h.ListPacks).Methods("GET").Name("list_packs") r.Handle("/api/v1/kolide/packs/{name}", h.DeletePack).Methods("DELETE").Name("delete_pack") r.Handle("/api/v1/kolide/packs/{id}/scheduled", h.GetScheduledQueriesInPack).Methods("GET").Name("get_scheduled_queries_in_pack") - r.Handle("/api/v1/kolide/packs/spec", h.ApplyPackSpecs).Methods("POST").Name("apply_pack_specs") - r.Handle("/api/v1/kolide/packs/spec", h.GetPackSpecs).Methods("GET").Name("get_pack_specs") + r.Handle("/api/v1/kolide/spec/packs", h.ApplyPackSpecs).Methods("POST").Name("apply_pack_specs") + r.Handle("/api/v1/kolide/spec/packs", h.GetPackSpecs).Methods("GET").Name("get_pack_specs") r.Handle("/api/v1/kolide/labels/{id}", h.GetLabel).Methods("GET").Name("get_label") r.Handle("/api/v1/kolide/labels", h.ListLabels).Methods("GET").Name("list_labels") r.Handle("/api/v1/kolide/labels/{name}", h.DeleteLabel).Methods("DELETE").Name("delete_label") - r.Handle("/api/v1/kolide/labels/spec", h.ApplyLabelSpecs).Methods("POST").Name("apply_label_specs") - r.Handle("/api/v1/kolide/labels/spec", h.GetLabelSpecs).Methods("GET").Name("get_label_specs") + r.Handle("/api/v1/kolide/spec/labels", h.ApplyLabelSpecs).Methods("POST").Name("apply_label_specs") + r.Handle("/api/v1/kolide/spec/labels", h.GetLabelSpecs).Methods("GET").Name("get_label_specs") r.Handle("/api/v1/kolide/hosts", h.ListHosts).Methods("GET").Name("list_hosts") r.Handle("/api/v1/kolide/host_summary", h.GetHostSummary).Methods("GET").Name("get_host_summary")