1 /* 2 * librdkafka - Apache Kafka C library 3 * 4 * Copyright (c) 2020, Magnus Edenhill 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright notice, 11 * this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright notice, 13 * this list of conditions and the following disclaimer in the documentation 14 * and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include "test.h" 30 31 #include "rdkafka.h" 32 33 /** 34 * @name Verify KIP-511, client.software.name and client.software.version 35 * 36 */ 37 static char jmx_cmd[512]; 38 39 /** 40 * @brief Verify that the expected software name and version is reported 41 * in JMX metrics. 42 */ 43 static void jmx_verify (const char *exp_swname, const char *exp_swversion) { 44 #if _WIN32 45 return; 46 #else 47 int r; 48 char cmd[512+256]; 49 50 if (!*jmx_cmd) 51 return; 52 53 rd_snprintf(cmd, sizeof(cmd), 54 "%s | " 55 "grep -F 'clientSoftwareName=%s,clientSoftwareVersion=%s'", 56 jmx_cmd, 57 exp_swname, exp_swversion ? exp_swversion : ""); 58 r = system(cmd); 59 if (WEXITSTATUS(r) == 1) 60 TEST_FAIL("Expected software name and version not found in " 61 "JMX metrics with command \"%s\"", cmd); 62 else if (r == -1 || WIFSIGNALED(r) || WEXITSTATUS(r)) 63 TEST_FAIL("Failed to execute JmxTool command \"%s\": " 64 "exit code %d", cmd, r); 65 66 TEST_SAY("Expected software name \"%s\" and version \"%s\" " 67 "found in JMX metrics\n", 68 exp_swname, exp_swversion); 69 #endif /* !_WIN32 */ 70 } 71 72 73 static void do_test_swname (const char *broker, 74 const char *swname, const char *swversion, 75 const char *exp_swname, const char *exp_swversion) { 76 rd_kafka_t *rk; 77 rd_kafka_conf_t *conf; 78 const rd_kafka_metadata_t *md; 79 rd_kafka_resp_err_t err; 80 81 TEST_SAY(_C_MAG "[ Test client.software.name=%s, " 82 "client.software.version=%s ]\n", 83 swname ? swname : "NULL", swversion ? swversion : "NULL"); 84 85 test_conf_init(&conf, NULL, 30 /* jmxtool is severely slow */); 86 if (broker) 87 test_conf_set(conf, "bootstrap.servers", broker); 88 if (swname) 89 test_conf_set(conf, "client.software.name", swname); 90 if (swversion) 91 test_conf_set(conf, "client.software.version", swversion); 92 rk = test_create_handle(RD_KAFKA_PRODUCER, conf); 93 94 /* Trigger a metadata request so we know we're connected. */ 95 err = rd_kafka_metadata(rk, 0, NULL, &md, tmout_multip(5000)); 96 TEST_ASSERT(!err, "metadata() failed: %s", rd_kafka_err2str(err)); 97 rd_kafka_metadata_destroy(md); 98 99 /* Verify JMX metrics, if possible */ 100 jmx_verify(exp_swname, exp_swversion); 101 102 rd_kafka_destroy(rk); 103 104 TEST_SAY(_C_GRN "[ Test client.software.name=%s, " 105 "client.software.version=%s: PASS ]\n", 106 swname ? swname : "NULL", swversion ? swversion : "NULL"); 107 } 108 109 int main_0016_client_swname (int argc, char **argv) { 110 const char *broker; 111 const char *kafka_path; 112 const char *jmx_port; 113 const char *reason = NULL; 114 115 /* If available, use the Kafka JmxTool to query software name 116 * in broker JMX metrics */ 117 if (!(broker = test_getenv("BROKER_ADDRESS_2", NULL))) 118 reason = "Env var BROKER_ADDRESS_2 missing " 119 "(not running in trivup or trivup too old?)"; 120 else if (test_broker_version < TEST_BRKVER(2,5,0,0)) 121 reason = "Client software JMX metrics not exposed prior to " 122 "Apache Kafka 2.5.0.0"; 123 else if (!(kafka_path = test_getenv("KAFKA_PATH", NULL))) 124 reason = "Env var KAFKA_PATH missing (not running in trivup?)"; 125 else if (!(jmx_port = test_getenv("BROKER_JMX_PORT_2", NULL))) 126 reason = "Env var BROKER_JMX_PORT_2 missing " 127 "(not running in trivup or trivup too old?)"; 128 else 129 rd_snprintf(jmx_cmd, sizeof(jmx_cmd), 130 "%s/bin/kafka-run-class.sh kafka.tools.JmxTool " 131 "--jmx-url " 132 "service:jmx:rmi:///jndi/rmi://:%s/jmxrmi " 133 "--attributes connections --one-time true | " 134 "grep clientSoftware", 135 kafka_path, jmx_port); 136 137 if (reason) 138 TEST_WARN("Will not be able to verify JMX metrics: %s\n", 139 reason); 140 141 /* Default values, the version is not checked since the 142 * built librdkafka may not use the same string, and additionally we 143 * don't want to perform the string mangling here to make the string 144 * protocol safe. */ 145 do_test_swname(broker, NULL, NULL, "librdkafka", NULL); 146 /* Properly formatted */ 147 do_test_swname(broker, 148 "my-little-version", "1.2.3.4", 149 "my-little-version", "1.2.3.4"); 150 /* Containing invalid characters, verify that safing the strings works */ 151 do_test_swname(broker, 152 "?1?this needs! ESCAPING?", "--v99.11 ~b~", 153 "1-this-needs--ESCAPING", "v99.11--b"); 154 155 return 0; 156 } 157 158