|
| 1 | +// Copyright 2025 Google LLC |
| 2 | +// |
| 3 | +// Use of this source code is governed by an MIT-style license that can be found |
| 4 | +// in the LICENSE file or at https://opensource.org/licenses/MIT. |
| 5 | + |
| 6 | +//! Developer command to run a Fleetspeakless one-shot RRG action. |
| 7 | +//! |
| 8 | +//! e.g. you may run an action as root with: |
| 9 | +//! ```text |
| 10 | +//! cargo build && (protoc --proto_path=proto/ --encode=rrg.Request proto/rrg.proto proto/rrg/action/*.proto | sudo -A ./target/debug/rrg_oneshot) <<EOF |
| 11 | +//! action: GET_FILESYSTEM_TIMELINE_TSK |
| 12 | +//! args { |
| 13 | +//! [type.googleapis.com/rrg.action.get_filesystem_timeline_tsk.Args] { |
| 14 | +//! root: { |
| 15 | +//! raw_bytes: "/mnt/foo/bar" |
| 16 | +//! } |
| 17 | +//! } |
| 18 | +//! } |
| 19 | +//! EOF |
| 20 | +//! ``` |
| 21 | +use protobuf::Message as _; |
| 22 | + |
| 23 | +struct OneshotSession { |
| 24 | + args: rrg::args::Args, |
| 25 | +} |
| 26 | + |
| 27 | +impl OneshotSession { |
| 28 | + /// Constructs a new fake session with test default agent arguments. |
| 29 | + pub fn new() -> Self { |
| 30 | + Self::with_args(rrg::args::Args { |
| 31 | + heartbeat_rate: std::time::Duration::from_secs(0), |
| 32 | + ping_rate: std::time::Duration::from_secs(0), |
| 33 | + command_verification_key: None, |
| 34 | + verbosity: log::LevelFilter::Debug, |
| 35 | + log_to_stdout: false, |
| 36 | + log_to_file: None, |
| 37 | + }) |
| 38 | + } |
| 39 | + |
| 40 | + /// Constructs a new fake session with the given agent arguments. |
| 41 | + pub fn with_args(args: rrg::args::Args) -> Self { |
| 42 | + Self { args } |
| 43 | + } |
| 44 | +} |
| 45 | + |
| 46 | +impl rrg::session::Session for OneshotSession { |
| 47 | + fn args(&self) -> &rrg::args::Args { |
| 48 | + &self.args |
| 49 | + } |
| 50 | + |
| 51 | + fn reply<I>(&mut self, item: I) -> rrg::session::Result<()> |
| 52 | + where |
| 53 | + I: rrg::Item + 'static, |
| 54 | + { |
| 55 | + println!( |
| 56 | + "Reply: {}", |
| 57 | + protobuf::text_format::print_to_string_pretty(&item.into_proto()) |
| 58 | + ); |
| 59 | + Ok(()) |
| 60 | + } |
| 61 | + |
| 62 | + fn send<I>(&mut self, sink: rrg::Sink, item: I) -> rrg::session::Result<()> |
| 63 | + where |
| 64 | + I: rrg::Item + 'static, |
| 65 | + { |
| 66 | + println!( |
| 67 | + "Sent to {sink:?}: {}", |
| 68 | + protobuf::text_format::print_to_string_pretty(&item.into_proto()) |
| 69 | + ); |
| 70 | + Ok(()) |
| 71 | + } |
| 72 | + |
| 73 | + fn heartbeat(&mut self) {} |
| 74 | +} |
| 75 | + |
| 76 | +fn main() { |
| 77 | + // rust-protobuf does not support Any in text or JSON formats, so we're |
| 78 | + // stuck taking in encoded protobufs. |
| 79 | + // See https://github.com/stepancheg/rust-protobuf/issues/628 |
| 80 | + let request_proto = rrg_proto::rrg::Request::parse_from_reader(&mut std::io::stdin()) |
| 81 | + .expect("Failed to parse request protobuf"); |
| 82 | + let request = rrg::Request::try_from(request_proto).expect("Failed to parse request"); |
| 83 | + let mut session = OneshotSession::new(); |
| 84 | + rrg::action::dispatch(&mut session, request).unwrap(); |
| 85 | +} |
0 commit comments