diff --git a/kibana/fleet.go b/kibana/fleet.go index 2c1684b7..e2068815 100644 --- a/kibana/fleet.go +++ b/kibana/fleet.go @@ -45,6 +45,7 @@ const ( fleetUninstallTokensAPI = "/api/fleet/uninstall_tokens" //nolint:gosec // NOT the "Potential hardcoded credentials" fleetUpgradeAgentAPI = "/api/fleet/agents/%s/upgrade" fleetAgentDownloadSourcesAPI = "/api/fleet/agent_download_sources" + fleetAgentDownloadSourceAPI = "/api/fleet/agent_download_sources/%s" fleetProxiesAPI = "/api/fleet/proxies" ) @@ -204,6 +205,51 @@ func (client *Client) CreateDownloadSource(ctx context.Context, source DownloadS return body, nil } +func (client *Client) UpdateDownloadSource(ctx context.Context, id string, source DownloadSource) (DownloadSourceResponse, error) { + reqBody, err := json.Marshal(source) + if err != nil { + return DownloadSourceResponse{}, + fmt.Errorf("unable to marshal DownloadSource into JSON: %w", err) + } + + resp, err := client.SendWithContext( + ctx, + http.MethodPut, + fmt.Sprintf(fleetAgentDownloadSourceAPI, id), + nil, + nil, + bytes.NewReader(reqBody)) + if err != nil { + return DownloadSourceResponse{}, + fmt.Errorf("error calling Agent Binary Download Source API: %w", err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + var respBody string + if bs, err := io.ReadAll(resp.Body); err != nil { + respBody = "could not read response body" + } else { + respBody = string(bs) + } + + client.log.Errorw( + "could not update download source, kibana returned "+resp.Status, + "http.response.body.content", respBody) + return DownloadSourceResponse{}, + fmt.Errorf("could not update download source, kibana returned %s. response body: %s: %w", + resp.Status, respBody, err) + } + + body := DownloadSourceResponse{} + if err = json.NewDecoder(resp.Body).Decode(&body); err != nil { + return DownloadSourceResponse{}, + fmt.Errorf("failed parsing download source response: %w", err) + } + + return body, nil +} + // GetPolicy returns the policy with 'policy_id' id. func (client *Client) GetPolicy(ctx context.Context, id string) (r PolicyResponse, err error) { apiURL := fmt.Sprintf(fleetAgentPolicyAPI, id) diff --git a/kibana/fleet_test.go b/kibana/fleet_test.go index 0b60bdfa..7f3745a5 100644 --- a/kibana/fleet_test.go +++ b/kibana/fleet_test.go @@ -54,6 +54,12 @@ var ( //go:embed testdata/fleet_get_fleet_server_host_response.json fleetGetFleetServerHostResponse []byte + + //go:embed testdata/fleet_create_download_source_response.json + fleetCreateDownloadSourceResponse []byte + + //go:embed testdata/fleet_update_download_source_response.json + fleetUpdateDownloadSourceResponse []byte ) func TestFleetCreatePolicy(t *testing.T) { @@ -385,6 +391,45 @@ func TestFleetGetFleetServerHost(t *testing.T) { require.True(t, resp.IsPreconfigured) } +func TestFleetDownloadSource(t *testing.T) { + id := "test-id" + name := "test-name" + handler := func(w http.ResponseWriter, r *http.Request) { + switch r.Method { + case http.MethodPost: + _, _ = w.Write(fleetCreateDownloadSourceResponse) + case http.MethodPut: + _, _ = w.Write(fleetUpdateDownloadSourceResponse) + default: + http.Error(w, "not implemented", http.StatusNotImplemented) + } + } + client, err := createTestServerAndClient(handler) + require.NoError(t, err) + require.NotNil(t, client) + + t.Run("create", func(t *testing.T) { + resp, err := client.CreateDownloadSource(t.Context(), DownloadSource{ + Name: name, + Host: "http://test.local", + }) + require.NoError(t, err) + require.Equal(t, id, resp.Item.ID) + require.Equal(t, name, resp.Item.Name) + require.NotEmpty(t, "http://test.local", resp.Item.Host) + }) + t.Run("update", func(t *testing.T) { + resp, err := client.UpdateDownloadSource(t.Context(), id, DownloadSource{ + Name: name, + Host: "http://newtest.local", + }) + require.NoError(t, err) + require.Equal(t, id, resp.Item.ID) + require.Equal(t, name, resp.Item.Name) + require.NotEmpty(t, "http://newtest.local", resp.Item.Host) + }) +} + func createTestServerAndClient(handler http.HandlerFunc) (*Client, error) { kibanaTS := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { switch r.URL.Path { diff --git a/kibana/testdata/fleet_create_download_source_response.json b/kibana/testdata/fleet_create_download_source_response.json new file mode 100644 index 00000000..19924161 --- /dev/null +++ b/kibana/testdata/fleet_create_download_source_response.json @@ -0,0 +1,8 @@ +{ + "item": { + "id": "test-id", + "name": "test-name", + "host": "http://test.local", + "is_default": false + } +} diff --git a/kibana/testdata/fleet_update_download_source_response.json b/kibana/testdata/fleet_update_download_source_response.json new file mode 100644 index 00000000..7305568a --- /dev/null +++ b/kibana/testdata/fleet_update_download_source_response.json @@ -0,0 +1,9 @@ +{ + "item": { + "id": "test-id", + "name": "test-name", + "host": "http://newtest.local", + "is_default": false + } +} +