1 /* 2 * Copyright 2020 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.examples.helloworldxds; 18 19 import io.grpc.InsecureServerCredentials; 20 import io.grpc.Server; 21 import io.grpc.ServerCredentials; 22 import io.grpc.health.v1.HealthCheckResponse.ServingStatus; 23 import io.grpc.protobuf.services.ProtoReflectionService; 24 import io.grpc.services.HealthStatusManager; 25 import io.grpc.xds.XdsServerBuilder; 26 import io.grpc.xds.XdsServerCredentials; 27 import java.util.Arrays; 28 import java.io.IOException; 29 import java.util.concurrent.TimeUnit; 30 31 /** 32 * An xDS-managed Server for the {@code Greeter} service. 33 */ 34 public class XdsHelloWorldServer { main(String[] args)35 public static void main(String[] args) throws IOException, InterruptedException { 36 int port = 50051; 37 String hostname = null; 38 ServerCredentials credentials = InsecureServerCredentials.create(); 39 if (args.length >= 1 && "--xds-creds".equals(args[0])) { 40 // The xDS credentials use the security configured by the xDS server when available. When xDS 41 // is not used or when xDS does not provide security configuration, the xDS credentials fall 42 // back to other credentials (in this case, InsecureServerCredentials). 43 credentials = XdsServerCredentials.create(InsecureServerCredentials.create()); 44 args = Arrays.copyOfRange(args, 1, args.length); 45 } 46 if (args.length >= 1) { 47 try { 48 port = Integer.parseInt(args[0]); 49 } catch (NumberFormatException ex) { 50 System.err.println("Usage: [--xds-creds] [PORT [HOSTNAME]]"); 51 System.err.println(""); 52 System.err.println(" --xds-creds Use credentials provided by xDS. Defaults to insecure"); 53 System.err.println(""); 54 System.err.println(" PORT The listen port. Defaults to " + port); 55 System.err.println(" HOSTNAME The name clients will see in greet responses. "); 56 System.err.println(" Defaults to the machine's hostname"); 57 System.exit(1); 58 } 59 } 60 if (args.length >= 2) { 61 hostname = args[1]; 62 } 63 // Since the main server may be using TLS, we start a second server just for plaintext health 64 // checks 65 int healthPort = port + 1; 66 final HealthStatusManager health = new HealthStatusManager(); 67 final Server server = XdsServerBuilder.forPort(port, credentials) 68 .addService(new HostnameGreeter(hostname)) 69 .addService(ProtoReflectionService.newInstance()) // convenient for command line tools 70 .addService(health.getHealthService()) // allow management servers to monitor health 71 .build() 72 .start(); 73 final Server healthServer = 74 XdsServerBuilder.forPort(healthPort, InsecureServerCredentials.create()) 75 .addService(health.getHealthService()) // allow management servers to monitor health 76 .build() 77 .start(); 78 System.out.println("Listening on port " + port); 79 System.out.println("Plaintext health service listening on port " + healthPort); 80 Runtime.getRuntime().addShutdownHook(new Thread() { 81 @Override 82 public void run() { 83 health.setStatus("", ServingStatus.NOT_SERVING); 84 // Start graceful shutdown 85 server.shutdown(); 86 try { 87 // Wait for RPCs to complete processing 88 if (!server.awaitTermination(30, TimeUnit.SECONDS)) { 89 // That was plenty of time. Let's cancel the remaining RPCs 90 server.shutdownNow(); 91 // shutdownNow isn't instantaneous, so give a bit of time to clean resources up 92 // gracefully. Normally this will be well under a second. 93 server.awaitTermination(5, TimeUnit.SECONDS); 94 } 95 healthServer.shutdownNow(); 96 healthServer.awaitTermination(5, TimeUnit.SECONDS); 97 } catch (InterruptedException ex) { 98 server.shutdownNow(); 99 healthServer.shutdownNow(); 100 } 101 } 102 }); 103 // This would normally be tied to the service's dependencies. For example, if HostnameGreeter 104 // used a Channel to contact a required service, then when 'channel.getState() == 105 // TRANSIENT_FAILURE' we'd want to set NOT_SERVING. But HostnameGreeter has no dependencies, so 106 // hard-coding SERVING is appropriate. 107 health.setStatus("", ServingStatus.SERVING); 108 server.awaitTermination(); 109 } 110 } 111