diff --git a/README.md b/README.md index b0cc25e..4ca901c 100644 --- a/README.md +++ b/README.md @@ -11,90 +11,36 @@ A command line utility to talk to a tchannel server. ``` -tcurl [-H | -p host:port] [options] - - Version: 4.14.0 - - Options: - --head (-2) [data] JSON or raw - --body (-3) [data] JSON or raw - (JSON promoted to Thrift via IDL when applicable) - --shardKey send ringpop shardKey transport header - --depth=n configure inspect printing depth - --thrift (-t) [dir] directory containing Thrift files - --no-strict parse Thrift loosely - --json (-j) Use JSON argument scheme - (default unless endpoint has ::) - --http method - --raw encode arg2 & arg3 raw - --health - --timeout [num] +usage: tcurl [OPTIONS] service endpoint + +Options: + -h --help Show detailed manpage + -v --version Print version + -H --hostlist Path to hostlist file + -p --peer IP and port of single peer + -t --thrift Path to thrift IDL file + -2 --head Set header to + -3 --body Set body to + --http Use HTTP instead of TCP + --health Print health for + --raw Send header and body as binary diaray + --shardKey Send Ringpop shardKey transport header + --no-strict Parse thrift IDL files loosely + --timeout Set a timeout value in milliseconds ``` [Click here for full usage docs.](usage.md) ## Installation -`npm install tcurl` - -## Examples - -### Thrift - -For the purposes of these examples, let's assume that you have a TChannel -server listening on `localhost:1234`. The server registers handlers for the -thrift interface saved as `services/chamber.thrift` and defined as: - -```thrift -struct EchoRequest { - 1: required string input; -} - -service Chamber { - string echo( - 1: required EchoRequest request; - ) -} -``` - -You could use TCurl to query this service by running: - -``` -tcurl -p localhost:1234 chamber Chamber::echo -t ./services -3 '{"request": {"input": "foo"}}' -``` - -## `localhost` caveat - -For TChannel and Hyperbahn to work together effectively, most tchannel services need to listen on the -external IP of the host they are running on. - -This means when you use `127.0.0.1` you cannot reach the service with tcurl as it's not listening on -loopback. - -To make supporting external IPs easier we've made `localhost` resolve to the external IP of the machine. -This means if your listening on loopback you have to use `127.0.0.1` and not `localhost` - -## Exit Codes - - - 0: for all successful requests - - 1: timeout - - 2: cancelled - - 3: busy - - 4: declined - - 5: unexpected error - - 6: bad request - - 7: network error - - 8: unhealthy (broken circuit) - - 124: unhealthy / not OK thrift response - - 125: misc tcurl / tchannel internal error - - 126: response not ok error - - 127: fatal protocol error +`npm install tcurl --global` ## NPM scripts - `npm run add-licence` This will add the licence headers. - `npm run cover` This runs the tests with code coverage - `npm run lint` This will run the linter on your code + - `npm run man` This will build the manpage. - `npm test` This will run the tests. - `npm run trace` This will run your tests in tracing mode. - `npm run travis` This is run by travis.CI to run your tests @@ -105,6 +51,7 @@ This means if your listening on loopback you have to use `127.0.0.1` and not `lo - Raynos - ShanniLi - kriskowal + - malandrew ## MIT Licenced diff --git a/index.js b/index.js index 5845fca..ef1813f 100755 --- a/index.js +++ b/index.js @@ -96,7 +96,7 @@ function main(argv, delegate) { if (conf.help) { return printFullHelp(); } else if (conf.h || conf._.length === 0) { - return help(); + return help(conf.helpUrl); } var opts = parseArgs(conf); @@ -128,11 +128,29 @@ main.exec = function execMain(str, delegate) { main(str, delegate); }; -function help() { - console.log('usage: tcurl [--help] [-v | --version] [-H] [-p] [-t]'); - console.log(' [-2 | --arg2 | --head] [-3 | --arg3 | --body]'); - console.log(' [--shardKey] [--no-strict] [--timeout]'); - console.log(' [--http] [--raw] [--health]'); +function help(helpUrl) { + console.log('usage: tcurl [OPTIONS] service endpoint'); + console.log(''); + console.log('Options:'); + console.log(' -h --help Show detailed manpage'); + console.log(' -v --version Print version'); + console.log(' -H --hostlist Path to hostlist file'); + console.log(' -p --peer IP and port of single peer'); + console.log(' -t --thrift Path to thrift IDL file'); + console.log(' -2 --head Set header to '); + console.log(' -3 --body Set body to '); + console.log(' --http Use HTTP instead of TCP'); + console.log(' --health Print health for '); + console.log(' --raw Send header and body as binary diaray') + console.log(' --shardKey Send Ringpop shardKey transport header'); + console.log(' --no-strict Parse thrift IDL files loosely'); + console.log(' --timeout Set a timeout value in milliseconds'); + if (typeof helpUrl === 'string' && helpUrl.length > 0) { + console.log(''); + console.log('More information on how tcurl is used by your'); + console.log('organization can be found at:'); + console.log(helpUrl); + } } function printFullHelp() { diff --git a/man/tcurl.1 b/man/tcurl.1 index c76471b..90b79e7 100644 --- a/man/tcurl.1 +++ b/man/tcurl.1 @@ -1,40 +1,82 @@ -.TH "TCURL" "1" "October 2015" "v4.15.0" "tcurl" +.TH "TCURL" "1" "October 2015" "v4.15.1" "tcurl" .SH "NAME" \fBtcurl\fR \- curl for tchannel .SH SYNOPSIS .P -\fBtcurl\fP [\-\-help] [\-v | \-\-version] [\-H] [\-p] [\-t] - [\-2 | \-\-arg2 | \-\-head] [\-3 | \-\-arg3 | \-\-body] - [\-\-shardKey] [\-\-no\-strict] [\-\-timeout] - [\-\-http] [\-\-raw] [\-\-health] +tcurl [OPTIONS] service endpoint +.P +Options: + \-h \-\-help Show detailed manpage + \-v \-\-version Print version + \-H \-\-hostlist Path to hostlist file + \-p \-\-peer IP and port of single peer + \-t \-\-thrift Path to thrift IDL file + \-2 \-\-head Set header to + \-3 \-\-body Set body to + \-\-http Use HTTP instead of TCP + \-\-health Print health for + \-\-raw Send header and body as binary diaray + \-\-shardKey Send Ringpop shardKey transport header + \-\-no\-strict Parse thrift IDL files loosely + \-\-timeout Set a timeout value in milliseconds .SH DESCRIPTION .P -\fBtcurl\fP is a tool for constructing and sending requests to -a tchannel service\. It supports thrift, JSON, and raw request format\. +\fBtcurl\fP is a tool for constructing and sending requests to a tchannel service\. +It supports Thrift, JSON, and raw request format\. .SH EXAMPLES .RS 0 .IP \(bu 2 \fBtcurl \-p localhost:8080 serviceName \-\-health\fP .IP \(bu 2 -\fBtcurl \-p 127\.0\.0\.1:21300 hyperbahn Hyperbahn::discover \-t \./hyperbahn\.thrift \-3 '{"query":{"serviceName":"ringpop"}}'\fP -.IP \(bu 2 \fBtcurl \-p localhost:8080 serviceName endpoint \-\-raw \-3 'message'\fP +.IP \(bu 2 +\fBtcurl \-p 127\.0\.0\.1:21300 hyperbahn Hyperbahn::discover \-t \./hyperbahn\.thrift \-3 '{"query":{"serviceName":"ringpop"}}'\fP + +.RE +.P +The following is an example thrift file for the thrift example command above: +.P +.RS 2 +.nf +``` +struct Query { + 1: required string serviceName; +} +service Hyperbahn { + string discover( + 1: required Query query; + ) +} +``` +.fi .RE .SH OPTIONS .P \fB\-v | \-\-version\fP Print the current version\. .P -\fB\-p host:port serviceName [endpoint]\fP - Specify the destination where the request should be sent to - including the host, the port, the serviceName, and the endpoint\. - When used with \-\-health, endpoint is not required\. +\fB\-p | \-\-peer host:port serviceName \fP + Specify the destination where the request should be sent to including the + host, the port, the serviceName, and the endpoint\. When used with \-\-health, + endpoint is not required\. .P -\fB\-H host\-file serviceName [endpoint]\fP +\fB\-H | \-\-hostfile \fP Similar to the \fB\-p\fP option\. Instead of the host:port, it takes a host\-file that contains a list of host:port where this request can be sent to\. - TChannel will only pick one host:port to send the request to\. + TChannel will only pick one host:port to send the request to\. An example + hostfile with two hyperbahn hosts: +.P +.RS 2 +.nf +``` +[ + "127\.0\.0\.1:21300", + "127\.0\.0\.1:21301" +] +``` +.fi +.RE .P \fB\-\-health\fP Send a health check request to a sevice that implements the "Meta::health" @@ -83,9 +125,9 @@ service Hyperbahn { .fi .RE .P -\fB\-t thrift\fP - Used with the thrift encoding to specify the path to the thrift files\. - The thrift option value can either point to a file or a directory\. +\fB\-t | \-\-thrift \fP + Used with the thrift encoding to specify the path to the thrift files\. The + thrift option value can either point to a file or a directory\. For example: .P .RS 2 @@ -93,13 +135,18 @@ service Hyperbahn { ``` tcurl \-p 127\.0\.0\.1:21300 serviceName Meta::health \-t \. \-3 null ``` -The above command assumes that current folder contains the meta\.thrift IDL file\. +The above command assumes that current folder contains the meta\.thrift IDL +file\. The endpoint specified at the command line should be defined in the +specified thrift file\. Using the example immediatly above, the following +would be a valid request: +``` +tcurl hyperbahn Hyperbahn::DiscoveryResult \-\-body '{ "serviceName": "ringpop" }' `\-\-thrift \./idl/hyperbahn\.thrift .fi .RE .P \fB\-\-no\-strict\fP - Disable the default strict mode of thrift parsing\. When strict mode is enabled, - all fields must be specified as either "required" or "optional"\. + Disable the default strict mode of thrift parsing\. When strict mode is + enabled, all fields must be specified as either "required" or "optional"\. .P \fB\-\-raw\fP Use raw format (i\.e\. plain text) for request\. @@ -117,7 +164,7 @@ tcurl \-p 127\.0\.0\.1:21300 echoServer '/echo' \-\-http 'POST' \-\-head '{"Acce .RE .P \fB\-\-timeout value\fP - Specify the maximum time in miniseconds this request can take + Specify the maximum time in milliseconds this request can take until it timeout\. For example, the following command specifies a timeout value of one second: @@ -132,6 +179,57 @@ tcurl \-p 127\.0\.0\.1:8080 serviceName endpoint \-\-timeout 1000 .P \fB\-\-shardKey\fP Ringpop only\. Send ringpop shardKey transport header\. +.P +\fB\-\-config\fP + Path to a JSON or ini\-style configuration file with values for any + of the configurable keys above\. +.P +\fB\-\-helpUrl\fP + A url string that is printed along with usage information\. This feature + exists for organizations using tcurl, tchannel and hyperbahn to provide a + URL to a help document specific to how they use tcurl\. This option should + not be specified as a command line flag and should instead be specified + in a tcurlrc file\. +.SH CONFIGURATION +.P +\fBtcurl\fP supports getting its configuration from command line arguments, +environment variables and tcurlrc files (in that order)\. +.P +The command line options are listed above\. Environment variables should +be prefixed with TCURL_ and the key in UPPER_SNAKE_CASE\. e\.g\. +.P +.RS 2 +.nf +``` +TCURL_HOSTFILE=/path/to/hostfile\.json +TCURL_NO_STRICT=true +``` +.fi +.RE +.P +After giving precedence to command line arguments and environment +variables it will probe the following JSON or ini\-style configuration +files in order of highest precedence to lowest\. +.RS 0 +.IP \(bu 2 +a tcurlrc specified with the \-\-config flag\. +.IP \(bu 2 +a local \.tcurlrc in the current working directory or the first one +found looking in \./ \.\./ \.\./\.\./ \.\./\.\./\.\./ etc\. +.IP \(bu 2 +$HOME/\.tcurlrc +.IP \(bu 2 +$HOME/\.tcurl/config +.IP \(bu 2 +$HOME/\.config/tcurl +.IP \(bu 2 +$HOME/\.config/tcurl/config +.IP \(bu 2 +/etc/tcurlrc +.IP \(bu 2 +/etc/tcurl/config + +.RE .SH EXIT CODES .RS 0 .IP \(bu 2 @@ -162,6 +260,18 @@ tcurl \-p 127\.0\.0\.1:8080 serviceName endpoint \-\-timeout 1000 \fB127: fatal protocol error\fP .RE +.SH \fBlocalhost\fP caveat +.P +For TChannel and Hyperbahn to work together effectively, most tchannel +services need to listen on the external IP of the host they are running +on\. +.P +This means when you use \fB127\.0\.0\.1\fP you cannot reach the service with +tcurl as it's not listening on loopback\. +.P +To make supporting external IPs easier we've made \fBlocalhost\fP resolve +to the external IP of the machine\. This means if your listening on +loopback you have to use \fB127\.0\.0\.1\fP and not \fBlocalhost\fP .SH BUGS .P Please report any bugs to https://github\.com/uber/tcurl diff --git a/usage.md b/usage.md index 4adbc78..fb929af 100644 --- a/usage.md +++ b/usage.md @@ -2,36 +2,69 @@ ## SYNOPSIS -`tcurl` [--help] [-v | --version] [-H] [-p] [-t] - [-2 | --arg2 | --head] [-3 | --arg3 | --body] - [--shardKey] [--no-strict] [--timeout] - [--http] [--raw] [--health] +tcurl [OPTIONS] service endpoint + +Options: + -h --help Show detailed manpage + -v --version Print version + -H --hostlist Path to hostlist file + -p --peer IP and port of single peer + -t --thrift Path to thrift IDL file + -2 --head Set header to + -3 --body Set body to + --http Use HTTP instead of TCP + --health Print health for + --raw Send header and body as binary diaray + --shardKey Send Ringpop shardKey transport header + --no-strict Parse thrift IDL files loosely + --timeout Set a timeout value in milliseconds ## DESCRIPTION -`tcurl` is a tool for constructing and sending requests to -a tchannel service. It supports thrift, JSON, and raw request format. +`tcurl` is a tool for constructing and sending requests to a tchannel service. +It supports Thrift, JSON, and raw request format. ## EXAMPLES - `tcurl -p localhost:8080 serviceName --health` - - `tcurl -p 127.0.0.1:21300 hyperbahn Hyperbahn::discover -t ./hyperbahn.thrift -3 '{"query":{"serviceName":"ringpop"}}'` - `tcurl -p localhost:8080 serviceName endpoint --raw -3 'message'` + - `tcurl -p 127.0.0.1:21300 hyperbahn Hyperbahn::discover -t ./hyperbahn.thrift -3 '{"query":{"serviceName":"ringpop"}}'` + +The following is an example thrift file for the thrift example command above: + + ``` + struct Query { + 1: required string serviceName; + } + + service Hyperbahn { + string discover( + 1: required Query query; + ) + } + ``` ## OPTIONS `-v | --version` Print the current version. -`-p host:port serviceName [endpoint]` - Specify the destination where the request should be sent to - including the host, the port, the serviceName, and the endpoint. - When used with --health, endpoint is not required. +`-p | --peer host:port serviceName ` + Specify the destination where the request should be sent to including the + host, the port, the serviceName, and the endpoint. When used with --health, + endpoint is not required. -`-H host-file serviceName [endpoint]` +`-H | --hostfile ` Similar to the `-p` option. Instead of the host:port, it takes a host-file that contains a list of host:port where this request can be sent to. - TChannel will only pick one host:port to send the request to. + TChannel will only pick one host:port to send the request to. An example + hostfile with two hyperbahn hosts: + ``` + [ + "127.0.0.1:21300", + "127.0.0.1:21301" + ] + ``` `--health` Send a health check request to a sevice that implements the "Meta::health" @@ -71,18 +104,23 @@ a tchannel service. It supports thrift, JSON, and raw request format. } ``` -`-t thrift` - Used with the thrift encoding to specify the path to the thrift files. - The thrift option value can either point to a file or a directory. +`-t | --thrift ` + Used with the thrift encoding to specify the path to the thrift files. The + thrift option value can either point to a file or a directory. For example: ``` tcurl -p 127.0.0.1:21300 serviceName Meta::health -t . -3 null ``` - The above command assumes that current folder contains the meta.thrift IDL file. + The above command assumes that current folder contains the meta.thrift IDL + file. The endpoint specified at the command line should be defined in the + specified thrift file. Using the example immediatly above, the following + would be a valid request: + ``` + tcurl hyperbahn Hyperbahn::DiscoveryResult --body '{ "serviceName": "ringpop" }' `--thrift ./idl/hyperbahn.thrift `--no-strict` - Disable the default strict mode of thrift parsing. When strict mode is enabled, - all fields must be specified as either "required" or "optional". + Disable the default strict mode of thrift parsing. When strict mode is + enabled, all fields must be specified as either "required" or "optional". `--raw` Use raw format (i.e. plain text) for request. @@ -95,7 +133,7 @@ a tchannel service. It supports thrift, JSON, and raw request format. ``` `--timeout value` - Specify the maximum time in miniseconds this request can take + Specify the maximum time in milliseconds this request can take until it timeout. For example, the following command specifies a timeout value of one second: @@ -106,6 +144,41 @@ a tchannel service. It supports thrift, JSON, and raw request format. `--shardKey` Ringpop only. Send ringpop shardKey transport header. +`--config` + Path to a JSON or ini-style configuration file with values for any + of the configurable keys above. + +`--helpUrl` + A url string that is printed along with usage information. This feature + exists for organizations using tcurl, tchannel and hyperbahn to provide a + URL to a help document specific to how they use tcurl. This option should + not be specified as a command line flag and should instead be specified + in a tcurlrc file. + +## CONFIGURATION + +`tcurl` supports getting its configuration from command line arguments, +environment variables and tcurlrc files (in that order). + +The command line options are listed above. Environment variables should +be prefixed with TCURL_ and the key in UPPER_SNAKE_CASE. e.g. + ``` + TCURL_HOSTFILE=/path/to/hostfile.json + TCURL_NO_STRICT=true + ``` + +After giving precedence to command line arguments and environment +variables it will probe the following JSON or ini-style configuration +files in order of highest precedence to lowest. + - a tcurlrc specified with the --config flag. + - a local .tcurlrc in the current working directory or the first one + found looking in ./ ../ ../../ ../../../ etc. + - $HOME/.tcurlrc + - $HOME/.tcurl/config + - $HOME/.config/tcurl + - $HOME/.config/tcurl/config + - /etc/tcurlrc + - /etc/tcurl/config ## EXIT CODES - `0: for all successful requests` @@ -122,6 +195,18 @@ a tchannel service. It supports thrift, JSON, and raw request format. - `126: response not ok error` - `127: fatal protocol error` +## `localhost` caveat + +For TChannel and Hyperbahn to work together effectively, most tchannel +services need to listen on the external IP of the host they are running +on. + +This means when you use `127.0.0.1` you cannot reach the service with +tcurl as it's not listening on loopback. + +To make supporting external IPs easier we've made `localhost` resolve +to the external IP of the machine. This means if your listening on +loopback you have to use `127.0.0.1` and not `localhost` ## BUGS