1# Copyright 2015 gRPC authors. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14"""The Python implementation of the GRPC interoperability test client.""" 15 16import argparse 17import os 18 19from google import auth as google_auth 20from google.auth import jwt as google_auth_jwt 21import grpc 22from src.proto.grpc.testing import test_pb2_grpc 23 24from tests.interop import methods 25from tests.interop import resources 26 27 28def parse_interop_client_args(): 29 parser = argparse.ArgumentParser() 30 parser.add_argument('--server_host', 31 default="localhost", 32 type=str, 33 help='the host to which to connect') 34 parser.add_argument('--server_port', 35 type=int, 36 required=True, 37 help='the port to which to connect') 38 parser.add_argument('--test_case', 39 default='large_unary', 40 type=str, 41 help='the test case to execute') 42 parser.add_argument('--use_tls', 43 default=False, 44 type=resources.parse_bool, 45 help='require a secure connection') 46 parser.add_argument('--use_alts', 47 default=False, 48 type=resources.parse_bool, 49 help='require an ALTS secure connection') 50 parser.add_argument('--use_test_ca', 51 default=False, 52 type=resources.parse_bool, 53 help='replace platform root CAs with ca.pem') 54 parser.add_argument('--custom_credentials_type', 55 choices=["compute_engine_channel_creds"], 56 default=None, 57 help='use google default credentials') 58 parser.add_argument('--server_host_override', 59 type=str, 60 help='the server host to which to claim to connect') 61 parser.add_argument('--oauth_scope', 62 type=str, 63 help='scope for OAuth tokens') 64 parser.add_argument('--default_service_account', 65 type=str, 66 help='email address of the default service account') 67 parser.add_argument( 68 "--grpc_test_use_grpclb_with_child_policy", 69 type=str, 70 help=( 71 "If non-empty, set a static service config on channels created by " 72 + "grpc::CreateTestChannel, that configures the grpclb LB policy " + 73 "with a child policy being the value of this flag (e.g. round_robin " 74 + "or pick_first).")) 75 return parser.parse_args() 76 77 78def _create_call_credentials(args): 79 if args.test_case == 'oauth2_auth_token': 80 google_credentials, unused_project_id = google_auth.default( 81 scopes=[args.oauth_scope]) 82 google_credentials.refresh(google_auth.transport.requests.Request()) 83 return grpc.access_token_call_credentials(google_credentials.token) 84 elif args.test_case == 'compute_engine_creds': 85 google_credentials, unused_project_id = google_auth.default( 86 scopes=[args.oauth_scope]) 87 return grpc.metadata_call_credentials( 88 google_auth.transport.grpc.AuthMetadataPlugin( 89 credentials=google_credentials, 90 request=google_auth.transport.requests.Request())) 91 elif args.test_case == 'jwt_token_creds': 92 google_credentials = google_auth_jwt.OnDemandCredentials.from_service_account_file( 93 os.environ[google_auth.environment_vars.CREDENTIALS]) 94 return grpc.metadata_call_credentials( 95 google_auth.transport.grpc.AuthMetadataPlugin( 96 credentials=google_credentials, request=None)) 97 else: 98 return None 99 100 101def get_secure_channel_parameters(args): 102 call_credentials = _create_call_credentials(args) 103 104 channel_opts = () 105 if args.grpc_test_use_grpclb_with_child_policy: 106 channel_opts += (( 107 "grpc.service_config", 108 '{"loadBalancingConfig": [{"grpclb": {"childPolicy": [{"%s": {}}]}}]}' 109 % args.grpc_test_use_grpclb_with_child_policy),) 110 if args.custom_credentials_type is not None: 111 if args.custom_credentials_type == "compute_engine_channel_creds": 112 assert call_credentials is None 113 google_credentials, unused_project_id = google_auth.default( 114 scopes=[args.oauth_scope]) 115 call_creds = grpc.metadata_call_credentials( 116 google_auth.transport.grpc.AuthMetadataPlugin( 117 credentials=google_credentials, 118 request=google_auth.transport.requests.Request())) 119 channel_credentials = grpc.compute_engine_channel_credentials( 120 call_creds) 121 else: 122 raise ValueError("Unknown credentials type '{}'".format( 123 args.custom_credentials_type)) 124 elif args.use_tls: 125 if args.use_test_ca: 126 root_certificates = resources.test_root_certificates() 127 else: 128 root_certificates = None # will load default roots. 129 130 channel_credentials = grpc.ssl_channel_credentials(root_certificates) 131 if call_credentials is not None: 132 channel_credentials = grpc.composite_channel_credentials( 133 channel_credentials, call_credentials) 134 135 if args.server_host_override: 136 channel_opts += (( 137 'grpc.ssl_target_name_override', 138 args.server_host_override, 139 ),) 140 elif args.use_alts: 141 channel_credentials = grpc.alts_channel_credentials() 142 143 return channel_credentials, channel_opts 144 145 146def _create_channel(args): 147 target = '{}:{}'.format(args.server_host, args.server_port) 148 149 if args.use_tls or args.use_alts or args.custom_credentials_type is not None: 150 channel_credentials, options = get_secure_channel_parameters(args) 151 return grpc.secure_channel(target, channel_credentials, options) 152 else: 153 return grpc.insecure_channel(target) 154 155 156def create_stub(channel, args): 157 if args.test_case == "unimplemented_service": 158 return test_pb2_grpc.UnimplementedServiceStub(channel) 159 else: 160 return test_pb2_grpc.TestServiceStub(channel) 161 162 163def _test_case_from_arg(test_case_arg): 164 for test_case in methods.TestCase: 165 if test_case_arg == test_case.value: 166 return test_case 167 else: 168 raise ValueError('No test case "%s"!' % test_case_arg) 169 170 171def test_interoperability(): 172 args = parse_interop_client_args() 173 channel = _create_channel(args) 174 stub = create_stub(channel, args) 175 test_case = _test_case_from_arg(args.test_case) 176 test_case.test_interoperability(stub, args) 177 178 179if __name__ == '__main__': 180 test_interoperability() 181