diff --git a/internal/knowledge/datasources/plugins/openstack/limes/limes_api.go b/internal/knowledge/datasources/plugins/openstack/limes/limes_api.go index e24c74928..c5e8a7b79 100644 --- a/internal/knowledge/datasources/plugins/openstack/limes/limes_api.go +++ b/internal/knowledge/datasources/plugins/openstack/limes/limes_api.go @@ -136,6 +136,14 @@ func (api *limesAPI) getCommitments(ctx context.Context, project identity.Projec return nil, err } defer resp.Body.Close() + + // This can happen if a project was deleted after we fetched the list of projects but before we fetched the commitments for the project. + // In this case, we can simply ignore the error and return an empty list of commitments for the project. + if resp.StatusCode == http.StatusNotFound { + slog.Warn("limes returned 404 for project, skipping", "projectID", project.ID, "domainID", project.DomainID) + return []Commitment{}, nil + } + if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("unexpected status code: %d", resp.StatusCode) } diff --git a/internal/knowledge/datasources/plugins/openstack/limes/limes_api_test.go b/internal/knowledge/datasources/plugins/openstack/limes/limes_api_test.go index d7e5be069..ec5eacc44 100644 --- a/internal/knowledge/datasources/plugins/openstack/limes/limes_api_test.go +++ b/internal/knowledge/datasources/plugins/openstack/limes/limes_api_test.go @@ -146,6 +146,15 @@ func TestLimesAPI_GetAllCommitments_MultipleProjects(t *testing.T) { } }) + handler.HandleFunc("/v1/domains/domain1/projects/project-deleted/commitments", func(w http.ResponseWriter, r *http.Request) { + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusNotFound) + _, err := w.Write([]byte(`{"error": "project not found"}`)) + if err != nil { + t.Fatalf("failed to write response: %v", err) + } + }) + server := httptest.NewServer(handler) defer server.Close() @@ -162,6 +171,8 @@ func TestLimesAPI_GetAllCommitments_MultipleProjects(t *testing.T) { projects := []identity.Project{ {ID: "project1", DomainID: "domain1"}, {ID: "project2", DomainID: "domain1"}, + // Returns a 404, should be handled gracefully and not cause the entire API call to fail. + {ID: "project-deleted", DomainID: "domain1"}, } commitments, err := api.GetAllCommitments(ctx, projects) if err != nil {