14 """Channelz debugging tool for xDS test client/server.
16 This is intended as a debugging / local development helper and not executed
17 as a part of interop test suites.
19 Typical usage examples:
21 # Show channel and server socket pair
22 python -m bin.run_channelz --flagfile=config/local-dev.cfg
24 # Evaluate setup for different security configurations
25 python -m bin.run_channelz --flagfile=config/local-dev.cfg --security=tls
26 python -m bin.run_channelz --flagfile=config/local-dev.cfg --security=mtls_error
28 # More information and usage options
29 python -m bin.run_channelz --helpfull
35 from absl
import flags
37 from framework
import xds_flags
38 from framework
import xds_k8s_flags
44 logger = logging.getLogger(__name__)
46 _SERVER_RPC_HOST = flags.DEFINE_string(
'server_rpc_host',
48 help=
'Server RPC host')
49 _CLIENT_RPC_HOST = flags.DEFINE_string(
'client_rpc_host',
51 help=
'Client RPC host')
52 _SECURITY = flags.DEFINE_enum(
'security',
55 'mtls',
'tls',
'plaintext',
'mtls_error',
58 help=
'Show info for a security setup')
59 flags.adopt_module_key_flags(xds_flags)
60 flags.adopt_module_key_flags(xds_k8s_flags)
62 flags.mark_flag_as_required(
"resource_suffix")
65 _Channel = grpc_channelz.Channel
66 _Socket = grpc_channelz.Socket
67 _ChannelState = grpc_channelz.ChannelState
68 _XdsTestServer = server_app.XdsTestServer
69 _XdsTestClient = client_app.XdsTestClient
75 sha1 = hashlib.sha1(cert)
76 return f
'sha1={sha1.hexdigest()}, len={len(cert)}'
80 return (f
'local: {debug_cert(tls.local_certificate)}\n'
81 f
'remote: {debug_cert(tls.remote_certificate)}')
85 deployment = k8s_ns.get_deployment(deployment_name)
86 pods = k8s_ns.list_deployment_pods(deployment)
87 return [pod.status.pod_ip
for pod
in pods]
91 """Debug negative cases: mTLS Error, Server AuthZ error
93 1) mTLS Error: Server expects client mTLS cert,
94 but client configured only for TLS.
95 2) AuthZ error: Client does not authorize server because of mismatched
99 client_correct_setup =
True
100 channel: _Channel = test_client.wait_for_server_channel_state(
101 state=_ChannelState.TRANSIENT_FAILURE)
103 subchannel, *subchannels = list(
104 test_client.channelz.list_channel_subchannels(channel))
106 print(
"Client setup fail: subchannel not found. "
107 "Common causes: test client didn't connect to TD; "
108 "test client exhausted retries, and closed all subchannels.")
112 logger.debug(
'Found subchannel, %s', subchannel)
114 client_correct_setup =
False
115 print(f
'Unexpected subchannels {subchannels}')
116 subchannel_state: _ChannelState = subchannel.data.state.state
117 if subchannel_state
is not _ChannelState.TRANSIENT_FAILURE:
118 client_correct_setup =
False
119 print(
'Subchannel expected to be in '
120 'TRANSIENT_FAILURE, same as its channel')
123 sockets = list(test_client.channelz.list_subchannels_sockets(subchannel))
125 client_correct_setup =
False
126 print(f
'Unexpected subchannel sockets {sockets}')
129 if client_correct_setup:
130 print(
'Client setup pass: the channel '
131 'to the server has exactly one subchannel '
132 'in TRANSIENT_FAILURE, and no sockets')
136 """Debug positive cases: mTLS, TLS, Plaintext."""
137 test_client.wait_for_active_server_channel()
138 client_sock: _Socket = test_client.get_active_server_channel_socket()
139 server_sock: _Socket = test_server.get_server_socket_matching_client(
142 server_tls = server_sock.security.tls
143 client_tls = client_sock.security.tls
145 print(f
'\nServer certs:\n{debug_sock_tls(server_tls)}')
146 print(f
'\nClient certs:\n{debug_sock_tls(client_tls)}')
149 if server_tls.local_certificate:
150 eq = server_tls.local_certificate == client_tls.remote_certificate
151 print(f
'(TLS) Server local matches client remote: {eq}')
153 print(
'(TLS) Not detected')
155 if server_tls.remote_certificate:
156 eq = server_tls.remote_certificate == client_tls.local_certificate
157 print(f
'(mTLS) Server remote matches client local: {eq}')
159 print(
'(mTLS) Not detected')
163 """Show channel and server socket pair"""
164 test_client.wait_for_active_server_channel()
165 client_sock: _Socket = test_client.get_active_server_channel_socket()
166 server_sock: _Socket = test_server.get_server_socket_matching_client(
169 print(f
'Client socket:\n{client_sock}\n')
170 print(f
'Matching server:\n{server_sock}\n')
175 raise app.UsageError(
'Too many command-line arguments.')
177 k8s_api_manager = k8s.KubernetesApiManager(xds_k8s_flags.KUBE_CONTEXT.value)
180 resource_prefix: str = xds_flags.RESOURCE_PREFIX.value
183 server_name = xds_flags.SERVER_NAME.value
184 server_namespace = resource_prefix
185 server_k8s_ns = k8s.KubernetesNamespace(k8s_api_manager, server_namespace)
189 rpc_port=xds_flags.SERVER_PORT.value,
190 xds_host=xds_flags.SERVER_XDS_HOST.value,
191 xds_port=xds_flags.SERVER_XDS_PORT.value,
192 rpc_host=_SERVER_RPC_HOST.value)
195 client_name = xds_flags.CLIENT_NAME.value
196 client_namespace = resource_prefix
197 client_k8s_ns = k8s.KubernetesNamespace(k8s_api_manager, client_namespace)
201 server_target=test_server.xds_uri,
202 rpc_port=xds_flags.CLIENT_PORT.value,
203 rpc_host=_CLIENT_RPC_HOST.value)
205 if _SECURITY.value
in (
'mtls',
'tls',
'plaintext'):
207 elif _SECURITY.value == (
'mtls_error',
'server_authz_error'):
216 if __name__ ==
'__main__':