Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix envoy bootstrap logic to not append multiple self_admin clusters #8371

Merged
merged 1 commit into from
Jul 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 38 additions & 5 deletions command/connect/envoy/bootstrap_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ import (
"text/template"
)

const (
selfAdminName = "self_admin"
)

// BootstrapConfig is the set of keys we care about in a Connect.Proxy.Config
// map. Note that this only includes config keys that affects Envoy bootstrap
// generation. For Envoy config keys that affect runtime xDS behavior see
Expand Down Expand Up @@ -70,7 +74,7 @@ type BootstrapConfig struct {
// liveness of an Envoy instance when no other listeners are garaunteed to be
// configured, as is the case with ingress gateways.
//
// Not that we do not allow this to be configured via the service
// Note that we do not allow this to be configured via the service
// definition config map currently.
ReadyBindAddr string `mapstructure:"-"`

Expand Down Expand Up @@ -405,7 +409,7 @@ func (c *BootstrapConfig) generateListenerConfig(args *BootstrapTplArgs, bindAdd
}

clusterJSON := `{
"name": "self_admin",
"name": "` + selfAdminName + `",
"connect_timeout": "5s",
"type": "STATIC",
"http_protocol_options": {},
Expand Down Expand Up @@ -476,14 +480,43 @@ func (c *BootstrapConfig) generateListenerConfig(args *BootstrapTplArgs, bindAdd
]
}`

if args.StaticClustersJSON != "" {
clusterJSON = ",\n" + clusterJSON
// Make sure we do not append the same cluster multiple times, as that will
// cause envoy startup to fail.
selfAdminClusterExists, err := containsSelfAdminCluster(args.StaticClustersJSON)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I started off by just doing a strings.Contains(args.StaticClustersJSON, clusterJSON), but decided to actually parse out the cluster names to validate it. I think the string comparison would've worked just fine, but parsing out the JSON and checking cluster names felt more semantically correct.

if err != nil {
return err
}

if args.StaticClustersJSON == "" {
args.StaticClustersJSON = clusterJSON
} else if !selfAdminClusterExists {
args.StaticClustersJSON += ",\n" + clusterJSON
}
args.StaticClustersJSON += clusterJSON

if args.StaticListenersJSON != "" {
listenerJSON = ",\n" + listenerJSON
}
args.StaticListenersJSON += listenerJSON
return nil
}

func containsSelfAdminCluster(clustersJSON string) (bool, error) {
clusterNames := []struct {
Name string
}{}

// StaticClustersJSON is defined as a comma-separated list of clusters, so we
// need to wrap it in JSON array brackets
err := json.Unmarshal([]byte("["+clustersJSON+"]"), &clusterNames)
if err != nil {
return false, fmt.Errorf("failed to parse static clusters: %s", err)
}

for _, cluster := range clusterNames {
if cluster.Name == selfAdminName {
return true, nil
}
}

return false, nil
}
25 changes: 25 additions & 0 deletions command/connect/envoy/bootstrap_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -598,6 +598,31 @@ func TestBootstrapConfig_ConfigureArgs(t *testing.T) {
},
wantErr: false,
},
{
name: "ready-bind-addr-and-prometheus-and-stats",
input: BootstrapConfig{
ReadyBindAddr: "0.0.0.0:4444",
PrometheusBindAddr: "0.0.0.0:9000",
StatsBindAddr: "0.0.0.0:9000",
},
baseArgs: BootstrapTplArgs{
AdminBindAddress: "127.0.0.1",
AdminBindPort: "19000",
},
wantArgs: BootstrapTplArgs{
AdminBindAddress: "127.0.0.1",
AdminBindPort: "19000",
// Should add a static cluster for the self-proxy to admin
StaticClustersJSON: expectedSelfAdminCluster,
// Should add a static http listener too
StaticListenersJSON: strings.Join(
[]string{expectedPromListener, expectedStatsListener, expectedReadyListener},
", ",
),
StatsConfigJSON: defaultStatsConfigJSON,
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down