1use clap::Subcommand;
2
3pub use output::*;
4use wash_lib::cli::{
5 get::{GetClaimsCommand, GetHostInventoriesCommand, GetHostsCommand},
6 link::LinkCommand,
7 scale::ScaleCommand,
8 start::StartCommand,
9 stop::StopCommand,
10 update::UpdateCommand,
11};
12
13mod output;
14
15#[derive(Debug, Clone, Subcommand)]
16pub enum CtlCliCommand {
17 #[clap(name = "get", subcommand)]
19 Get(CtlGetCommand),
20
21 #[clap(name = "link", alias = "links", subcommand)]
23 Link(LinkCommand),
24
25 #[clap(name = "start", subcommand)]
27 Start(StartCommand),
28
29 #[clap(name = "stop", subcommand)]
31 Stop(StopCommand),
32
33 #[clap(name = "update", subcommand)]
35 Update(UpdateCommand),
36
37 #[clap(name = "scale", subcommand)]
38 Scale(ScaleCommand),
39}
40
41#[derive(Debug, Clone, Subcommand)]
42pub enum CtlGetCommand {
43 #[clap(name = "hosts")]
45 Hosts(GetHostsCommand),
46
47 #[clap(name = "inventory")]
49 HostInventories(GetHostInventoriesCommand),
50
51 #[clap(name = "claims")]
53 Claims(GetClaimsCommand),
54}
55
56#[cfg(test)]
57mod test {
58 use clap::Parser;
59
60 use wash_lib::cli::{
61 get::GetHostsCommand,
62 scale::ScaleComponentCommand,
63 stop::{StopComponentCommand, StopProviderCommand},
64 update::UpdateComponentCommand,
65 };
66
67 use super::*;
68
69 #[derive(Parser)]
70 struct Cmd {
71 #[clap(subcommand)]
72 command: CtlCliCommand,
73 }
74
75 const CTL_HOST: &str = "127.0.0.1";
76 const CTL_PORT: &str = "4222";
77 const DEFAULT_LATTICE: &str = "default";
78 const JS_DOMAIN: &str = "custom-domain";
79
80 const COMPONENT_ID: &str = "MDPDJEYIAK6MACO67PRFGOSSLODBISK4SCEYDY3HEOY4P5CVJN6UCWUK";
81 const PROVIDER_ID: &str = "VBKTSBG2WKP6RJWLQ5O7RDVIIB4LMW6U5R67A7QMIDBZDGZWYTUE3TSI";
82 const HOST_ID: &str = "NCE7YHGI42RWEKBRDJZWXBEJJCFNE5YIWYMSTLGHQBEGFY55BKJ3EG3G";
83
84 #[test]
85 fn test_ctl_comprehensive() -> anyhow::Result<()> {
89 let stop_component_all: Cmd = Parser::try_parse_from([
90 "ctl",
91 "stop",
92 "component",
93 "--lattice",
94 DEFAULT_LATTICE,
95 "--ctl-host",
96 CTL_HOST,
97 "--ctl-port",
98 CTL_PORT,
99 "--timeout-ms",
100 "2001",
101 "--host-id",
102 HOST_ID,
103 COMPONENT_ID,
104 ])?;
105 match stop_component_all.command {
106 CtlCliCommand::Stop(StopCommand::Component(StopComponentCommand {
107 opts,
108 host_id,
109 component_id,
110 skip_wait,
111 })) => {
112 assert_eq!(&opts.ctl_host.unwrap(), CTL_HOST);
113 assert_eq!(&opts.ctl_port.unwrap(), CTL_PORT);
114 assert_eq!(&opts.lattice.unwrap(), DEFAULT_LATTICE);
115 assert_eq!(opts.timeout_ms, 2001);
116 assert_eq!(host_id, Some(HOST_ID.to_string()));
117 assert_eq!(component_id, COMPONENT_ID);
118 assert!(!skip_wait);
119 }
120 cmd => panic!("ctl stop component constructed incorrect command {cmd:?}"),
121 }
122 let stop_component_minimal: Cmd =
123 Parser::try_parse_from(["ctl", "stop", "component", "foobar"])?;
124 match stop_component_minimal.command {
125 CtlCliCommand::Stop(StopCommand::Component(StopComponentCommand {
126 host_id,
127 component_id,
128 ..
129 })) => {
130 assert_eq!(host_id, None);
131 assert_eq!(component_id, "foobar");
132 }
133 cmd => panic!("ctl stop component constructed incorrect command {cmd:?}"),
134 }
135 let stop_provider_all: Cmd = Parser::try_parse_from([
136 "ctl",
137 "stop",
138 "provider",
139 "--lattice",
140 DEFAULT_LATTICE,
141 "--ctl-host",
142 CTL_HOST,
143 "--ctl-port",
144 CTL_PORT,
145 "--timeout-ms",
146 "2001",
147 "--host-id",
148 HOST_ID,
149 PROVIDER_ID,
150 ])?;
151 match stop_provider_all.command {
152 CtlCliCommand::Stop(StopCommand::Provider(StopProviderCommand {
153 opts,
154 host_id,
155 provider_id,
156 skip_wait,
157 })) => {
158 assert_eq!(&opts.ctl_host.unwrap(), CTL_HOST);
159 assert_eq!(&opts.ctl_port.unwrap(), CTL_PORT);
160 assert_eq!(&opts.lattice.unwrap(), DEFAULT_LATTICE);
161 assert_eq!(opts.timeout_ms, 2001);
162 assert_eq!(host_id, Some(HOST_ID.to_string()));
163 assert_eq!(provider_id, PROVIDER_ID);
164 assert!(!skip_wait);
165 }
166 cmd => panic!("ctl stop component constructed incorrect command {cmd:?}"),
167 }
168 let stop_provider_minimal: Cmd =
169 Parser::try_parse_from(["ctl", "stop", "provider", "foobar"])?;
170 match stop_provider_minimal.command {
171 CtlCliCommand::Stop(StopCommand::Provider(StopProviderCommand {
172 host_id,
173 provider_id,
174 ..
175 })) => {
176 assert_eq!(host_id, None);
177 assert_eq!(provider_id, "foobar");
178 }
179 cmd => panic!("ctl stop component constructed incorrect command {cmd:?}"),
180 }
181 let get_hosts_all: Cmd = Parser::try_parse_from([
182 "ctl",
183 "get",
184 "hosts",
185 "--lattice",
186 DEFAULT_LATTICE,
187 "--ctl-host",
188 CTL_HOST,
189 "--ctl-port",
190 CTL_PORT,
191 "--timeout-ms",
192 "2001",
193 ])?;
194 match get_hosts_all.command {
195 CtlCliCommand::Get(CtlGetCommand::Hosts(GetHostsCommand { opts })) => {
196 assert_eq!(&opts.ctl_host.unwrap(), CTL_HOST);
197 assert_eq!(&opts.ctl_port.unwrap(), CTL_PORT);
198 assert_eq!(&opts.lattice.unwrap(), DEFAULT_LATTICE);
199 assert_eq!(opts.timeout_ms, 2001);
200 }
201 cmd => panic!("ctl get hosts constructed incorrect command {cmd:?}"),
202 }
203 let get_host_inventory_all: Cmd = Parser::try_parse_from([
204 "ctl",
205 "get",
206 "inventory",
207 "--lattice",
208 DEFAULT_LATTICE,
209 "--ctl-host",
210 CTL_HOST,
211 "--ctl-port",
212 CTL_PORT,
213 "--timeout-ms",
214 "2001",
215 HOST_ID,
216 ])?;
217 match get_host_inventory_all.command {
218 CtlCliCommand::Get(CtlGetCommand::HostInventories(GetHostInventoriesCommand {
219 opts,
220 host_id,
221 watch: _,
222 })) => {
223 assert_eq!(&opts.ctl_host.unwrap(), CTL_HOST);
224 assert_eq!(&opts.ctl_port.unwrap(), CTL_PORT);
225 assert_eq!(&opts.lattice.unwrap(), DEFAULT_LATTICE);
226 assert_eq!(opts.timeout_ms, 2001);
227 assert_eq!(host_id.unwrap(), HOST_ID.parse()?);
228 }
229 cmd => panic!("ctl get inventory constructed incorrect command {cmd:?}"),
230 }
231 let get_claims_all: Cmd = Parser::try_parse_from([
232 "ctl",
233 "get",
234 "claims",
235 "--lattice",
236 DEFAULT_LATTICE,
237 "--ctl-host",
238 CTL_HOST,
239 "--ctl-port",
240 CTL_PORT,
241 "--timeout-ms",
242 "2001",
243 "--js-domain",
244 JS_DOMAIN,
245 ])?;
246 match get_claims_all.command {
247 CtlCliCommand::Get(CtlGetCommand::Claims(GetClaimsCommand { opts })) => {
248 assert_eq!(&opts.ctl_host.unwrap(), CTL_HOST);
249 assert_eq!(&opts.ctl_port.unwrap(), CTL_PORT);
250 assert_eq!(&opts.lattice.unwrap(), DEFAULT_LATTICE);
251 assert_eq!(opts.timeout_ms, 2001);
252 assert_eq!(opts.js_domain.unwrap(), JS_DOMAIN);
253 }
254 cmd => panic!("ctl get claims constructed incorrect command {cmd:?}"),
255 }
256 let link_all: Cmd = Parser::try_parse_from([
257 "ctl",
258 "link",
259 "put",
260 "--lattice",
261 DEFAULT_LATTICE,
262 "--ctl-host",
263 CTL_HOST,
264 "--ctl-port",
265 CTL_PORT,
266 "--timeout-ms",
267 "2001",
268 "--link-name",
269 "notdefault",
270 COMPONENT_ID,
271 PROVIDER_ID,
272 "wasmcloud",
273 "provider",
274 "--interface",
275 "foo",
276 ])?;
277 use wash_lib::cli::link::LinkPutCommand;
278 match link_all.command {
279 CtlCliCommand::Link(LinkCommand::Put(LinkPutCommand {
280 opts,
281 source_id,
282 target,
283 wit_namespace,
284 wit_package,
285 interfaces,
286 source_config,
287 target_config,
288 link_name,
289 })) => {
290 assert_eq!(&opts.ctl_host.unwrap(), CTL_HOST);
291 assert_eq!(&opts.ctl_port.unwrap(), CTL_PORT);
292 assert_eq!(&opts.lattice.unwrap(), DEFAULT_LATTICE);
293 assert_eq!(opts.timeout_ms, 2001);
294 assert_eq!(source_id, COMPONENT_ID);
295 assert_eq!(target, PROVIDER_ID);
296 assert_eq!(wit_namespace, "wasmcloud".to_string());
297 assert_eq!(wit_package, "provider".to_string());
298 assert_eq!(link_name.unwrap(), "notdefault".to_string());
299 assert_eq!(interfaces.as_slice(), &["foo".to_string()]);
300 assert!(source_config.is_empty());
301 assert!(target_config.is_empty());
302 }
303 cmd => panic!("ctl link put constructed incorrect command {cmd:?}"),
304 }
305 let update_all: Cmd = Parser::try_parse_from([
306 "ctl",
307 "update",
308 "component",
309 "--lattice",
310 DEFAULT_LATTICE,
311 "--ctl-host",
312 CTL_HOST,
313 "--ctl-port",
314 CTL_PORT,
315 "--timeout-ms",
316 "2001",
317 "--host-id",
318 HOST_ID,
319 COMPONENT_ID,
320 "wasmcloud.azurecr.io/component:v2",
321 ])?;
322 match update_all.command {
323 CtlCliCommand::Update(UpdateCommand::Component(UpdateComponentCommand {
324 opts,
325 host_id,
326 component_id,
327 new_component_ref,
328 })) => {
329 assert_eq!(&opts.ctl_host.unwrap(), CTL_HOST);
330 assert_eq!(&opts.ctl_port.unwrap(), CTL_PORT);
331 assert_eq!(&opts.lattice.unwrap(), DEFAULT_LATTICE);
332 assert_eq!(opts.timeout_ms, 2001);
333 assert_eq!(host_id, Some(HOST_ID.to_string()));
334 assert_eq!(component_id, COMPONENT_ID);
335 assert_eq!(
336 new_component_ref,
337 "wasmcloud.azurecr.io/component:v2".to_string()
338 );
339 }
340 cmd => panic!("ctl get claims constructed incorrect command {cmd:?}"),
341 }
342
343 let scale_component_all: Cmd = Parser::try_parse_from([
344 "ctl",
345 "scale",
346 "component",
347 "--lattice",
348 DEFAULT_LATTICE,
349 "--ctl-host",
350 CTL_HOST,
351 "--ctl-port",
352 CTL_PORT,
353 "--timeout-ms",
354 "2001",
355 HOST_ID,
356 "wasmcloud.azurecr.io/component:v2",
357 "mycomponentv2",
358 "--count",
359 "1",
360 "--annotations",
361 "foo=bar",
362 "--config",
363 "default-port",
364 "--config",
365 "lang",
366 ])?;
367
368 match scale_component_all.command {
369 CtlCliCommand::Scale(ScaleCommand::Component(ScaleComponentCommand {
370 opts,
371 host_id,
372 component_ref,
373 component_id,
374 max_instances,
375 annotations,
376 config,
377 skip_wait,
378 wait_timeout_ms,
379 })) => {
380 assert_eq!(&opts.ctl_host.unwrap(), CTL_HOST);
381 assert_eq!(&opts.ctl_port.unwrap(), CTL_PORT);
382 assert_eq!(&opts.lattice.unwrap(), DEFAULT_LATTICE);
383 assert_eq!(opts.timeout_ms, 2001);
384 assert_eq!(host_id, HOST_ID);
385 assert_eq!(
386 component_ref,
387 "wasmcloud.azurecr.io/component:v2".to_string()
388 );
389 assert_eq!(component_id, "mycomponentv2".to_string());
390 assert_eq!(max_instances, 1);
391 assert_eq!(annotations, vec!["foo=bar".to_string()]);
392 assert_eq!(config, vec!["default-port", "lang"]);
393 assert!(!skip_wait);
394 assert_eq!(wait_timeout_ms, 5000);
395 }
396 cmd => panic!("ctl scale component constructed incorrect command {cmd:?}"),
397 }
398
399 Ok(())
400 }
401}