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