diff --git a/.changelog/9278.txt b/.changelog/9278.txt new file mode 100644 index 000000000..3d6440275 --- /dev/null +++ b/.changelog/9278.txt @@ -0,0 +1,3 @@ +```release-note:improvement +server: deletions of intentions by name using the intention API is now idempotent +``` diff --git a/agent/consul/intention_endpoint.go b/agent/consul/intention_endpoint.go index 199825586..b35167a18 100644 --- a/agent/consul/intention_endpoint.go +++ b/agent/consul/intention_endpoint.go @@ -413,9 +413,7 @@ func (s *Intention) computeApplyChangesDelete( return nil, fmt.Errorf("Intention lookup failed: %v", err) } if ixn == nil { - src := structs.NewServiceName(exactIxn.SourceName, exactIxn.SourceEnterpriseMeta()) - dst := structs.NewServiceName(exactIxn.DestinationName, exactIxn.DestinationEnterpriseMeta()) - return nil, fmt.Errorf("Cannot delete non-existent intention: source=%q, destination=%q", src.String(), dst.String()) + return nil, nil // by-name deletions are idempotent } return &structs.IntentionMutation{ diff --git a/agent/consul/intention_endpoint_test.go b/agent/consul/intention_endpoint_test.go index 6e80865c0..669ae1d65 100644 --- a/agent/consul/intention_endpoint_test.go +++ b/agent/consul/intention_endpoint_test.go @@ -653,14 +653,14 @@ func TestIntentionApply_WithoutIDs(t *testing.T) { require.Equal(t, expect, entry) } - // Delete a non existent intention should return an error - testutil.RequireErrorContains(t, opApply(&structs.IntentionRequest{ + // Delete a non existent intention should act like it did work + require.NoError(t, opApply(&structs.IntentionRequest{ Op: structs.IntentionOpDelete, Intention: &structs.Intention{ SourceName: "ghost", DestinationName: "phantom", }, - }), "Cannot delete non-existent intention") + })) // Delete the original require.NoError(t, opApply(&structs.IntentionRequest{ diff --git a/agent/intentions_endpoint_test.go b/agent/intentions_endpoint_test.go index eceadbf9f..68f44d6bc 100644 --- a/agent/intentions_endpoint_test.go +++ b/agent/intentions_endpoint_test.go @@ -554,8 +554,8 @@ func TestIntentionDeleteExact(t *testing.T) { resp := httptest.NewRecorder() obj, err := a.srv.IntentionExact(resp, req) - require.Nil(t, obj) - testutil.RequireErrorContains(t, err, "Cannot delete non-existent intention") + require.NoError(t, err) // by-name deletions are idempotent + require.Equal(t, true, obj) }) exact := ixn.ToExact() @@ -643,6 +643,18 @@ func TestIntentionSpecificDelete(t *testing.T) { ixn := structs.TestIntention(t) ixn.SourceName = "foo" + t.Run("cannot delete non-existent intention", func(t *testing.T) { + fakeID := generateUUID() + + req, err := http.NewRequest("DELETE", "/v1/connect/intentions/"+fakeID, nil) + require.NoError(t, err) + + resp := httptest.NewRecorder() + obj, err := a.srv.IntentionSpecific(resp, req) + testutil.RequireErrorContains(t, err, "Cannot delete non-existent intention") + require.Nil(t, obj) + }) + // Create an intention directly var reply string {