diff --git a/agent/consul/intention_endpoint.go b/agent/consul/intention_endpoint.go index 118dfb5b92..fc552afd98 100644 --- a/agent/consul/intention_endpoint.go +++ b/agent/consul/intention_endpoint.go @@ -37,7 +37,11 @@ func (s *Intention) Apply( // appending to the Raft log, because the ID is not deterministic. Once // the entry is in the log, the state update MUST be deterministic or // the followers will not converge. - if args.Op == structs.IntentionOpCreate && args.Intention.ID == "" { + if args.Op == structs.IntentionOpCreate { + if args.Intention.ID != "" { + return fmt.Errorf("ID must be empty when creating a new intention") + } + state := s.srv.fsm.State() for { var err error diff --git a/agent/consul/intention_endpoint_test.go b/agent/consul/intention_endpoint_test.go index 6049c5f355..e0b4762de4 100644 --- a/agent/consul/intention_endpoint_test.go +++ b/agent/consul/intention_endpoint_test.go @@ -65,6 +65,35 @@ func TestIntentionApply_new(t *testing.T) { } } +// Shouldn't be able to create with an ID set +func TestIntentionApply_createWithID(t *testing.T) { + t.Parallel() + dir1, s1 := testServer(t) + defer os.RemoveAll(dir1) + defer s1.Shutdown() + codec := rpcClient(t, s1) + defer codec.Close() + + testrpc.WaitForLeader(t, s1.RPC, "dc1") + + // Setup a basic record to create + ixn := structs.IntentionRequest{ + Datacenter: "dc1", + Op: structs.IntentionOpCreate, + Intention: &structs.Intention{ + ID: generateUUID(), + SourceName: "test", + }, + } + var reply string + + // Create + err := msgpackrpc.CallWithCodec(codec, "Intention.Apply", &ixn, &reply) + if err == nil || !strings.Contains(err.Error(), "ID must be empty") { + t.Fatalf("bad: %v", err) + } +} + // Test basic updating func TestIntentionApply_updateGood(t *testing.T) { t.Parallel()