Skip to content

Commit

Permalink
system networking allow-list cli (#658)
Browse files Browse the repository at this point in the history
  • Loading branch information
ahl authored May 6, 2024
1 parent e3a8c97 commit 247b205
Show file tree
Hide file tree
Showing 13 changed files with 1,219 additions and 8 deletions.
29 changes: 29 additions & 0 deletions cli/docs/cli.json
Original file line number Diff line number Diff line change
Expand Up @@ -3088,6 +3088,35 @@
}
]
},
{
"name": "allow-list",
"subcommands": [
{
"name": "update",
"about": "Update user-facing services IP allowlist",
"args": [
{
"long": "any"
},
{
"long": "ip"
},
{
"long": "json-body",
"help": "Path to a file that contains the full json body."
},
{
"long": "json-body-template",
"help": "XXX"
}
]
},
{
"name": "view",
"about": "Get user-facing services IP allowlist"
}
]
},
{
"name": "bfd",
"subcommands": [
Expand Down
25 changes: 25 additions & 0 deletions cli/src/cli_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,28 @@ impl<'a> Default for NewCli<'a> {
.multiple(false),
),

CliCommand::NetworkingAllowListUpdate => cmd
.mut_arg("json-body", |arg| arg.required(false))
.arg(
clap::Arg::new("any")
.long("any")
.action(clap::ArgAction::SetTrue)
.value_parser(clap::value_parser!(bool)),
)
.arg(
clap::Arg::new("ips")
.long("ip")
.action(clap::ArgAction::Append)
.value_name("IP or IPNET")
.value_parser(clap::value_parser!(crate::IpOrNet)),
)
.group(
clap::ArgGroup::new("allow-list")
.args(["ips", "any"])
.required(true)
.multiple(false),
),

// Command is fine as-is.
_ => cmd,
};
Expand Down Expand Up @@ -467,6 +489,9 @@ fn xxx<'a>(command: CliCommand) -> Option<&'a str> {
CliCommand::SystemPolicyView => Some("system policy view"),
CliCommand::SystemPolicyUpdate => Some("system policy update"),

CliCommand::NetworkingAllowListView => Some("system networking allow-list view"),
CliCommand::NetworkingAllowListUpdate => Some("system networking allow-list update"),

CliCommand::CurrentUserView => Some("current-user view"),
CliCommand::CurrentUserGroups => Some("current-user groups"),
CliCommand::CurrentUserSshKeyList => Some("current-user ssh-key list"),
Expand Down
97 changes: 97 additions & 0 deletions cli/src/generated_cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,8 @@ impl<T: CliConfig> Cli<T> {
CliCommand::NetworkingAddressLotBlockList => {
Self::cli_networking_address_lot_block_list()
}
CliCommand::NetworkingAllowListView => Self::cli_networking_allow_list_view(),
CliCommand::NetworkingAllowListUpdate => Self::cli_networking_allow_list_update(),
CliCommand::NetworkingBfdDisable => Self::cli_networking_bfd_disable(),
CliCommand::NetworkingBfdEnable => Self::cli_networking_bfd_enable(),
CliCommand::NetworkingBfdStatus => Self::cli_networking_bfd_status(),
Expand Down Expand Up @@ -3953,6 +3955,29 @@ impl<T: CliConfig> Cli<T> {
.about("List blocks in address lot")
}

pub fn cli_networking_allow_list_view() -> clap::Command {
clap::Command::new("").about("Get user-facing services IP allowlist")
}

pub fn cli_networking_allow_list_update() -> clap::Command {
clap::Command::new("")
.arg(
clap::Arg::new("json-body")
.long("json-body")
.value_name("JSON-FILE")
.required(true)
.value_parser(clap::value_parser!(std::path::PathBuf))
.help("Path to a file that contains the full json body."),
)
.arg(
clap::Arg::new("json-body-template")
.long("json-body-template")
.action(clap::ArgAction::SetTrue)
.help("XXX"),
)
.about("Update user-facing services IP allowlist")
}

pub fn cli_networking_bfd_disable() -> clap::Command {
clap::Command::new("")
.arg(
Expand Down Expand Up @@ -5689,6 +5714,12 @@ impl<T: CliConfig> Cli<T> {
self.execute_networking_address_lot_block_list(matches)
.await
}
CliCommand::NetworkingAllowListView => {
self.execute_networking_allow_list_view(matches).await
}
CliCommand::NetworkingAllowListUpdate => {
self.execute_networking_allow_list_update(matches).await
}
CliCommand::NetworkingBfdDisable => self.execute_networking_bfd_disable(matches).await,
CliCommand::NetworkingBfdEnable => self.execute_networking_bfd_enable(matches).await,
CliCommand::NetworkingBfdStatus => self.execute_networking_bfd_status(matches).await,
Expand Down Expand Up @@ -10021,6 +10052,52 @@ impl<T: CliConfig> Cli<T> {
}
}

pub async fn execute_networking_allow_list_view(
&self,
matches: &clap::ArgMatches,
) -> anyhow::Result<()> {
let mut request = self.client.networking_allow_list_view();
self.config
.execute_networking_allow_list_view(matches, &mut request)?;
let result = request.send().await;
match result {
Ok(r) => {
self.config.item_success(&r);
Ok(())
}
Err(r) => {
self.config.item_error(&r);
Err(anyhow::Error::new(r))
}
}
}

pub async fn execute_networking_allow_list_update(
&self,
matches: &clap::ArgMatches,
) -> anyhow::Result<()> {
let mut request = self.client.networking_allow_list_update();
if let Some(value) = matches.get_one::<std::path::PathBuf>("json-body") {
let body_txt = std::fs::read_to_string(value).unwrap();
let body_value = serde_json::from_str::<types::AllowListUpdate>(&body_txt).unwrap();
request = request.body(body_value);
}

self.config
.execute_networking_allow_list_update(matches, &mut request)?;
let result = request.send().await;
match result {
Ok(r) => {
self.config.item_success(&r);
Ok(())
}
Err(r) => {
self.config.item_error(&r);
Err(anyhow::Error::new(r))
}
}
}

pub async fn execute_networking_bfd_disable(
&self,
matches: &clap::ArgMatches,
Expand Down Expand Up @@ -12901,6 +12978,22 @@ pub trait CliConfig {
Ok(())
}

fn execute_networking_allow_list_view(
&self,
matches: &clap::ArgMatches,
request: &mut builder::NetworkingAllowListView,
) -> anyhow::Result<()> {
Ok(())
}

fn execute_networking_allow_list_update(
&self,
matches: &clap::ArgMatches,
request: &mut builder::NetworkingAllowListUpdate,
) -> anyhow::Result<()> {
Ok(())
}

fn execute_networking_bfd_disable(
&self,
matches: &clap::ArgMatches,
Expand Down Expand Up @@ -13480,6 +13573,8 @@ pub enum CliCommand {
NetworkingAddressLotCreate,
NetworkingAddressLotDelete,
NetworkingAddressLotBlockList,
NetworkingAllowListView,
NetworkingAllowListUpdate,
NetworkingBfdDisable,
NetworkingBfdEnable,
NetworkingBfdStatus,
Expand Down Expand Up @@ -13669,6 +13764,8 @@ impl CliCommand {
CliCommand::NetworkingAddressLotCreate,
CliCommand::NetworkingAddressLotDelete,
CliCommand::NetworkingAddressLotBlockList,
CliCommand::NetworkingAllowListView,
CliCommand::NetworkingAllowListUpdate,
CliCommand::NetworkingBfdDisable,
CliCommand::NetworkingBfdEnable,
CliCommand::NetworkingBfdStatus,
Expand Down
81 changes: 80 additions & 1 deletion cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use async_trait::async_trait;
use cli_builder::NewCli;
use generated_cli::CliConfig;
use oxide::context::Context;
use oxide::types::{IdpMetadataSource, IpRange, Ipv4Range, Ipv6Range};
use oxide::types::{AllowedSourceIps, IdpMetadataSource, IpRange, Ipv4Range, Ipv6Range};

mod cli_builder;
mod cmd_api;
Expand Down Expand Up @@ -215,6 +215,36 @@ impl CliConfig for OxideOverride {
}
Ok(())
}

fn execute_networking_allow_list_update(
&self,
matches: &clap::ArgMatches,
request: &mut oxide::builder::NetworkingAllowListUpdate,
) -> anyhow::Result<()> {
match matches
.get_one::<clap::Id>("allow-list")
.map(clap::Id::as_str)
{
Some("any") => {
let value = matches.get_one::<bool>("any").unwrap();
assert!(value);
*request = request
.to_owned()
.body_map(|body| body.allowed_ips(AllowedSourceIps::Any));
}
Some("ips") => {
let values: Vec<IpOrNet> = matches.get_many("ips").unwrap().cloned().collect();
*request = request.to_owned().body_map(|body| {
body.allowed_ips(AllowedSourceIps::List(
values.into_iter().map(IpOrNet::into_ip_net).collect(),
))
});
}
_ => unreachable!("invalid value for allow-list group"),
}

Ok(())
}
}

#[cfg(test)]
Expand Down Expand Up @@ -313,3 +343,52 @@ mod tests {
assert_contents("tests/data/json-body-required.txt", &out);
}
}

#[derive(Debug, Clone)]
pub(crate) enum IpOrNet {
Ip(std::net::IpAddr),
Net(oxide::types::IpNet),
}

#[derive(Clone, Debug)]
pub(crate) struct IpOrNetParser;
impl clap::builder::TypedValueParser for IpOrNetParser {
type Value = IpOrNet;

fn parse_ref(
&self,
cmd: &clap::Command,
arg: Option<&clap::Arg>,
value: &std::ffi::OsStr,
) -> std::prelude::v1::Result<Self::Value, clap::Error> {
fn parse(value: &str) -> Result<IpOrNet, String> {
if let Ok(ip) = value.parse() {
Ok(IpOrNet::Ip(ip))
} else if let Ok(net) = value.parse() {
Ok(IpOrNet::Net(net))
} else {
Err("value must be an IP address or subnet".to_string())
}
}

parse.parse_ref(cmd, arg, value)
}
}

impl clap::builder::ValueParserFactory for IpOrNet {
type Parser = IpOrNetParser;

fn value_parser() -> Self::Parser {
IpOrNetParser
}
}

impl IpOrNet {
pub fn into_ip_net(self) -> oxide::types::IpNet {
match self {
IpOrNet::Ip(std::net::IpAddr::V4(v4)) => format!("{}/32", v4).parse().unwrap(),
IpOrNet::Ip(std::net::IpAddr::V6(v6)) => format!("{}/128", v6).parse().unwrap(),
IpOrNet::Net(net) => net,
}
}
}
7 changes: 7 additions & 0 deletions cli/tests/data/test_system_networking_allowlist_any.stdout
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"allowed_ips": {
"allow": "any"
},
"time_created": "2018-11-14T19:07:30Z",
"time_modified": "2018-11-14T19:07:30Z"
}
5 changes: 5 additions & 0 deletions cli/tests/data/test_system_networking_allowlist_both.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
error: the argument '--any' cannot be used with '--ip <IP or IPNET>'

Usage: oxide system networking allow-list update <--ip <IP or IPNET>|--any>

For more information, try '--help'.
14 changes: 14 additions & 0 deletions cli/tests/data/test_system_networking_allowlist_many_ips.stdout
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"allowed_ips": {
"allow": "list",
"ips": [
"1.2.3.4/5",
"5.6.7.8/9",
"1.0.0.1/32",
"::1/127",
"::1/128"
]
},
"time_created": "2018-11-14T19:07:30Z",
"time_modified": "2018-11-14T19:07:30Z"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
error: the following required arguments were not provided:
<--ip <IP or IPNET>|--any>

Usage: oxide system networking allow-list update <--ip <IP or IPNET>|--any>

For more information, try '--help'.
10 changes: 10 additions & 0 deletions cli/tests/data/test_system_networking_allowlist_one_ip.stdout
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"allowed_ips": {
"allow": "list",
"ips": [
"1.2.3.4/5"
]
},
"time_created": "2018-11-14T19:07:30Z",
"time_modified": "2018-11-14T19:07:30Z"
}
Loading

0 comments on commit 247b205

Please sign in to comment.