|
1 | 1 | package bootstrap
|
2 | 2 |
|
3 | 3 | import (
|
| 4 | + "fmt" |
| 5 | + "io/ioutil" |
| 6 | + "path" |
| 7 | + "path/filepath" |
| 8 | + |
| 9 | + xds_bootstrap "github.com/envoyproxy/go-control-plane/envoy/config/bootstrap/v3" |
| 10 | + . "github.com/onsi/ginkgo" |
| 11 | + . "github.com/onsi/gomega" |
| 12 | + |
| 13 | + "github.com/golang/mock/gomock" |
| 14 | + |
4 | 15 | "testing"
|
5 | 16 |
|
| 17 | + "github.com/openservicemesh/osm/pkg/apis/config/v1alpha2" |
| 18 | + "github.com/openservicemesh/osm/pkg/configurator" |
| 19 | + |
6 | 20 | tassert "github.com/stretchr/testify/assert"
|
7 | 21 |
|
8 | 22 | tresorFake "github.com/openservicemesh/osm/pkg/certificate/providers/tresor/fake"
|
9 | 23 | "github.com/openservicemesh/osm/pkg/constants"
|
| 24 | + "github.com/openservicemesh/osm/pkg/models" |
10 | 25 | "github.com/openservicemesh/osm/pkg/utils"
|
11 | 26 | )
|
12 | 27 |
|
@@ -103,3 +118,125 @@ static_resources:
|
103 | 118 | `
|
104 | 119 | assert.Equal(expectedYAML, string(actualYAML))
|
105 | 120 | }
|
| 121 | + |
| 122 | +var _ = Describe("Test functions creating Envoy bootstrap configuration", func() { |
| 123 | + const ( |
| 124 | + // This file contains the Bootstrap YAML generated for all of the Envoy proxies in OSM. |
| 125 | + // This is provisioned by the MutatingWebhook during the addition of a sidecar |
| 126 | + // to every new Pod that is being created in a namespace participating in the service mesh. |
| 127 | + // We deliberately leave this entire string literal here to document and visualize what the |
| 128 | + // generated YAML looks like! |
| 129 | + expectedEnvoyBootstrapConfigFileName = "expected_envoy_bootstrap_config.yaml" |
| 130 | + actualGeneratedEnvoyBootstrapConfigFileName = "actual_envoy_bootstrap_config.yaml" |
| 131 | + |
| 132 | + // All the YAML files listed above are in this sub-directory |
| 133 | + directoryForYAMLFiles = "test_fixtures" |
| 134 | + ) |
| 135 | + |
| 136 | + meshConfig := v1alpha2.MeshConfig{ |
| 137 | + Spec: v1alpha2.MeshConfigSpec{ |
| 138 | + Sidecar: v1alpha2.SidecarSpec{ |
| 139 | + TLSMinProtocolVersion: "TLSv1_2", |
| 140 | + TLSMaxProtocolVersion: "TLSv1_3", |
| 141 | + CipherSuites: []string{}, |
| 142 | + }, |
| 143 | + }, |
| 144 | + } |
| 145 | + |
| 146 | + cert := tresorFake.NewFakeCertificate() |
| 147 | + mockCtrl := gomock.NewController(GinkgoT()) |
| 148 | + mockConfigurator := configurator.NewMockConfigurator(mockCtrl) |
| 149 | + mockConfigurator.EXPECT().GetMeshConfig().Return(meshConfig).AnyTimes() |
| 150 | + |
| 151 | + getExpectedEnvoyYAML := func(filename string) string { |
| 152 | + expectedEnvoyConfig, err := ioutil.ReadFile(filepath.Clean(path.Join(directoryForYAMLFiles, filename))) |
| 153 | + if err != nil { |
| 154 | + log.Error().Err(err).Msgf("Error reading expected Envoy bootstrap YAML from file %s", filename) |
| 155 | + } |
| 156 | + Expect(err).ToNot(HaveOccurred()) |
| 157 | + return string(expectedEnvoyConfig) |
| 158 | + } |
| 159 | + |
| 160 | + getExpectedEnvoyConfig := func(filename string) *xds_bootstrap.Bootstrap { |
| 161 | + yaml := getExpectedEnvoyYAML(filename) |
| 162 | + conf := xds_bootstrap.Bootstrap{} |
| 163 | + err := utils.YAMLToProto([]byte(yaml), &conf) |
| 164 | + Expect(err).ToNot(HaveOccurred()) |
| 165 | + return &conf |
| 166 | + } |
| 167 | + |
| 168 | + saveActualEnvoyConfig := func(filename string, actual *xds_bootstrap.Bootstrap) { |
| 169 | + actualContent, err := utils.ProtoToYAML(actual) |
| 170 | + Expect(err).ToNot(HaveOccurred()) |
| 171 | + err = ioutil.WriteFile(filepath.Clean(path.Join(directoryForYAMLFiles, filename)), actualContent, 0600) |
| 172 | + if err != nil { |
| 173 | + log.Error().Err(err).Msgf("Error writing actual Envoy Cluster XDS YAML to file %s", filename) |
| 174 | + } |
| 175 | + Expect(err).ToNot(HaveOccurred()) |
| 176 | + } |
| 177 | + |
| 178 | + probes := models.HealthProbes{ |
| 179 | + Liveness: &models.HealthProbe{Path: "/liveness", Port: 81, IsHTTP: true}, |
| 180 | + Readiness: &models.HealthProbe{Path: "/readiness", Port: 82, IsHTTP: true}, |
| 181 | + Startup: &models.HealthProbe{Path: "/startup", Port: 83, IsHTTP: true}, |
| 182 | + } |
| 183 | + |
| 184 | + config := EnvoyBootstrapConfigMeta{ |
| 185 | + NodeID: cert.GetCommonName().String(), |
| 186 | + |
| 187 | + EnvoyAdminPort: 15000, |
| 188 | + |
| 189 | + XDSClusterName: constants.OSMControllerName, |
| 190 | + XDSHost: "osm-controller.b.svc.cluster.local", |
| 191 | + XDSPort: 15128, |
| 192 | + |
| 193 | + OriginalHealthProbes: probes, |
| 194 | + TLSMinProtocolVersion: meshConfig.Spec.Sidecar.TLSMinProtocolVersion, |
| 195 | + TLSMaxProtocolVersion: meshConfig.Spec.Sidecar.TLSMaxProtocolVersion, |
| 196 | + CipherSuites: meshConfig.Spec.Sidecar.CipherSuites, |
| 197 | + ECDHCurves: meshConfig.Spec.Sidecar.ECDHCurves, |
| 198 | + } |
| 199 | + |
| 200 | + Context("Test GenerateEnvoyConfig()", func() { |
| 201 | + It("creates Envoy bootstrap config", func() { |
| 202 | + config.OriginalHealthProbes = probes |
| 203 | + actual, err := GenerateEnvoyConfig(config, mockConfigurator) |
| 204 | + Expect(err).ToNot(HaveOccurred()) |
| 205 | + saveActualEnvoyConfig(actualGeneratedEnvoyBootstrapConfigFileName, actual) |
| 206 | + |
| 207 | + expectedEnvoyConfig := getExpectedEnvoyConfig(expectedEnvoyBootstrapConfigFileName) |
| 208 | + |
| 209 | + actualYaml, err := utils.ProtoToYAML(actual) |
| 210 | + Expect(err).ToNot(HaveOccurred()) |
| 211 | + |
| 212 | + expectedYaml, err := utils.ProtoToYAML(expectedEnvoyConfig) |
| 213 | + Expect(err).ToNot(HaveOccurred()) |
| 214 | + |
| 215 | + Expect(actualYaml).To(Equal(expectedYaml), |
| 216 | + fmt.Sprintf(" %s and %s\nExpected:\n%s\nActual:\n%s\n", |
| 217 | + expectedEnvoyBootstrapConfigFileName, actualGeneratedEnvoyBootstrapConfigFileName, expectedYaml, actualYaml)) |
| 218 | + }) |
| 219 | + }) |
| 220 | + |
| 221 | + Context("Test getProbeResources()", func() { |
| 222 | + It("Should not create listeners and clusters when there are no probes", func() { |
| 223 | + config.OriginalHealthProbes = models.HealthProbes{} // no probes |
| 224 | + actualListeners, actualClusters, err := getProbeResources(config) |
| 225 | + Expect(err).To(BeNil()) |
| 226 | + Expect(actualListeners).To(BeNil()) |
| 227 | + Expect(actualClusters).To(BeNil()) |
| 228 | + }) |
| 229 | + |
| 230 | + It("Should not create listeners and cluster for TCPSocket probes", func() { |
| 231 | + config.OriginalHealthProbes = models.HealthProbes{ |
| 232 | + Liveness: &models.HealthProbe{Port: 81, IsTCPSocket: true}, |
| 233 | + Readiness: &models.HealthProbe{Port: 82, IsTCPSocket: true}, |
| 234 | + Startup: &models.HealthProbe{Port: 83, IsTCPSocket: true}, |
| 235 | + } |
| 236 | + actualListeners, actualClusters, err := getProbeResources(config) |
| 237 | + Expect(err).To(BeNil()) |
| 238 | + Expect(actualListeners).To(BeNil()) |
| 239 | + Expect(actualClusters).To(BeNil()) |
| 240 | + }) |
| 241 | + }) |
| 242 | +}) |
0 commit comments