mirror of
https://github.com/status-im/consul.git
synced 2025-01-09 13:26:07 +00:00
5fb9df1640
* Adding explicit MPL license for sub-package This directory and its subdirectories (packages) contain files licensed with the MPLv2 `LICENSE` file in this directory and are intentionally licensed separately from the BSL `LICENSE` file at the root of this repository. * Adding explicit MPL license for sub-package This directory and its subdirectories (packages) contain files licensed with the MPLv2 `LICENSE` file in this directory and are intentionally licensed separately from the BSL `LICENSE` file at the root of this repository. * Updating the license from MPL to Business Source License Going forward, this project will be licensed under the Business Source License v1.1. Please see our blog post for more details at <Blog URL>, FAQ at www.hashicorp.com/licensing-faq, and details of the license at www.hashicorp.com/bsl. * add missing license headers * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 --------- Co-authored-by: hashicorp-copywrite[bot] <110428419+hashicorp-copywrite[bot]@users.noreply.github.com>
554 lines
15 KiB
Go
554 lines
15 KiB
Go
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
package configentry
|
|
|
|
import (
|
|
"sort"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/hashicorp/consul/acl"
|
|
"github.com/hashicorp/consul/agent/structs"
|
|
)
|
|
|
|
func Test_ComputeResolvedServiceConfig(t *testing.T) {
|
|
type args struct {
|
|
scReq *structs.ServiceConfigRequest
|
|
entries *ResolvedServiceConfigSet
|
|
}
|
|
|
|
sid := structs.ServiceID{
|
|
ID: "sid",
|
|
EnterpriseMeta: *acl.DefaultEnterpriseMeta(),
|
|
}
|
|
uid := structs.PeeredServiceName{
|
|
ServiceName: structs.NewServiceName("upstream1", acl.DefaultEnterpriseMeta()),
|
|
}
|
|
|
|
uids := []structs.PeeredServiceName{uid}
|
|
|
|
wildcard := structs.PeeredServiceName{
|
|
ServiceName: structs.NewServiceName(structs.WildcardSpecifier, acl.WildcardEnterpriseMeta()),
|
|
}
|
|
|
|
localMeshGW := structs.MeshGatewayConfig{Mode: structs.MeshGatewayModeLocal}
|
|
remoteMeshGW := structs.MeshGatewayConfig{Mode: structs.MeshGatewayModeRemote}
|
|
noneMeshGW := structs.MeshGatewayConfig{Mode: structs.MeshGatewayModeNone}
|
|
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want *structs.ServiceConfigResponse
|
|
}{
|
|
{
|
|
name: "proxy with balanceinboundconnections",
|
|
args: args{
|
|
scReq: &structs.ServiceConfigRequest{
|
|
Name: "sid",
|
|
},
|
|
entries: &ResolvedServiceConfigSet{
|
|
ServiceDefaults: map[structs.ServiceID]*structs.ServiceConfigEntry{
|
|
sid: {
|
|
BalanceInboundConnections: "exact_balance",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
want: &structs.ServiceConfigResponse{
|
|
ProxyConfig: map[string]interface{}{
|
|
"balance_inbound_connections": "exact_balance",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "proxy with maxinboundsconnections",
|
|
args: args{
|
|
scReq: &structs.ServiceConfigRequest{
|
|
Name: "sid",
|
|
},
|
|
entries: &ResolvedServiceConfigSet{
|
|
ServiceDefaults: map[structs.ServiceID]*structs.ServiceConfigEntry{
|
|
sid: {
|
|
MaxInboundConnections: 20,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
want: &structs.ServiceConfigResponse{
|
|
ProxyConfig: map[string]interface{}{
|
|
"max_inbound_connections": 20,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "proxy with local_connect_timeout_ms and local_request_timeout_ms",
|
|
args: args{
|
|
scReq: &structs.ServiceConfigRequest{
|
|
Name: "sid",
|
|
},
|
|
entries: &ResolvedServiceConfigSet{
|
|
ServiceDefaults: map[structs.ServiceID]*structs.ServiceConfigEntry{
|
|
sid: {
|
|
MaxInboundConnections: 20,
|
|
LocalConnectTimeoutMs: 20000,
|
|
LocalRequestTimeoutMs: 30000,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
want: &structs.ServiceConfigResponse{
|
|
ProxyConfig: map[string]interface{}{
|
|
"max_inbound_connections": 20,
|
|
"local_connect_timeout_ms": 20000,
|
|
"local_request_timeout_ms": 30000,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "proxy upstream mesh-gateway inherits proxy-defaults",
|
|
args: args{
|
|
scReq: &structs.ServiceConfigRequest{
|
|
Name: "sid",
|
|
UpstreamServiceNames: uids,
|
|
},
|
|
entries: &ResolvedServiceConfigSet{
|
|
ProxyDefaults: map[string]*structs.ProxyConfigEntry{
|
|
acl.DefaultEnterpriseMeta().PartitionOrDefault(): {
|
|
MeshGateway: remoteMeshGW, // applied 1st
|
|
},
|
|
},
|
|
},
|
|
},
|
|
want: &structs.ServiceConfigResponse{
|
|
MeshGateway: remoteMeshGW,
|
|
UpstreamConfigs: structs.OpaqueUpstreamConfigs{
|
|
{
|
|
Upstream: wildcard,
|
|
Config: map[string]interface{}{
|
|
"mesh_gateway": structs.MeshGatewayConfig{
|
|
Mode: structs.MeshGatewayModeRemote,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Upstream: uid,
|
|
Config: map[string]interface{}{
|
|
"mesh_gateway": remoteMeshGW,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "proxy inherits kitchen sink from proxy-defaults",
|
|
args: args{
|
|
scReq: &structs.ServiceConfigRequest{
|
|
Name: "sid",
|
|
UpstreamServiceNames: uids,
|
|
},
|
|
entries: &ResolvedServiceConfigSet{
|
|
ProxyDefaults: map[string]*structs.ProxyConfigEntry{
|
|
acl.DefaultEnterpriseMeta().PartitionOrDefault(): {
|
|
Config: map[string]interface{}{
|
|
"foo": "bar",
|
|
},
|
|
Expose: structs.ExposeConfig{
|
|
Checks: true,
|
|
Paths: []structs.ExposePath{},
|
|
},
|
|
Mode: structs.ProxyModeTransparent,
|
|
MeshGateway: remoteMeshGW,
|
|
TransparentProxy: structs.TransparentProxyConfig{
|
|
OutboundListenerPort: 6666,
|
|
DialedDirectly: true,
|
|
},
|
|
AccessLogs: structs.AccessLogsConfig{
|
|
Enabled: true,
|
|
DisableListenerLogs: true,
|
|
Type: structs.FileLogSinkType,
|
|
Path: "/tmp/accesslog.txt",
|
|
JSONFormat: "{ \"custom_start_time\": \"%START_TIME%\" }",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
want: &structs.ServiceConfigResponse{
|
|
ProxyConfig: map[string]interface{}{
|
|
"foo": "bar",
|
|
},
|
|
Expose: structs.ExposeConfig{
|
|
Checks: true,
|
|
Paths: []structs.ExposePath{},
|
|
},
|
|
Mode: structs.ProxyModeTransparent,
|
|
MeshGateway: remoteMeshGW,
|
|
TransparentProxy: structs.TransparentProxyConfig{
|
|
OutboundListenerPort: 6666,
|
|
DialedDirectly: true,
|
|
},
|
|
AccessLogs: structs.AccessLogsConfig{
|
|
Enabled: true,
|
|
DisableListenerLogs: true,
|
|
Type: structs.FileLogSinkType,
|
|
Path: "/tmp/accesslog.txt",
|
|
JSONFormat: "{ \"custom_start_time\": \"%START_TIME%\" }",
|
|
},
|
|
UpstreamConfigs: structs.OpaqueUpstreamConfigs{
|
|
{
|
|
Upstream: wildcard,
|
|
Config: map[string]interface{}{
|
|
"mesh_gateway": remoteMeshGW,
|
|
},
|
|
},
|
|
{
|
|
Upstream: uid,
|
|
Config: map[string]interface{}{
|
|
"mesh_gateway": remoteMeshGW,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "proxy upstream mesh-gateway inherits service-defaults",
|
|
args: args{
|
|
scReq: &structs.ServiceConfigRequest{
|
|
Name: "sid",
|
|
UpstreamServiceNames: uids,
|
|
},
|
|
entries: &ResolvedServiceConfigSet{
|
|
ProxyDefaults: map[string]*structs.ProxyConfigEntry{
|
|
acl.DefaultEnterpriseMeta().PartitionOrDefault(): {
|
|
MeshGateway: localMeshGW, // applied 1st
|
|
},
|
|
},
|
|
ServiceDefaults: map[structs.ServiceID]*structs.ServiceConfigEntry{
|
|
sid: {
|
|
MeshGateway: noneMeshGW, // applied 2nd
|
|
},
|
|
},
|
|
},
|
|
},
|
|
want: &structs.ServiceConfigResponse{
|
|
MeshGateway: noneMeshGW, // service-defaults has a higher precedence.
|
|
UpstreamConfigs: structs.OpaqueUpstreamConfigs{
|
|
{
|
|
Upstream: wildcard,
|
|
Config: map[string]interface{}{
|
|
"mesh_gateway": noneMeshGW,
|
|
},
|
|
},
|
|
{
|
|
Upstream: uid,
|
|
Config: map[string]interface{}{
|
|
"mesh_gateway": noneMeshGW,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "proxy wildcard upstream mesh-gateway inherits proxy-defaults",
|
|
args: args{
|
|
scReq: &structs.ServiceConfigRequest{
|
|
Name: "sid",
|
|
Mode: structs.ProxyModeTransparent,
|
|
},
|
|
entries: &ResolvedServiceConfigSet{
|
|
ProxyDefaults: map[string]*structs.ProxyConfigEntry{
|
|
acl.DefaultEnterpriseMeta().PartitionOrDefault(): {
|
|
MeshGateway: localMeshGW,
|
|
},
|
|
},
|
|
ServiceDefaults: map[structs.ServiceID]*structs.ServiceConfigEntry{
|
|
sid: {
|
|
UpstreamConfig: &structs.UpstreamConfiguration{
|
|
Defaults: &structs.UpstreamConfig{
|
|
Protocol: "http",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
want: &structs.ServiceConfigResponse{
|
|
MeshGateway: localMeshGW,
|
|
UpstreamConfigs: structs.OpaqueUpstreamConfigs{
|
|
{
|
|
Upstream: wildcard,
|
|
Config: map[string]interface{}{
|
|
"mesh_gateway": localMeshGW, // From proxy-defaults
|
|
"protocol": "http",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "proxy upstream mesh-gateway inherits upstream defaults",
|
|
args: args{
|
|
scReq: &structs.ServiceConfigRequest{
|
|
Name: "sid",
|
|
UpstreamServiceNames: uids,
|
|
},
|
|
entries: &ResolvedServiceConfigSet{
|
|
ProxyDefaults: map[string]*structs.ProxyConfigEntry{
|
|
acl.DefaultEnterpriseMeta().PartitionOrDefault(): {
|
|
MeshGateway: localMeshGW,
|
|
},
|
|
},
|
|
ServiceDefaults: map[structs.ServiceID]*structs.ServiceConfigEntry{
|
|
sid: {
|
|
MeshGateway: noneMeshGW,
|
|
UpstreamConfig: &structs.UpstreamConfiguration{
|
|
Defaults: &structs.UpstreamConfig{
|
|
MeshGateway: remoteMeshGW,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
want: &structs.ServiceConfigResponse{
|
|
MeshGateway: noneMeshGW, // Merged from proxy-defaults + service-defaults
|
|
UpstreamConfigs: structs.OpaqueUpstreamConfigs{
|
|
{
|
|
Upstream: wildcard,
|
|
Config: map[string]interface{}{
|
|
// Wildcard stores the values from UpstreamConfig.Defaults directly
|
|
"mesh_gateway": remoteMeshGW,
|
|
},
|
|
},
|
|
{
|
|
Upstream: uid,
|
|
Config: map[string]interface{}{
|
|
// Upstream-specific config comes from UpstreamConfig.Defaults
|
|
"mesh_gateway": remoteMeshGW,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "proxy upstream mesh-gateway inherits value from node-service",
|
|
args: args{
|
|
scReq: &structs.ServiceConfigRequest{
|
|
Name: "sid",
|
|
UpstreamServiceNames: uids,
|
|
|
|
// MeshGateway from NodeService is received in the request
|
|
MeshGateway: remoteMeshGW,
|
|
},
|
|
entries: &ResolvedServiceConfigSet{
|
|
ServiceDefaults: map[structs.ServiceID]*structs.ServiceConfigEntry{
|
|
sid: {
|
|
UpstreamConfig: &structs.UpstreamConfiguration{
|
|
Defaults: &structs.UpstreamConfig{
|
|
MeshGateway: noneMeshGW,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
want: &structs.ServiceConfigResponse{
|
|
UpstreamConfigs: structs.OpaqueUpstreamConfigs{
|
|
{
|
|
Upstream: wildcard,
|
|
Config: map[string]interface{}{
|
|
// NodeService.Proxy.MeshGateway has a higher precedence than centralized
|
|
// UpstreamConfig.Defaults, since it's specific to a service instance.
|
|
"mesh_gateway": remoteMeshGW,
|
|
},
|
|
},
|
|
{
|
|
Upstream: uid,
|
|
Config: map[string]interface{}{
|
|
"mesh_gateway": remoteMeshGW,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "proxy upstream mesh-gateway inherits value from service-defaults override",
|
|
args: args{
|
|
scReq: &structs.ServiceConfigRequest{
|
|
Name: "sid",
|
|
UpstreamServiceNames: uids,
|
|
MeshGateway: localMeshGW, // applied 2nd
|
|
},
|
|
entries: &ResolvedServiceConfigSet{
|
|
ServiceDefaults: map[structs.ServiceID]*structs.ServiceConfigEntry{
|
|
sid: {
|
|
UpstreamConfig: &structs.UpstreamConfiguration{
|
|
Defaults: &structs.UpstreamConfig{
|
|
MeshGateway: localMeshGW, // applied 1st
|
|
},
|
|
Overrides: []*structs.UpstreamConfig{
|
|
{
|
|
Name: uid.ServiceName.Name,
|
|
MeshGateway: remoteMeshGW, // applied 3rd
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
want: &structs.ServiceConfigResponse{
|
|
UpstreamConfigs: structs.OpaqueUpstreamConfigs{
|
|
{
|
|
Upstream: wildcard,
|
|
Config: map[string]interface{}{
|
|
// Wildcard stores the values from UpstreamConfig.Defaults directly
|
|
"mesh_gateway": localMeshGW,
|
|
},
|
|
},
|
|
{
|
|
Upstream: uid,
|
|
Config: map[string]interface{}{
|
|
// UpstreamConfig.Overrides has a higher precedence than UpstreamConfig.Defaults
|
|
"mesh_gateway": remoteMeshGW,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "servicedefaults envoy extension",
|
|
args: args{
|
|
scReq: &structs.ServiceConfigRequest{
|
|
Name: "sid",
|
|
},
|
|
entries: &ResolvedServiceConfigSet{
|
|
ServiceDefaults: map[structs.ServiceID]*structs.ServiceConfigEntry{
|
|
sid: {
|
|
EnvoyExtensions: []structs.EnvoyExtension{
|
|
{
|
|
Name: "sd-ext",
|
|
Required: false,
|
|
Arguments: map[string]interface{}{"arg": "val"},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
want: &structs.ServiceConfigResponse{
|
|
EnvoyExtensions: []structs.EnvoyExtension{
|
|
{
|
|
Name: "sd-ext",
|
|
Required: false,
|
|
Arguments: map[string]interface{}{"arg": "val"},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "proxydefaults envoy extension appended to servicedefaults extension",
|
|
args: args{
|
|
scReq: &structs.ServiceConfigRequest{
|
|
Name: "sid",
|
|
},
|
|
entries: &ResolvedServiceConfigSet{
|
|
ProxyDefaults: map[string]*structs.ProxyConfigEntry{
|
|
acl.DefaultEnterpriseMeta().PartitionOrDefault(): {
|
|
EnvoyExtensions: []structs.EnvoyExtension{
|
|
{
|
|
Name: "pd-ext",
|
|
Required: false,
|
|
Arguments: map[string]interface{}{"arg": "val"},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
ServiceDefaults: map[structs.ServiceID]*structs.ServiceConfigEntry{
|
|
sid: {
|
|
EnvoyExtensions: []structs.EnvoyExtension{
|
|
{
|
|
Name: "sd-ext",
|
|
Required: false,
|
|
Arguments: map[string]interface{}{"arg": "val"},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
want: &structs.ServiceConfigResponse{
|
|
EnvoyExtensions: []structs.EnvoyExtension{
|
|
{
|
|
Name: "pd-ext",
|
|
Required: false,
|
|
Arguments: map[string]interface{}{"arg": "val"},
|
|
},
|
|
{
|
|
Name: "sd-ext",
|
|
Required: false,
|
|
Arguments: map[string]interface{}{"arg": "val"},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "service-defaults inherits mutual_tls_mode from proxy-defaults",
|
|
args: args{
|
|
scReq: &structs.ServiceConfigRequest{
|
|
Name: "sid",
|
|
},
|
|
entries: &ResolvedServiceConfigSet{
|
|
ProxyDefaults: map[string]*structs.ProxyConfigEntry{
|
|
acl.DefaultEnterpriseMeta().PartitionOrDefault(): {
|
|
MutualTLSMode: structs.MutualTLSModePermissive,
|
|
},
|
|
},
|
|
ServiceDefaults: map[structs.ServiceID]*structs.ServiceConfigEntry{
|
|
sid: {},
|
|
},
|
|
},
|
|
},
|
|
want: &structs.ServiceConfigResponse{
|
|
MutualTLSMode: structs.MutualTLSModePermissive,
|
|
},
|
|
},
|
|
{
|
|
name: "service-defaults overrides mutual_tls_mode in proxy-defaults",
|
|
args: args{
|
|
scReq: &structs.ServiceConfigRequest{
|
|
Name: "sid",
|
|
},
|
|
entries: &ResolvedServiceConfigSet{
|
|
ProxyDefaults: map[string]*structs.ProxyConfigEntry{
|
|
acl.DefaultEnterpriseMeta().PartitionOrDefault(): {
|
|
MutualTLSMode: structs.MutualTLSModeStrict,
|
|
},
|
|
},
|
|
ServiceDefaults: map[structs.ServiceID]*structs.ServiceConfigEntry{
|
|
sid: {
|
|
MutualTLSMode: structs.MutualTLSModePermissive,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
want: &structs.ServiceConfigResponse{
|
|
MutualTLSMode: structs.MutualTLSModePermissive,
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, err := ComputeResolvedServiceConfig(tt.args.scReq, tt.args.entries, nil)
|
|
require.NoError(t, err)
|
|
// This is needed because map iteration is random and determines the order of some outputs.
|
|
sort.Slice(got.UpstreamConfigs, func(i, j int) bool {
|
|
return got.UpstreamConfigs[i].Upstream.ServiceName.Name < got.UpstreamConfigs[j].Upstream.ServiceName.Name
|
|
})
|
|
require.Equal(t, tt.want, got)
|
|
})
|
|
}
|
|
}
|