1use std::net::SocketAddr;
4
5use clap::builder::ValueParser;
6use clap::{Arg, ArgAction, ArgGroup, Command, ValueHint};
7use clap_complete::Shell;
8
9pub const VERSION: &str = env!("CARGO_PKG_VERSION");
10pub const ABOUT: &str = "The official Sentry Relay.";
11
12pub fn make_app() -> Command {
13 Command::new("relay")
14 .disable_help_subcommand(true)
15 .subcommand_required(true)
16 .propagate_version(true)
17 .max_term_width(79)
18 .version(VERSION)
19 .about(ABOUT)
20 .arg(
21 Arg::new("config")
22 .long("config")
23 .short('c')
24 .global(true)
25 .value_hint(ValueHint::DirPath)
26 .value_parser(ValueParser::path_buf())
27 .help("The path to the config folder."),
28 )
29 .subcommand(
30 Command::new("run")
31 .about("Run the relay")
32 .after_help(
33 "This runs the relay in the foreground until it's shut down. It will bind \
34 to the port and network interface configured in the config file.",
35 )
36 .arg(
37 Arg::new("mode")
38 .long("mode")
39 .help("The relay mode to set")
40 .value_parser(["managed", "proxy", "static"]),
41 )
42 .arg(
43 Arg::new("log_level")
44 .long("log-level")
45 .help("The relay log level")
46 .value_parser(["info", "warn", "error", "debug", "trace"]),
47 )
48 .arg(
49 Arg::new("log_format")
50 .long("log-format")
51 .help("The relay log format")
52 .value_parser(["auto", "pretty", "simplified", "json"]),
53 )
54 .arg(
55 Arg::new("secret_key")
56 .long("secret-key")
57 .short('s')
58 .requires("public_key")
59 .help("The secret key to set"),
60 )
61 .arg(
62 Arg::new("public_key")
63 .long("public-key")
64 .short('p')
65 .requires("secret_key")
66 .help("The public key to set"),
67 )
68 .arg(
69 Arg::new("id")
70 .long("id")
71 .short('i')
72 .help("The relay ID to set"),
73 )
74 .arg(
75 Arg::new("upstream")
76 .value_name("url")
77 .value_hint(ValueHint::Url)
78 .short('u')
79 .long("upstream")
80 .help("The upstream server URL."),
81 )
82 .arg(
83 Arg::new("upstream_dsn")
84 .value_name("dsn")
85 .long("upstream-dsn")
86 .conflicts_with("upstream")
87 .help(
88 "Alternate upstream provided through a Sentry DSN, compatible with the \
89 SENTRY_DSN environment variable. Key and project of the DSN will be \
90 ignored.",
91 ),
92 )
93 .arg(
94 Arg::new("host")
95 .value_name("HOST")
96 .short('H')
97 .long("host")
98 .help("The host dns name."),
99 )
100 .arg(
101 Arg::new("port")
102 .value_name("PORT")
103 .short('P')
104 .long("port")
105 .help("The server port."),
106 )
107 .arg(
108 Arg::new("processing")
109 .long("processing")
110 .help("Enable processing.")
111 .action(ArgAction::SetTrue),
112 )
113 .arg(
114 Arg::new("no_processing")
115 .long("no-processing")
116 .help("Disable processing.")
117 .action(ArgAction::SetTrue),
118 )
119 .group(
120 ArgGroup::new("processing_group")
121 .args(["processing", "no_processing"])
122 .multiple(false),
123 )
124 .arg(
125 Arg::new("kafka_broker_url")
126 .value_name("url")
127 .value_hint(ValueHint::Url)
128 .long("kafka-broker-url")
129 .help("Kafka broker URL."),
130 )
131 .arg(
132 Arg::new("redis_url")
133 .value_name("url")
134 .value_hint(ValueHint::Url)
135 .long("redis-url")
136 .help("Redis server URL."),
137 )
138 .arg(
139 Arg::new("source_id")
140 .long("source-id")
141 .env("RELAY_SOURCE_ID")
142 .help("Names the current relay in the outcome source."),
143 )
144 .arg(
145 Arg::new("shutdown_timeout")
146 .value_name("seconds")
147 .long("shutdown-timeout")
148 .help(
149 "Maximum number of seconds to wait for pending envelopes on shutdown.",
150 ),
151 )
152 .arg(
153 Arg::new("instance")
154 .long("instance")
155 .help("The instance type of this Relay."),
156 )
157 .arg(
158 Arg::new("server_name")
159 .long("server-name")
160 .help("The server name reported to Sentry."),
161 ),
162 )
163 .subcommand(
164 Command::new("credentials")
165 .subcommand_required(true)
166 .about("Manage the relay credentials")
167 .after_help(
168 "This command can be used to manage the stored credentials of \
169 the relay. These credentials are used to authenticate with the \
170 upstream sentry. A sentry organization trusts a certain public \
171 key and each relay is identified with a unique relay ID.\n\
172 \n\
173 Multiple relays can share the same public/secret key pair for as \
174 long as they use different relay IDs. Once a relay (as identified \
175 by the ID) has signed in with a certain key it cannot be changed \
176 any more.",
177 )
178 .subcommand(
179 Command::new("generate")
180 .about("Generate new credentials")
181 .after_help(
182 "This generates new credentials for the relay and stores \
183 them. In case the relay already has credentials stored \
184 this command will error unless the '--overwrite' option \
185 has been passed.",
186 )
187 .arg(
188 Arg::new("overwrite")
189 .long("overwrite")
190 .action(ArgAction::SetTrue)
191 .help("Overwrite already existing credentials instead of failing"),
192 )
193 .arg(
194 Arg::new("stdout")
195 .long("stdout")
196 .action(ArgAction::SetTrue)
197 .help("Write credentials to stdout instead of credentials.json"),
198 ),
199 )
200 .subcommand(
201 Command::new("remove")
202 .about("Remove credentials")
203 .after_help(
204 "This command removes already stored credentials from the \
205 relay.",
206 )
207 .arg(
208 Arg::new("yes")
209 .long("yes")
210 .action(ArgAction::SetTrue)
211 .help("Do not prompt for confirmation"),
212 ),
213 )
214 .subcommand(
215 Command::new("show")
216 .about("Show currently stored credentials.")
217 .after_help("This prints out the agent ID and public key."),
218 )
219 .subcommand(
220 Command::new("set")
221 .about("Set new credentials")
222 .after_help(
223 "Credentials can be stored by providing them on the command \
224 line. If just an agent id (or secret/public key pair) is \
225 provided that part of the credentials are overwritten. If \
226 no credentials are stored yet at all and no parameters are \
227 supplied the command will prompt for the appropriate values.",
228 )
229 .arg(
230 Arg::new("mode")
231 .long("mode")
232 .help("The relay mode to set")
233 .value_parser(["managed", "proxy", "static"]),
234 )
235 .arg(
236 Arg::new("secret_key")
237 .long("secret-key")
238 .short('s')
239 .requires("public_key")
240 .help("The secret key to set"),
241 )
242 .arg(
243 Arg::new("public_key")
244 .long("public-key")
245 .short('p')
246 .requires("secret_key")
247 .help("The public key to set"),
248 )
249 .arg(
250 Arg::new("id")
251 .long("id")
252 .short('i')
253 .help("The relay ID to set"),
254 ),
255 ),
256 )
257 .subcommand(
258 Command::new("config")
259 .about("Manage the relay config")
260 .after_help(
261 "This command provides basic config management. It can be \
262 used primarily to initialize a new relay config and to \
263 print out the current config.",
264 )
265 .subcommand_required(true)
266 .subcommand(
267 Command::new("init")
268 .about("Initialize a new relay config")
269 .after_help(
270 "For new relay installations this will guide through \
271 the initial config process and create the necessary \
272 files. It will create an initial config as well as \
273 set of credentials.",
274 ),
275 )
276 .subcommand(
277 Command::new("show")
278 .about("Show the entire config out for debugging purposes")
279 .after_help(
280 "This dumps out the entire config including the values \
281 which are not in the config file but filled in from \
282 defaults. The default output format is YAML but \
283 a debug format can also be specific which is useful \
284 to understand how the relay interprets the individual \
285 values.",
286 )
287 .arg(
288 Arg::new("format")
289 .short('f')
290 .long("format")
291 .value_parser(["debug", "yaml"])
292 .default_value("yaml")
293 .help("The output format"),
294 ),
295 ),
296 )
297 .subcommand(
298 Command::new("generate-completions")
299 .about("Generate shell completion file")
300 .after_help(
301 "This generates a completions file for the shell of choice. \
302 The default selection will be an educated guess for the currently \
303 running shell.",
304 )
305 .arg(
306 Arg::new("format")
307 .short('f')
308 .long("format")
309 .value_name("SHELL")
310 .value_parser(clap::value_parser!(Shell))
311 .help(
312 "Explicitly pick the shell to generate a completion file \
313 for. The default is autodetection.",
314 ),
315 ),
316 )
317 .subcommand(
318 Command::new("healthcheck")
319 .about("Check the health of the relay")
320 .after_help(
321 "This command checks the health of the relay. It will create \
322 HTTP request to relay's healthcheck endpoints.",
323 )
324 .arg(
325 Arg::new("mode")
326 .long("mode")
327 .help("The relay health check status to check. Possible values are `live` and `ready`.")
328 .default_value("live")
329 .value_parser(clap::builder::PossibleValuesParser::new(["live", "ready"]))
330 .required(false),
331 )
332 .arg(
333 Arg::new("timeout")
334 .long("timeout")
335 .help("The timeout in seconds to wait for the healthcheck")
336 .default_value("30")
337 .value_parser(clap::value_parser!(u64))
338 .required(false),
339 )
340 .arg(
341 Arg::new("addr")
342 .long("addr")
343 .help("Address where Relay is running. Defaults to the Relay configuration.")
344 .value_parser(clap::value_parser!(SocketAddr))
345 .required(false),
346 )
347 )
348}