diff --git a/agent/consul/state/intention.go b/agent/consul/state/intention.go index ba3871ea56..b737318ee7 100644 --- a/agent/consul/state/intention.go +++ b/agent/consul/state/intention.go @@ -125,6 +125,12 @@ func (s *Store) intentionSetTxn(tx *memdb.Txn, idx uint64, ixn *structs.Intentio } ixn.ModifyIndex = idx + // We always force meta to be non-nil so that we its an empty map. + // This makes it easy for API responses to not nil-check this everywhere. + if ixn.Meta == nil { + ixn.Meta = make(map[string]string) + } + // Insert if err := tx.Insert(intentionsTableName, ixn); err != nil { return err diff --git a/agent/consul/state/intention_test.go b/agent/consul/state/intention_test.go index 1bfb6d248e..dd7d9fcdf3 100644 --- a/agent/consul/state/intention_test.go +++ b/agent/consul/state/intention_test.go @@ -154,6 +154,53 @@ func TestStore_IntentionSet_updateCreatedAt(t *testing.T) { } } +func TestStore_IntentionSet_metaNil(t *testing.T) { + s := testStateStore(t) + + // Build a valid intention + ixn := structs.Intention{ + ID: testUUID(), + } + + // Insert + if err := s.IntentionSet(1, &ixn); err != nil { + t.Fatalf("err: %s", err) + } + + // Read it back and verify + _, actual, err := s.IntentionGet(nil, ixn.ID) + if err != nil { + t.Fatalf("err: %s", err) + } + if actual.Meta == nil { + t.Fatal("meta should be non-nil") + } +} + +func TestStore_IntentionSet_metaSet(t *testing.T) { + s := testStateStore(t) + + // Build a valid intention + ixn := structs.Intention{ + ID: testUUID(), + Meta: map[string]string{"foo": "bar"}, + } + + // Insert + if err := s.IntentionSet(1, &ixn); err != nil { + t.Fatalf("err: %s", err) + } + + // Read it back and verify + _, actual, err := s.IntentionGet(nil, ixn.ID) + if err != nil { + t.Fatalf("err: %s", err) + } + if !reflect.DeepEqual(actual.Meta, ixn.Meta) { + t.Fatalf("bad: %#v", actual) + } +} + func TestStore_IntentionDelete(t *testing.T) { s := testStateStore(t) diff --git a/agent/structs/intention.go b/agent/structs/intention.go index b60c366255..0a7d8c5d4a 100644 --- a/agent/structs/intention.go +++ b/agent/structs/intention.go @@ -23,6 +23,11 @@ type Intention struct { // ID is the UUID-based ID for the intention, always generated by Consul. ID string + // Description is a human-friendly description of this intention. + // It is opaque to Consul and is only stored and transferred in API + // requests. + Description string + // SourceNS, SourceName are the namespace and name, respectively, of // the source service. Either of these may be the wildcard "*", but only // the full value can be a wildcard. Partial wildcards are not allowed.