@@ -24,10 +24,26 @@ package xds_test
2424
2525import (
2626 "context"
27+ "crypto/tls"
28+ "crypto/x509"
29+ "encoding/json"
30+ "fmt"
31+ "io/ioutil"
32+ "log"
33+ "os"
34+ "path"
2735 "testing"
2836 "time"
2937
38+ "github.com/google/uuid"
39+ "google.golang.org/grpc/credentials"
3040 "google.golang.org/grpc/internal/grpctest"
41+ "google.golang.org/grpc/internal/leakcheck"
42+ "google.golang.org/grpc/internal/xds/env"
43+ "google.golang.org/grpc/testdata"
44+ "google.golang.org/grpc/xds/internal/testutils/e2e"
45+
46+ xdsinternal "google.golang.org/grpc/internal/xds"
3147 testpb "google.golang.org/grpc/test/grpc_testing"
3248)
3349
@@ -51,3 +67,148 @@ type testService struct {
5167func (* testService ) EmptyCall (context.Context , * testpb.Empty ) (* testpb.Empty , error ) {
5268 return & testpb.Empty {}, nil
5369}
70+
71+ var (
72+ // Globals corresponding to the single instance of the xDS management server
73+ // which is spawned for all the tests in this package.
74+ managementServer * e2e.ManagementServer
75+ xdsClientNodeID string
76+ )
77+
78+ // TestMain sets up an xDS management server, runs all tests, and stops the
79+ // management server.
80+ func TestMain (m * testing.M ) {
81+ // The management server is started and stopped from here, but the leakcheck
82+ // runs after every individual test. So, we need to skip the goroutine which
83+ // spawns the management server and is blocked on the call to `Serve()`.
84+ leakcheck .RegisterIgnoreGoroutine ("e2e.StartManagementServer" )
85+
86+ cancel , err := setupManagementServer ()
87+ if err != nil {
88+ log .Printf ("setupManagementServer() failed: %v" , err )
89+ os .Exit (1 )
90+ }
91+
92+ code := m .Run ()
93+ cancel ()
94+ os .Exit (code )
95+ }
96+
97+ func createTmpFile (src , dst string ) error {
98+ data , err := ioutil .ReadFile (src )
99+ if err != nil {
100+ return fmt .Errorf ("ioutil.ReadFile(%q) failed: %v" , src , err )
101+ }
102+ if err := ioutil .WriteFile (dst , data , os .ModePerm ); err != nil {
103+ return fmt .Errorf ("ioutil.WriteFile(%q) failed: %v" , dst , err )
104+ }
105+ return nil
106+ }
107+
108+ // createTempDirWithFiles creates a temporary directory under the system default
109+ // tempDir with the given dirSuffix. It also reads from certSrc, keySrc and
110+ // rootSrc files are creates appropriate files under the newly create tempDir.
111+ // Returns the name of the created tempDir.
112+ func createTmpDirWithFiles (dirSuffix , certSrc , keySrc , rootSrc string ) (string , error ) {
113+ // Create a temp directory. Passing an empty string for the first argument
114+ // uses the system temp directory.
115+ dir , err := ioutil .TempDir ("" , dirSuffix )
116+ if err != nil {
117+ return "" , fmt .Errorf ("ioutil.TempDir() failed: %v" , err )
118+ }
119+
120+ if err := createTmpFile (testdata .Path (certSrc ), path .Join (dir , certFile )); err != nil {
121+ return "" , err
122+ }
123+ if err := createTmpFile (testdata .Path (keySrc ), path .Join (dir , keyFile )); err != nil {
124+ return "" , err
125+ }
126+ if err := createTmpFile (testdata .Path (rootSrc ), path .Join (dir , rootFile )); err != nil {
127+ return "" , err
128+ }
129+ return dir , nil
130+ }
131+
132+ // createClientTLSCredentials creates client-side TLS transport credentials.
133+ func createClientTLSCredentials (t * testing.T ) credentials.TransportCredentials {
134+ t .Helper ()
135+
136+ cert , err := tls .LoadX509KeyPair (testdata .Path ("x509/client1_cert.pem" ), testdata .Path ("x509/client1_key.pem" ))
137+ if err != nil {
138+ t .Fatalf ("tls.LoadX509KeyPair(x509/client1_cert.pem, x509/client1_key.pem) failed: %v" , err )
139+ }
140+ b , err := ioutil .ReadFile (testdata .Path ("x509/server_ca_cert.pem" ))
141+ if err != nil {
142+ t .Fatalf ("ioutil.ReadFile(x509/server_ca_cert.pem) failed: %v" , err )
143+ }
144+ roots := x509 .NewCertPool ()
145+ if ! roots .AppendCertsFromPEM (b ) {
146+ t .Fatal ("failed to append certificates" )
147+ }
148+ return credentials .NewTLS (& tls.Config {
149+ Certificates : []tls.Certificate {cert },
150+ RootCAs : roots ,
151+ ServerName : "x.test.example.com" ,
152+ })
153+ }
154+
155+ // setupManagement server performs the following:
156+ // - spin up an xDS management server on a local port
157+ // - set up certificates for consumption by the file_watcher plugin
158+ // - sets up the global variables which refer to this management server and the
159+ // nodeID to be used when talking to this management server.
160+ //
161+ // Returns a function to be invoked by the caller to stop the management server.
162+ func setupManagementServer () (func (), error ) {
163+ // Turn on the env var protection for client-side security.
164+ origClientSideSecurityEnvVar := env .ClientSideSecuritySupport
165+ env .ClientSideSecuritySupport = true
166+
167+ // Spin up an xDS management server on a local port.
168+ var err error
169+ managementServer , err = e2e .StartManagementServer ()
170+ if err != nil {
171+ return nil , err
172+ }
173+
174+ // Create a directory to hold certs and key files used on the server side.
175+ serverDir , err := createTmpDirWithFiles ("testServerSideXDS*" , "x509/server1_cert.pem" , "x509/server1_key.pem" , "x509/client_ca_cert.pem" )
176+ if err != nil {
177+ managementServer .Stop ()
178+ return nil , err
179+ }
180+
181+ // Create a directory to hold certs and key files used on the client side.
182+ clientDir , err := createTmpDirWithFiles ("testClientSideXDS*" , "x509/client1_cert.pem" , "x509/client1_key.pem" , "x509/server_ca_cert.pem" )
183+ if err != nil {
184+ managementServer .Stop ()
185+ return nil , err
186+ }
187+
188+ // Create certificate providers section of the bootstrap config with entries
189+ // for both the client and server sides.
190+ cpc := map [string ]json.RawMessage {
191+ e2e .ServerSideCertProviderInstance : e2e .DefaultFileWatcherConfig (path .Join (serverDir , certFile ), path .Join (serverDir , keyFile ), path .Join (serverDir , rootFile )),
192+ e2e .ClientSideCertProviderInstance : e2e .DefaultFileWatcherConfig (path .Join (clientDir , certFile ), path .Join (clientDir , keyFile ), path .Join (clientDir , rootFile )),
193+ }
194+
195+ // Create a bootstrap file in a temporary directory.
196+ xdsClientNodeID = uuid .New ().String ()
197+ bootstrapCleanup , err := xdsinternal .SetupBootstrapFile (xdsinternal.BootstrapOptions {
198+ Version : xdsinternal .TransportV3 ,
199+ NodeID : xdsClientNodeID ,
200+ ServerURI : managementServer .Address ,
201+ CertificateProviders : cpc ,
202+ ServerListenerResourceNameTemplate : e2e .ServerListenerResourceNameTemplate ,
203+ })
204+ if err != nil {
205+ managementServer .Stop ()
206+ return nil , err
207+ }
208+
209+ return func () {
210+ managementServer .Stop ()
211+ bootstrapCleanup ()
212+ env .ClientSideSecuritySupport = origClientSideSecurityEnvVar
213+ }, nil
214+ }
0 commit comments