1 /* 2 * Copyright 2014 The gRPC Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package io.grpc.testing.integration; 18 19 import com.google.common.annotations.VisibleForTesting; 20 import com.google.common.util.concurrent.MoreExecutors; 21 import io.grpc.BindableService; 22 import io.grpc.Grpc; 23 import io.grpc.InsecureServerCredentials; 24 import io.grpc.Server; 25 import io.grpc.ServerCredentials; 26 import io.grpc.ServerInterceptors; 27 import io.grpc.TlsServerCredentials; 28 import io.grpc.alts.AltsServerCredentials; 29 import io.grpc.services.MetricRecorder; 30 import io.grpc.testing.TlsTesting; 31 import io.grpc.xds.orca.OrcaMetricReportingServerInterceptor; 32 import io.grpc.xds.orca.OrcaServiceImpl; 33 import java.util.concurrent.Executors; 34 import java.util.concurrent.ScheduledExecutorService; 35 import java.util.concurrent.TimeUnit; 36 37 /** Server that manages startup/shutdown of a single {@code TestService}. */ 38 public class TestServiceServer { 39 /** The main application allowing this server to be launched from the command line. */ main(String[] args)40 public static void main(String[] args) throws Exception { 41 final TestServiceServer server = new TestServiceServer(); 42 server.parseArgs(args); 43 if (server.useTls) { 44 System.out.println( 45 "\nUsing fake CA for TLS certificate. Test clients should expect host\n" 46 + "*.test.google.fr and our test CA. For the Java test client binary, use:\n" 47 + "--server_host_override=foo.test.google.fr --use_test_ca=true\n"); 48 } 49 50 Runtime.getRuntime() 51 .addShutdownHook( 52 new Thread() { 53 @Override 54 @SuppressWarnings("CatchAndPrintStackTrace") 55 public void run() { 56 try { 57 System.out.println("Shutting down"); 58 server.stop(); 59 } catch (Exception e) { 60 e.printStackTrace(); 61 } 62 } 63 }); 64 server.start(); 65 System.out.println("Server started on port " + server.port); 66 server.blockUntilShutdown(); 67 } 68 69 private int port = 8080; 70 private boolean useTls = true; 71 private boolean useAlts = false; 72 73 private ScheduledExecutorService executor; 74 private Server server; 75 private int localHandshakerPort = -1; 76 77 @VisibleForTesting parseArgs(String[] args)78 void parseArgs(String[] args) { 79 boolean usage = false; 80 for (String arg : args) { 81 if (!arg.startsWith("--")) { 82 System.err.println("All arguments must start with '--': " + arg); 83 usage = true; 84 break; 85 } 86 String[] parts = arg.substring(2).split("=", 2); 87 String key = parts[0]; 88 if ("help".equals(key)) { 89 usage = true; 90 break; 91 } 92 if (parts.length != 2) { 93 System.err.println("All arguments must be of the form --arg=value"); 94 usage = true; 95 break; 96 } 97 String value = parts[1]; 98 if ("port".equals(key)) { 99 port = Integer.parseInt(value); 100 } else if ("use_tls".equals(key)) { 101 useTls = Boolean.parseBoolean(value); 102 } else if ("use_alts".equals(key)) { 103 useAlts = Boolean.parseBoolean(value); 104 } else if ("local_handshaker_port".equals(key)) { 105 localHandshakerPort = Integer.parseInt(value); 106 } else if ("grpc_version".equals(key)) { 107 if (!"2".equals(value)) { 108 System.err.println("Only grpc version 2 is supported"); 109 usage = true; 110 break; 111 } 112 } else { 113 System.err.println("Unknown argument: " + key); 114 usage = true; 115 break; 116 } 117 } 118 if (useAlts) { 119 useTls = false; 120 } 121 if (usage) { 122 TestServiceServer s = new TestServiceServer(); 123 System.out.println( 124 "Usage: [ARGS...]" 125 + "\n" 126 + "\n --port=PORT Port to connect to. Default " + s.port 127 + "\n --use_tls=true|false Whether to use TLS. Default " + s.useTls 128 + "\n --use_alts=true|false Whether to use ALTS. Enable ALTS will disable TLS." 129 + "\n Default " + s.useAlts 130 + "\n --local_handshaker_port=PORT" 131 + "\n Use local ALTS handshaker service on the specified port " 132 + "\n for testing. Only effective when --use_alts=true." 133 ); 134 System.exit(1); 135 } 136 } 137 138 @VisibleForTesting start()139 void start() throws Exception { 140 executor = Executors.newSingleThreadScheduledExecutor(); 141 ServerCredentials serverCreds; 142 if (useAlts) { 143 if (localHandshakerPort > -1) { 144 serverCreds = AltsServerCredentials.newBuilder() 145 .enableUntrustedAltsForTesting() 146 .setHandshakerAddressForTesting("localhost:" + localHandshakerPort).build(); 147 } else { 148 serverCreds = AltsServerCredentials.create(); 149 } 150 } else if (useTls) { 151 serverCreds = TlsServerCredentials.create( 152 TlsTesting.loadCert("server1.pem"), TlsTesting.loadCert("server1.key")); 153 } else { 154 serverCreds = InsecureServerCredentials.create(); 155 } 156 MetricRecorder metricRecorder = MetricRecorder.newInstance(); 157 BindableService orcaOobService = 158 OrcaServiceImpl.createService(executor, metricRecorder, 1, TimeUnit.SECONDS); 159 server = Grpc.newServerBuilderForPort(port, serverCreds) 160 .maxInboundMessageSize(AbstractInteropTest.MAX_MESSAGE_SIZE) 161 .addService( 162 ServerInterceptors.intercept( 163 new TestServiceImpl(executor, metricRecorder), TestServiceImpl.interceptors())) 164 .addService(orcaOobService) 165 .intercept(OrcaMetricReportingServerInterceptor.create(metricRecorder)) 166 .build() 167 .start(); 168 } 169 170 @VisibleForTesting stop()171 void stop() throws Exception { 172 server.shutdownNow(); 173 if (!server.awaitTermination(5, TimeUnit.SECONDS)) { 174 System.err.println("Timed out waiting for server shutdown"); 175 } 176 MoreExecutors.shutdownAndAwaitTermination(executor, 5, TimeUnit.SECONDS); 177 } 178 179 @VisibleForTesting getPort()180 int getPort() { 181 return server.getPort(); 182 } 183 184 /** Await termination on the main thread since the grpc library uses daemon threads. */ blockUntilShutdown()185 private void blockUntilShutdown() throws InterruptedException { 186 if (server != null) { 187 server.awaitTermination(); 188 } 189 } 190 } 191