diff --git a/.changelog/8596.txt b/.changelog/8596.txt new file mode 100644 index 0000000000..0c96f0c7d9 --- /dev/null +++ b/.changelog/8596.txt @@ -0,0 +1,3 @@ +```release-note:feature +connect: all config entries pick up a meta field +``` diff --git a/agent/config/runtime_test.go b/agent/config/runtime_test.go index adbc269e68..906724ac6e 100644 --- a/agent/config/runtime_test.go +++ b/agent/config/runtime_test.go @@ -3436,6 +3436,10 @@ func TestBuilder_BuildAndValide_ConfigFlagsAndEdgecases(t *testing.T) { { "kind": "service-defaults", "name": "web", + "meta" : { + "foo": "bar", + "gir": "zim" + }, "protocol": "http", "external_sni": "abc-123", "mesh_gateway": { @@ -3450,6 +3454,10 @@ func TestBuilder_BuildAndValide_ConfigFlagsAndEdgecases(t *testing.T) { bootstrap { kind = "service-defaults" name = "web" + meta { + "foo" = "bar" + "gir" = "zim" + } protocol = "http" external_sni = "abc-123" mesh_gateway { @@ -3461,8 +3469,12 @@ func TestBuilder_BuildAndValide_ConfigFlagsAndEdgecases(t *testing.T) { rt.DataDir = dataDir rt.ConfigEntryBootstrap = []structs.ConfigEntry{ &structs.ServiceConfigEntry{ - Kind: structs.ServiceDefaults, - Name: "web", + Kind: structs.ServiceDefaults, + Name: "web", + Meta: map[string]string{ + "foo": "bar", + "gir": "zim", + }, EnterpriseMeta: *defaultEntMeta, Protocol: "http", ExternalSNI: "abc-123", @@ -3482,6 +3494,10 @@ func TestBuilder_BuildAndValide_ConfigFlagsAndEdgecases(t *testing.T) { { "Kind": "service-defaults", "Name": "web", + "Meta" : { + "foo": "bar", + "gir": "zim" + }, "Protocol": "http", "ExternalSNI": "abc-123", "MeshGateway": { @@ -3496,6 +3512,10 @@ func TestBuilder_BuildAndValide_ConfigFlagsAndEdgecases(t *testing.T) { bootstrap { Kind = "service-defaults" Name = "web" + Meta { + "foo" = "bar" + "gir" = "zim" + } Protocol = "http" ExternalSNI = "abc-123" MeshGateway { @@ -3507,8 +3527,12 @@ func TestBuilder_BuildAndValide_ConfigFlagsAndEdgecases(t *testing.T) { rt.DataDir = dataDir rt.ConfigEntryBootstrap = []structs.ConfigEntry{ &structs.ServiceConfigEntry{ - Kind: structs.ServiceDefaults, - Name: "web", + Kind: structs.ServiceDefaults, + Name: "web", + Meta: map[string]string{ + "foo": "bar", + "gir": "zim", + }, EnterpriseMeta: *defaultEntMeta, Protocol: "http", ExternalSNI: "abc-123", @@ -3528,6 +3552,10 @@ func TestBuilder_BuildAndValide_ConfigFlagsAndEdgecases(t *testing.T) { { "kind": "service-router", "name": "main", + "meta" : { + "foo": "bar", + "gir": "zim" + }, "routes": [ { "match": { @@ -3612,6 +3640,10 @@ func TestBuilder_BuildAndValide_ConfigFlagsAndEdgecases(t *testing.T) { bootstrap { kind = "service-router" name = "main" + meta { + "foo" = "bar" + "gir" = "zim" + } routes = [ { match { @@ -3693,8 +3725,12 @@ func TestBuilder_BuildAndValide_ConfigFlagsAndEdgecases(t *testing.T) { rt.DataDir = dataDir rt.ConfigEntryBootstrap = []structs.ConfigEntry{ &structs.ServiceRouterConfigEntry{ - Kind: structs.ServiceRouter, - Name: "main", + Kind: structs.ServiceRouter, + Name: "main", + Meta: map[string]string{ + "foo": "bar", + "gir": "zim", + }, EnterpriseMeta: *defaultEntMeta, Routes: []structs.ServiceRoute{ { diff --git a/agent/structs/config_entry.go b/agent/structs/config_entry.go index 4cafb9b292..b1ffd3e0d6 100644 --- a/agent/structs/config_entry.go +++ b/agent/structs/config_entry.go @@ -10,6 +10,7 @@ import ( "github.com/hashicorp/consul/lib" "github.com/hashicorp/consul/lib/decode" "github.com/hashicorp/go-msgpack/codec" + "github.com/hashicorp/go-multierror" "github.com/mitchellh/hashstructure" "github.com/mitchellh/mapstructure" ) @@ -43,6 +44,7 @@ type ConfigEntry interface { CanRead(acl.Authorizer) bool CanWrite(acl.Authorizer) bool + GetMeta() map[string]string GetEnterpriseMeta() *EnterpriseMeta GetRaftIndex() *RaftIndex } @@ -64,6 +66,7 @@ type ServiceConfigEntry struct { // // Connect ConnectConfiguration + Meta map[string]string `json:",omitempty"` EnterpriseMeta `hcl:",squash" mapstructure:",squash"` RaftIndex } @@ -80,6 +83,13 @@ func (e *ServiceConfigEntry) GetName() string { return e.Name } +func (e *ServiceConfigEntry) GetMeta() map[string]string { + if e == nil { + return nil + } + return e.Meta +} + func (e *ServiceConfigEntry) Normalize() error { if e == nil { return fmt.Errorf("config entry is nil") @@ -94,7 +104,7 @@ func (e *ServiceConfigEntry) Normalize() error { } func (e *ServiceConfigEntry) Validate() error { - return nil + return validateConfigEntryMeta(e.Meta) } func (e *ServiceConfigEntry) CanRead(authz acl.Authorizer) bool { @@ -137,6 +147,7 @@ type ProxyConfigEntry struct { MeshGateway MeshGatewayConfig `json:",omitempty" alias:"mesh_gateway"` Expose ExposeConfig `json:",omitempty"` + Meta map[string]string `json:",omitempty"` EnterpriseMeta `hcl:",squash" mapstructure:",squash"` RaftIndex } @@ -153,6 +164,13 @@ func (e *ProxyConfigEntry) GetName() string { return e.Name } +func (e *ProxyConfigEntry) GetMeta() map[string]string { + if e == nil { + return nil + } + return e.Meta +} + func (e *ProxyConfigEntry) Normalize() error { if e == nil { return fmt.Errorf("config entry is nil") @@ -175,6 +193,10 @@ func (e *ProxyConfigEntry) Validate() error { return fmt.Errorf("invalid name (%q), only %q is supported", e.Name, ProxyConfigGlobal) } + if err := validateConfigEntryMeta(e.Meta); err != nil { + return err + } + return e.validateEnterpriseMeta() } @@ -682,3 +704,22 @@ func NewConfigEntryKindName(kind, name string, entMeta *EnterpriseMeta) ConfigEn ret.EnterpriseMeta.Normalize() return ret } + +func validateConfigEntryMeta(meta map[string]string) error { + var err error + if len(meta) > metaMaxKeyPairs { + err = multierror.Append(err, fmt.Errorf( + "Meta exceeds maximum element count %d", metaMaxKeyPairs)) + } + for k, v := range meta { + if len(k) > metaKeyMaxLength { + err = multierror.Append(err, fmt.Errorf( + "Meta key %q exceeds maximum length %d", k, metaKeyMaxLength)) + } + if len(v) > metaValueMaxLength { + err = multierror.Append(err, fmt.Errorf( + "Meta value for key %q exceeds maximum length %d", k, metaValueMaxLength)) + } + } + return err +} diff --git a/agent/structs/config_entry_discoverychain.go b/agent/structs/config_entry_discoverychain.go index 04cf32353a..57d0a69fe5 100644 --- a/agent/structs/config_entry_discoverychain.go +++ b/agent/structs/config_entry_discoverychain.go @@ -38,6 +38,7 @@ type ServiceRouterConfigEntry struct { // the default service. Routes []ServiceRoute + Meta map[string]string `json:",omitempty"` EnterpriseMeta `hcl:",squash" mapstructure:",squash"` RaftIndex } @@ -54,6 +55,13 @@ func (e *ServiceRouterConfigEntry) GetName() string { return e.Name } +func (e *ServiceRouterConfigEntry) GetMeta() map[string]string { + if e == nil { + return nil + } + return e.Meta +} + func (e *ServiceRouterConfigEntry) Normalize() error { if e == nil { return fmt.Errorf("config entry is nil") @@ -89,6 +97,10 @@ func (e *ServiceRouterConfigEntry) Validate() error { return fmt.Errorf("Name is required") } + if err := validateConfigEntryMeta(e.Meta); err != nil { + return err + } + // Technically you can have no explicit routes at all where just the // catch-all is configured for you, but at that point maybe you should just // delete it so it will default? @@ -407,6 +419,7 @@ type ServiceSplitterConfigEntry struct { // to the FIRST split. Splits []ServiceSplit + Meta map[string]string `json:",omitempty"` EnterpriseMeta `hcl:",squash" mapstructure:",squash"` RaftIndex } @@ -423,6 +436,13 @@ func (e *ServiceSplitterConfigEntry) GetName() string { return e.Name } +func (e *ServiceSplitterConfigEntry) GetMeta() map[string]string { + if e == nil { + return nil + } + return e.Meta +} + func (e *ServiceSplitterConfigEntry) Normalize() error { if e == nil { return fmt.Errorf("config entry is nil") @@ -461,6 +481,10 @@ func (e *ServiceSplitterConfigEntry) Validate() error { return fmt.Errorf("no splits configured") } + if err := validateConfigEntryMeta(e.Meta); err != nil { + return err + } + const maxScaledWeight = 100 * 100 copyAsKey := func(s ServiceSplit) ServiceSplit { @@ -639,6 +663,7 @@ type ServiceResolverConfigEntry struct { // to this service. ConnectTimeout time.Duration `json:",omitempty" alias:"connect_timeout"` + Meta map[string]string `json:",omitempty"` EnterpriseMeta `hcl:",squash" mapstructure:",squash"` RaftIndex } @@ -710,6 +735,13 @@ func (e *ServiceResolverConfigEntry) GetName() string { return e.Name } +func (e *ServiceResolverConfigEntry) GetMeta() map[string]string { + if e == nil { + return nil + } + return e.Meta +} + func (e *ServiceResolverConfigEntry) Normalize() error { if e == nil { return fmt.Errorf("config entry is nil") @@ -727,6 +759,10 @@ func (e *ServiceResolverConfigEntry) Validate() error { return fmt.Errorf("Name is required") } + if err := validateConfigEntryMeta(e.Meta); err != nil { + return err + } + if len(e.Subsets) > 0 { for name := range e.Subsets { if name == "" { diff --git a/agent/structs/config_entry_gateways.go b/agent/structs/config_entry_gateways.go index a5557dbafa..61b9930823 100644 --- a/agent/structs/config_entry_gateways.go +++ b/agent/structs/config_entry_gateways.go @@ -27,6 +27,7 @@ type IngressGatewayConfigEntry struct { // what services to associated to those ports. Listeners []IngressListener + Meta map[string]string `json:",omitempty"` EnterpriseMeta `hcl:",squash" mapstructure:",squash"` RaftIndex } @@ -73,6 +74,7 @@ type IngressService struct { // using a "tcp" listener. Hosts []string + Meta map[string]string `json:",omitempty"` EnterpriseMeta `hcl:",squash" mapstructure:",squash"` } @@ -93,6 +95,13 @@ func (e *IngressGatewayConfigEntry) GetName() string { return e.Name } +func (e *IngressGatewayConfigEntry) GetMeta() map[string]string { + if e == nil { + return nil + } + return e.Meta +} + func (e *IngressGatewayConfigEntry) Normalize() error { if e == nil { return fmt.Errorf("config entry is nil") @@ -121,6 +130,10 @@ func (e *IngressGatewayConfigEntry) Normalize() error { } func (e *IngressGatewayConfigEntry) Validate() error { + if err := validateConfigEntryMeta(e.Meta); err != nil { + return err + } + validProtocols := map[string]bool{ "tcp": true, "http": true, @@ -283,6 +296,7 @@ type TerminatingGatewayConfigEntry struct { Name string Services []LinkedService + Meta map[string]string `json:",omitempty"` EnterpriseMeta `hcl:",squash" mapstructure:",squash"` RaftIndex } @@ -322,6 +336,13 @@ func (e *TerminatingGatewayConfigEntry) GetName() string { return e.Name } +func (e *TerminatingGatewayConfigEntry) GetMeta() map[string]string { + if e == nil { + return nil + } + return e.Meta +} + func (e *TerminatingGatewayConfigEntry) Normalize() error { if e == nil { return fmt.Errorf("config entry is nil") @@ -339,6 +360,10 @@ func (e *TerminatingGatewayConfigEntry) Normalize() error { } func (e *TerminatingGatewayConfigEntry) Validate() error { + if err := validateConfigEntryMeta(e.Meta); err != nil { + return err + } + seen := make(map[ServiceID]bool) for _, svc := range e.Services { diff --git a/agent/structs/config_entry_test.go b/agent/structs/config_entry_test.go index 34ccfbaf46..d855529f4f 100644 --- a/agent/structs/config_entry_test.go +++ b/agent/structs/config_entry_test.go @@ -46,6 +46,10 @@ func TestDecodeConfigEntry(t *testing.T) { snake: ` kind = "proxy-defaults" name = "main" + meta { + "foo" = "bar" + "gir" = "zim" + } config { "foo" = 19 "bar" = "abc" @@ -60,6 +64,10 @@ func TestDecodeConfigEntry(t *testing.T) { camel: ` Kind = "proxy-defaults" Name = "main" + Meta { + "foo" = "bar" + "gir" = "zim" + } Config { "foo" = 19 "bar" = "abc" @@ -74,6 +82,10 @@ func TestDecodeConfigEntry(t *testing.T) { expect: &ProxyConfigEntry{ Kind: "proxy-defaults", Name: "main", + Meta: map[string]string{ + "foo": "bar", + "gir": "zim", + }, Config: map[string]interface{}{ "foo": 19, "bar": "abc", @@ -91,6 +103,10 @@ func TestDecodeConfigEntry(t *testing.T) { snake: ` kind = "service-defaults" name = "main" + meta { + "foo" = "bar" + "gir" = "zim" + } protocol = "http" external_sni = "abc-123" mesh_gateway { @@ -100,6 +116,10 @@ func TestDecodeConfigEntry(t *testing.T) { camel: ` Kind = "service-defaults" Name = "main" + Meta { + "foo" = "bar" + "gir" = "zim" + } Protocol = "http" ExternalSNI = "abc-123" MeshGateway { @@ -107,8 +127,12 @@ func TestDecodeConfigEntry(t *testing.T) { } `, expect: &ServiceConfigEntry{ - Kind: "service-defaults", - Name: "main", + Kind: "service-defaults", + Name: "main", + Meta: map[string]string{ + "foo": "bar", + "gir": "zim", + }, Protocol: "http", ExternalSNI: "abc-123", MeshGateway: MeshGatewayConfig{ @@ -121,6 +145,10 @@ func TestDecodeConfigEntry(t *testing.T) { snake: ` kind = "service-router" name = "main" + meta { + "foo" = "bar" + "gir" = "zim" + } routes = [ { match { @@ -200,6 +228,10 @@ func TestDecodeConfigEntry(t *testing.T) { camel: ` Kind = "service-router" Name = "main" + Meta { + "foo" = "bar" + "gir" = "zim" + } Routes = [ { Match { @@ -279,6 +311,10 @@ func TestDecodeConfigEntry(t *testing.T) { expect: &ServiceRouterConfigEntry{ Kind: "service-router", Name: "main", + Meta: map[string]string{ + "foo": "bar", + "gir": "zim", + }, Routes: []ServiceRoute{ { Match: &ServiceRouteMatch{ @@ -361,6 +397,10 @@ func TestDecodeConfigEntry(t *testing.T) { snake: ` kind = "service-splitter" name = "main" + meta { + "foo" = "bar" + "gir" = "zim" + } splits = [ { weight = 99.1 @@ -376,6 +416,10 @@ func TestDecodeConfigEntry(t *testing.T) { camel: ` Kind = "service-splitter" Name = "main" + Meta { + "foo" = "bar" + "gir" = "zim" + } Splits = [ { Weight = 99.1 @@ -391,6 +435,10 @@ func TestDecodeConfigEntry(t *testing.T) { expect: &ServiceSplitterConfigEntry{ Kind: ServiceSplitter, Name: "main", + Meta: map[string]string{ + "foo": "bar", + "gir": "zim", + }, Splits: []ServiceSplit{ { Weight: 99.1, @@ -409,6 +457,10 @@ func TestDecodeConfigEntry(t *testing.T) { snake: ` kind = "service-resolver" name = "main" + meta { + "foo" = "bar" + "gir" = "zim" + } default_subset = "v1" connect_timeout = "15s" subsets = { @@ -434,6 +486,10 @@ func TestDecodeConfigEntry(t *testing.T) { camel: ` Kind = "service-resolver" Name = "main" + Meta { + "foo" = "bar" + "gir" = "zim" + } DefaultSubset = "v1" ConnectTimeout = "15s" Subsets = { @@ -457,8 +513,12 @@ func TestDecodeConfigEntry(t *testing.T) { } }`, expect: &ServiceResolverConfigEntry{ - Kind: "service-resolver", - Name: "main", + Kind: "service-resolver", + Name: "main", + Meta: map[string]string{ + "foo": "bar", + "gir": "zim", + }, DefaultSubset: "v1", ConnectTimeout: 15 * time.Second, Subsets: map[string]ServiceResolverSubset{ @@ -536,6 +596,10 @@ func TestDecodeConfigEntry(t *testing.T) { snake: ` kind = "ingress-gateway" name = "ingress-web" + meta { + "foo" = "bar" + "gir" = "zim" + } tls { enabled = true @@ -578,6 +642,10 @@ func TestDecodeConfigEntry(t *testing.T) { camel: ` Kind = "ingress-gateway" Name = "ingress-web" + Meta { + "foo" = "bar" + "gir" = "zim" + } TLS { Enabled = true } @@ -618,6 +686,10 @@ func TestDecodeConfigEntry(t *testing.T) { expect: &IngressGatewayConfigEntry{ Kind: "ingress-gateway", Name: "ingress-web", + Meta: map[string]string{ + "foo": "bar", + "gir": "zim", + }, TLS: GatewayTLSConfig{ Enabled: true, }, @@ -661,6 +733,10 @@ func TestDecodeConfigEntry(t *testing.T) { snake: ` kind = "terminating-gateway" name = "terminating-gw-west" + meta { + "foo" = "bar" + "gir" = "zim" + } services = [ { name = "payments", @@ -681,6 +757,10 @@ func TestDecodeConfigEntry(t *testing.T) { camel: ` Kind = "terminating-gateway" Name = "terminating-gw-west" + Meta { + "foo" = "bar" + "gir" = "zim" + } Services = [ { Name = "payments", @@ -701,6 +781,10 @@ func TestDecodeConfigEntry(t *testing.T) { expect: &TerminatingGatewayConfigEntry{ Kind: "terminating-gateway", Name: "terminating-gw-west", + Meta: map[string]string{ + "foo": "bar", + "gir": "zim", + }, Services: []LinkedService{ { Name: "payments", diff --git a/api/config_entry.go b/api/config_entry.go index dc31d6110f..a234f6eb25 100644 --- a/api/config_entry.go +++ b/api/config_entry.go @@ -95,6 +95,7 @@ type ServiceConfigEntry struct { MeshGateway MeshGatewayConfig `json:",omitempty" alias:"mesh_gateway"` Expose ExposeConfig `json:",omitempty"` ExternalSNI string `json:",omitempty" alias:"external_sni"` + Meta map[string]string `json:",omitempty"` CreateIndex uint64 ModifyIndex uint64 } @@ -122,6 +123,7 @@ type ProxyConfigEntry struct { Config map[string]interface{} `json:",omitempty"` MeshGateway MeshGatewayConfig `json:",omitempty" alias:"mesh_gateway"` Expose ExposeConfig `json:",omitempty"` + Meta map[string]string `json:",omitempty"` CreateIndex uint64 ModifyIndex uint64 } diff --git a/api/config_entry_discoverychain.go b/api/config_entry_discoverychain.go index f3994f0dd9..209106339f 100644 --- a/api/config_entry_discoverychain.go +++ b/api/config_entry_discoverychain.go @@ -12,6 +12,7 @@ type ServiceRouterConfigEntry struct { Routes []ServiceRoute `json:",omitempty"` + Meta map[string]string `json:",omitempty"` CreateIndex uint64 ModifyIndex uint64 } @@ -111,6 +112,7 @@ type ServiceSplitterConfigEntry struct { Splits []ServiceSplit `json:",omitempty"` + Meta map[string]string `json:",omitempty"` CreateIndex uint64 ModifyIndex uint64 } @@ -138,6 +140,7 @@ type ServiceResolverConfigEntry struct { Failover map[string]ServiceResolverFailover `json:",omitempty"` ConnectTimeout time.Duration `json:",omitempty" alias:"connect_timeout"` + Meta map[string]string `json:",omitempty"` CreateIndex uint64 ModifyIndex uint64 } diff --git a/api/config_entry_gateways.go b/api/config_entry_gateways.go index 9d3ee0a6a9..e259427d86 100644 --- a/api/config_entry_gateways.go +++ b/api/config_entry_gateways.go @@ -21,6 +21,8 @@ type IngressGatewayConfigEntry struct { // what services to associated to those ports. Listeners []IngressListener + Meta map[string]string `json:",omitempty"` + // CreateIndex is the Raft index this entry was created at. This is a // read-only field. CreateIndex uint64 @@ -115,6 +117,8 @@ type TerminatingGatewayConfigEntry struct { // Services is a list of service names represented by the terminating gateway. Services []LinkedService `json:",omitempty"` + Meta map[string]string `json:",omitempty"` + // CreateIndex is the Raft index this entry was created at. This is a // read-only field. CreateIndex uint64 diff --git a/api/config_entry_test.go b/api/config_entry_test.go index aa384bb9f1..fac1665d36 100644 --- a/api/config_entry_test.go +++ b/api/config_entry_test.go @@ -271,6 +271,10 @@ func TestDecodeConfigEntry(t *testing.T) { { "Kind": "proxy-defaults", "Name": "main", + "Meta" : { + "foo": "bar", + "gir": "zim" + }, "Config": { "foo": 19, "bar": "abc", @@ -286,6 +290,10 @@ func TestDecodeConfigEntry(t *testing.T) { expect: &ProxyConfigEntry{ Kind: "proxy-defaults", Name: "main", + Meta: map[string]string{ + "foo": "bar", + "gir": "zim", + }, Config: map[string]interface{}{ "foo": float64(19), "bar": "abc", @@ -304,6 +312,10 @@ func TestDecodeConfigEntry(t *testing.T) { { "Kind": "service-defaults", "Name": "main", + "Meta" : { + "foo": "bar", + "gir": "zim" + }, "Protocol": "http", "ExternalSNI": "abc-123", "MeshGateway": { @@ -312,8 +324,12 @@ func TestDecodeConfigEntry(t *testing.T) { } `, expect: &ServiceConfigEntry{ - Kind: "service-defaults", - Name: "main", + Kind: "service-defaults", + Name: "main", + Meta: map[string]string{ + "foo": "bar", + "gir": "zim", + }, Protocol: "http", ExternalSNI: "abc-123", MeshGateway: MeshGatewayConfig{ @@ -327,6 +343,10 @@ func TestDecodeConfigEntry(t *testing.T) { { "Kind": "service-router", "Name": "main", + "Meta" : { + "foo": "bar", + "gir": "zim" + }, "Routes": [ { "Match": { @@ -407,6 +427,10 @@ func TestDecodeConfigEntry(t *testing.T) { expect: &ServiceRouterConfigEntry{ Kind: "service-router", Name: "main", + Meta: map[string]string{ + "foo": "bar", + "gir": "zim", + }, Routes: []ServiceRoute{ { Match: &ServiceRouteMatch{ @@ -490,6 +514,10 @@ func TestDecodeConfigEntry(t *testing.T) { { "Kind": "service-splitter", "Name": "main", + "Meta" : { + "foo": "bar", + "gir": "zim" + }, "Splits": [ { "Weight": 99.1, @@ -506,6 +534,10 @@ func TestDecodeConfigEntry(t *testing.T) { expect: &ServiceSplitterConfigEntry{ Kind: ServiceSplitter, Name: "main", + Meta: map[string]string{ + "foo": "bar", + "gir": "zim", + }, Splits: []ServiceSplit{ { Weight: 99.1, @@ -525,6 +557,10 @@ func TestDecodeConfigEntry(t *testing.T) { { "Kind": "service-resolver", "Name": "main", + "Meta" : { + "foo": "bar", + "gir": "zim" + }, "DefaultSubset": "v1", "ConnectTimeout": "15s", "Subsets": { @@ -549,8 +585,12 @@ func TestDecodeConfigEntry(t *testing.T) { } }`, expect: &ServiceResolverConfigEntry{ - Kind: "service-resolver", - Name: "main", + Kind: "service-resolver", + Name: "main", + Meta: map[string]string{ + "foo": "bar", + "gir": "zim", + }, DefaultSubset: "v1", ConnectTimeout: 15 * time.Second, Subsets: map[string]ServiceResolverSubset{ @@ -619,6 +659,10 @@ func TestDecodeConfigEntry(t *testing.T) { { "Kind": "ingress-gateway", "Name": "ingress-web", + "Meta" : { + "foo": "bar", + "gir": "zim" + }, "Tls": { "Enabled": true }, @@ -651,6 +695,10 @@ func TestDecodeConfigEntry(t *testing.T) { expect: &IngressGatewayConfigEntry{ Kind: "ingress-gateway", Name: "ingress-web", + Meta: map[string]string{ + "foo": "bar", + "gir": "zim", + }, TLS: GatewayTLSConfig{ Enabled: true, }, @@ -686,9 +734,13 @@ func TestDecodeConfigEntry(t *testing.T) { { "Kind": "terminating-gateway", "Name": "terminating-west", + "Meta" : { + "foo": "bar", + "gir": "zim" + }, "Services": [ { - "Namespace": "foo", + "Namespace": "foo", "Name": "web", "CAFile": "/etc/ca.pem", "CertFile": "/etc/cert.pem", @@ -707,6 +759,10 @@ func TestDecodeConfigEntry(t *testing.T) { expect: &TerminatingGatewayConfigEntry{ Kind: "terminating-gateway", Name: "terminating-west", + Meta: map[string]string{ + "foo": "bar", + "gir": "zim", + }, Services: []LinkedService{ { Namespace: "foo", diff --git a/command/config/write/config_write_test.go b/command/config/write/config_write_test.go index a5b9120b29..f11e907fde 100644 --- a/command/config/write/config_write_test.go +++ b/command/config/write/config_write_test.go @@ -161,6 +161,10 @@ func TestParseConfigEntry(t *testing.T) { snake: ` kind = "proxy-defaults" name = "main" + meta { + "foo" = "bar" + "gir" = "zim" + } config { "foo" = 19 "bar" = "abc" @@ -175,6 +179,10 @@ func TestParseConfigEntry(t *testing.T) { camel: ` Kind = "proxy-defaults" Name = "main" + Meta { + "foo" = "bar" + "gir" = "zim" + } Config { "foo" = 19 "bar" = "abc" @@ -190,6 +198,10 @@ func TestParseConfigEntry(t *testing.T) { { "kind": "proxy-defaults", "name": "main", + "meta" : { + "foo": "bar", + "gir": "zim" + }, "config": { "foo": 19, "bar": "abc", @@ -206,6 +218,10 @@ func TestParseConfigEntry(t *testing.T) { { "Kind": "proxy-defaults", "Name": "main", + "Meta" : { + "foo": "bar", + "gir": "zim" + }, "Config": { "foo": 19, "bar": "abc", @@ -221,6 +237,10 @@ func TestParseConfigEntry(t *testing.T) { expect: &api.ProxyConfigEntry{ Kind: "proxy-defaults", Name: "main", + Meta: map[string]string{ + "foo": "bar", + "gir": "zim", + }, Config: map[string]interface{}{ "foo": 19, "bar": "abc", @@ -235,6 +255,10 @@ func TestParseConfigEntry(t *testing.T) { expectJSON: &api.ProxyConfigEntry{ Kind: "proxy-defaults", Name: "main", + Meta: map[string]string{ + "foo": "bar", + "gir": "zim", + }, Config: map[string]interface{}{ "foo": float64(19), // json decoding gives float64 instead of int here "bar": "abc", @@ -253,6 +277,10 @@ func TestParseConfigEntry(t *testing.T) { kind = "terminating-gateway" name = "terminating-gw-west" namespace = "default" + meta { + "foo" = "bar" + "gir" = "zim" + } services = [ { name = "billing" @@ -272,6 +300,10 @@ func TestParseConfigEntry(t *testing.T) { Kind = "terminating-gateway" Name = "terminating-gw-west" Namespace = "default" + Meta { + "foo" = "bar" + "gir" = "zim" + } Services = [ { Name = "billing" @@ -292,6 +324,10 @@ func TestParseConfigEntry(t *testing.T) { "kind": "terminating-gateway", "name": "terminating-gw-west", "namespace": "default", + "meta" : { + "foo": "bar", + "gir": "zim" + }, "services": [ { "name": "billing", @@ -313,6 +349,10 @@ func TestParseConfigEntry(t *testing.T) { "Kind": "terminating-gateway", "Name": "terminating-gw-west", "Namespace": "default", + "Meta" : { + "foo": "bar", + "gir": "zim" + }, "Services": [ { "Name": "billing", @@ -333,6 +373,10 @@ func TestParseConfigEntry(t *testing.T) { Kind: "terminating-gateway", Name: "terminating-gw-west", Namespace: "default", + Meta: map[string]string{ + "foo": "bar", + "gir": "zim", + }, Services: []api.LinkedService{ { Name: "billing", @@ -352,6 +396,10 @@ func TestParseConfigEntry(t *testing.T) { Kind: "terminating-gateway", Name: "terminating-gw-west", Namespace: "default", + Meta: map[string]string{ + "foo": "bar", + "gir": "zim", + }, Services: []api.LinkedService{ { Name: "billing", @@ -373,6 +421,10 @@ func TestParseConfigEntry(t *testing.T) { snake: ` kind = "service-defaults" name = "main" + meta { + "foo" = "bar" + "gir" = "zim" + } protocol = "http" external_sni = "abc-123" mesh_gateway { @@ -382,6 +434,10 @@ func TestParseConfigEntry(t *testing.T) { camel: ` Kind = "service-defaults" Name = "main" + Meta { + "foo" = "bar" + "gir" = "zim" + } Protocol = "http" ExternalSNI = "abc-123" MeshGateway { @@ -392,6 +448,10 @@ func TestParseConfigEntry(t *testing.T) { { "kind": "service-defaults", "name": "main", + "meta" : { + "foo": "bar", + "gir": "zim" + }, "protocol": "http", "external_sni": "abc-123", "mesh_gateway": { @@ -403,6 +463,10 @@ func TestParseConfigEntry(t *testing.T) { { "Kind": "service-defaults", "Name": "main", + "Meta" : { + "foo": "bar", + "gir": "zim" + }, "Protocol": "http", "ExternalSNI": "abc-123", "MeshGateway": { @@ -411,8 +475,12 @@ func TestParseConfigEntry(t *testing.T) { } `, expect: &api.ServiceConfigEntry{ - Kind: "service-defaults", - Name: "main", + Kind: "service-defaults", + Name: "main", + Meta: map[string]string{ + "foo": "bar", + "gir": "zim", + }, Protocol: "http", ExternalSNI: "abc-123", MeshGateway: api.MeshGatewayConfig{ @@ -425,6 +493,10 @@ func TestParseConfigEntry(t *testing.T) { snake: ` kind = "service-router" name = "main" + meta { + "foo" = "bar" + "gir" = "zim" + } routes = [ { match { @@ -504,6 +576,10 @@ func TestParseConfigEntry(t *testing.T) { camel: ` Kind = "service-router" Name = "main" + Meta { + "foo" = "bar" + "gir" = "zim" + } Routes = [ { Match { @@ -584,6 +660,10 @@ func TestParseConfigEntry(t *testing.T) { { "kind": "service-router", "name": "main", + "meta" : { + "foo": "bar", + "gir": "zim" + }, "routes": [ { "match": { @@ -671,6 +751,10 @@ func TestParseConfigEntry(t *testing.T) { { "Kind": "service-router", "Name": "main", + "Meta" : { + "foo": "bar", + "gir": "zim" + }, "Routes": [ { "Match": { @@ -757,6 +841,10 @@ func TestParseConfigEntry(t *testing.T) { expect: &api.ServiceRouterConfigEntry{ Kind: "service-router", Name: "main", + Meta: map[string]string{ + "foo": "bar", + "gir": "zim", + }, Routes: []api.ServiceRoute{ { Match: &api.ServiceRouteMatch{ @@ -839,6 +927,10 @@ func TestParseConfigEntry(t *testing.T) { snake: ` kind = "service-splitter" name = "main" + meta { + "foo" = "bar" + "gir" = "zim" + } splits = [ { weight = 97.1 @@ -858,6 +950,10 @@ func TestParseConfigEntry(t *testing.T) { camel: ` Kind = "service-splitter" Name = "main" + Meta { + "foo" = "bar" + "gir" = "zim" + } Splits = [ { Weight = 97.1 @@ -878,6 +974,10 @@ func TestParseConfigEntry(t *testing.T) { { "kind": "service-splitter", "name": "main", + "meta" : { + "foo": "bar", + "gir": "zim" + }, "splits": [ { "weight": 97.1, @@ -899,6 +999,10 @@ func TestParseConfigEntry(t *testing.T) { { "Kind": "service-splitter", "Name": "main", + "Meta" : { + "foo": "bar", + "gir": "zim" + }, "Splits": [ { "Weight": 97.1, @@ -919,6 +1023,10 @@ func TestParseConfigEntry(t *testing.T) { expect: &api.ServiceSplitterConfigEntry{ Kind: api.ServiceSplitter, Name: "main", + Meta: map[string]string{ + "foo": "bar", + "gir": "zim", + }, Splits: []api.ServiceSplit{ { Weight: 97.1, @@ -941,6 +1049,10 @@ func TestParseConfigEntry(t *testing.T) { snake: ` kind = "service-resolver" name = "main" + meta { + "foo" = "bar" + "gir" = "zim" + } default_subset = "v1" connect_timeout = "15s" subsets = { @@ -966,6 +1078,10 @@ func TestParseConfigEntry(t *testing.T) { camel: ` Kind = "service-resolver" Name = "main" + Meta { + "foo" = "bar" + "gir" = "zim" + } DefaultSubset = "v1" ConnectTimeout = "15s" Subsets = { @@ -992,6 +1108,10 @@ func TestParseConfigEntry(t *testing.T) { { "kind": "service-resolver", "name": "main", + "meta" : { + "foo": "bar", + "gir": "zim" + }, "default_subset": "v1", "connect_timeout": "15s", "subsets": { @@ -1025,6 +1145,10 @@ func TestParseConfigEntry(t *testing.T) { { "Kind": "service-resolver", "Name": "main", + "Meta" : { + "foo": "bar", + "gir": "zim" + }, "DefaultSubset": "v1", "ConnectTimeout": "15s", "Subsets": { @@ -1055,8 +1179,12 @@ func TestParseConfigEntry(t *testing.T) { } `, expect: &api.ServiceResolverConfigEntry{ - Kind: "service-resolver", - Name: "main", + Kind: "service-resolver", + Name: "main", + Meta: map[string]string{ + "foo": "bar", + "gir": "zim", + }, DefaultSubset: "v1", ConnectTimeout: 15 * time.Second, Subsets: map[string]api.ServiceResolverSubset{ @@ -1390,6 +1518,10 @@ func TestParseConfigEntry(t *testing.T) { snake: ` kind = "ingress-gateway" name = "ingress-web" + meta { + "foo" = "bar" + "gir" = "zim" + } tls { enabled = true } @@ -1413,6 +1545,10 @@ func TestParseConfigEntry(t *testing.T) { camel: ` Kind = "ingress-gateway" Name = "ingress-web" + Meta { + "foo" = "bar" + "gir" = "zim" + } Tls { Enabled = true } @@ -1437,6 +1573,10 @@ func TestParseConfigEntry(t *testing.T) { { "kind": "ingress-gateway", "name": "ingress-web", + "meta" : { + "foo": "bar", + "gir": "zim" + }, "tls": { "enabled": true }, @@ -1462,6 +1602,10 @@ func TestParseConfigEntry(t *testing.T) { { "Kind": "ingress-gateway", "Name": "ingress-web", + "Meta" : { + "foo": "bar", + "gir": "zim" + }, "Tls": { "Enabled": true }, @@ -1486,6 +1630,10 @@ func TestParseConfigEntry(t *testing.T) { expect: &api.IngressGatewayConfigEntry{ Kind: "ingress-gateway", Name: "ingress-web", + Meta: map[string]string{ + "foo": "bar", + "gir": "zim", + }, TLS: api.GatewayTLSConfig{ Enabled: true, }, diff --git a/website/pages/docs/agent/config-entries/ingress-gateway.mdx b/website/pages/docs/agent/config-entries/ingress-gateway.mdx index 01d1fbc39b..6db703367c 100644 --- a/website/pages/docs/agent/config-entries/ingress-gateway.mdx +++ b/website/pages/docs/agent/config-entries/ingress-gateway.mdx @@ -329,6 +329,8 @@ Also make two services in the frontend namespace available over a custom port wi the gateway is registered in. If omitted, the namespace will be inherited from [the request](/api/config#ns) or will default to the `default` namespace. +- `Meta` `(map: nil)` - Specifies arbitrary KV metadata pairs. Added in Consul 1.9.0. + - `TLS` `(TLSConfig: )` - TLS configuration for this gateway. - `Enabled` `(bool: false)` - Set this configuration to enable TLS for diff --git a/website/pages/docs/agent/config-entries/proxy-defaults.mdx b/website/pages/docs/agent/config-entries/proxy-defaults.mdx index 2753ffdb10..e58550c32c 100644 --- a/website/pages/docs/agent/config-entries/proxy-defaults.mdx +++ b/website/pages/docs/agent/config-entries/proxy-defaults.mdx @@ -46,6 +46,8 @@ Config { - `Namespace` `(string: "default")` - Specifies the namespace the config entry will apply to. +- `Meta` `(map: nil)` - Specifies arbitrary KV metadata pairs. Added in Consul 1.9.0. + - `Config` `(map[string]arbitrary)` - An arbitrary map of configuration values used by Connect proxies. The available configurations depend on the Connect proxy you use. Any values that your proxy allows can be configured globally here. To diff --git a/website/pages/docs/agent/config-entries/service-defaults.mdx b/website/pages/docs/agent/config-entries/service-defaults.mdx index feb4e3ca51..af5aa1ec64 100644 --- a/website/pages/docs/agent/config-entries/service-defaults.mdx +++ b/website/pages/docs/agent/config-entries/service-defaults.mdx @@ -31,6 +31,8 @@ Protocol = "http" - `Namespace` `(string: "default")` - Specifies the namespace the config entry will apply to. +- `Meta` `(map: nil)` - Specifies arbitrary KV metadata pairs. Added in Consul 1.9.0. + - `Protocol` `(string: "tcp")` - Sets the protocol of the service. This is used by Connect proxies for things like observability features and to unlock usage of the [`service-splitter`](/docs/agent/config-entries/service-splitter) and diff --git a/website/pages/docs/agent/config-entries/service-resolver.mdx b/website/pages/docs/agent/config-entries/service-resolver.mdx index 7c418604a4..e09ad0f0e1 100644 --- a/website/pages/docs/agent/config-entries/service-resolver.mdx +++ b/website/pages/docs/agent/config-entries/service-resolver.mdx @@ -78,6 +78,10 @@ Name = "web" - `Name` `(string: )` - Set to the name of the service being configured. +- `Namespace` `(string: "default")` - Specifies the namespace the config entry will apply to. + +- `Meta` `(map: nil)` - Specifies arbitrary KV metadata pairs. Added in Consul 1.9.0. + - `ConnectTimeout` `(duration: 0s)` - The timeout for establishing new network connections to this service. diff --git a/website/pages/docs/agent/config-entries/service-router.mdx b/website/pages/docs/agent/config-entries/service-router.mdx index f169686008..55b73a77ec 100644 --- a/website/pages/docs/agent/config-entries/service-router.mdx +++ b/website/pages/docs/agent/config-entries/service-router.mdx @@ -129,6 +129,10 @@ Routes = [ - `Name` `(string: )` - Set to the name of the service being configured. +- `Namespace` `(string: "default")` - Specifies the namespace the config entry will apply to. + +- `Meta` `(map: nil)` - Specifies arbitrary KV metadata pairs. Added in Consul 1.9.0. + - `Routes` `(array)` - The list of routes to consider when processing L7 requests. The first route to match in the list is terminal and stops further evaluation. Traffic that fails to match any of the provided diff --git a/website/pages/docs/agent/config-entries/service-splitter.mdx b/website/pages/docs/agent/config-entries/service-splitter.mdx index 792a8241be..3ca56ff4e2 100644 --- a/website/pages/docs/agent/config-entries/service-splitter.mdx +++ b/website/pages/docs/agent/config-entries/service-splitter.mdx @@ -81,6 +81,10 @@ Splits = [ - `Name` `(string: )` - Set to the name of the service being configured. +- `Namespace` `(string: "default")` - Specifies the namespace the config entry will apply to. + +- `Meta` `(map: nil)` - Specifies arbitrary KV metadata pairs. Added in Consul 1.9.0. + - `Splits` `(array)` - Defines how much traffic to send to which set of service instances during a traffic split. The sum of weights across all splits must add up to 100. diff --git a/website/pages/docs/agent/config-entries/terminating-gateway.mdx b/website/pages/docs/agent/config-entries/terminating-gateway.mdx index cb8e2c94cb..4752fbbf5e 100644 --- a/website/pages/docs/agent/config-entries/terminating-gateway.mdx +++ b/website/pages/docs/agent/config-entries/terminating-gateway.mdx @@ -407,6 +407,8 @@ and configure default certificates for mutual TLS. Also override the SNI and CA If omitted, the namespace will be inherited from [the request](/api/config#ns) or will default to the `default` namespace. +- `Meta` `(map: nil)` - Specifies arbitrary KV metadata pairs. Added in Consul 1.9.0. + - `Services` `(array: )` - A list of services to link with the gateway. The gateway will proxy traffic to these services. These linked services must be registered with Consul for the gateway to discover their addresses. They must also