@@ -24,10 +24,26 @@ package xds_test
24
24
25
25
import (
26
26
"context"
27
+ "crypto/tls"
28
+ "crypto/x509"
29
+ "encoding/json"
30
+ "fmt"
31
+ "io/ioutil"
32
+ "log"
33
+ "os"
34
+ "path"
27
35
"testing"
28
36
"time"
29
37
38
+ "github.com/google/uuid"
39
+ "google.golang.org/grpc/credentials"
30
40
"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"
31
47
testpb "google.golang.org/grpc/test/grpc_testing"
32
48
)
33
49
@@ -51,3 +67,148 @@ type testService struct {
51
67
func (* testService ) EmptyCall (context.Context , * testpb.Empty ) (* testpb.Empty , error ) {
52
68
return & testpb.Empty {}, nil
53
69
}
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