Add global.with-veth/with-ipv6 config defaults for -n/--network creation
Replaces --no-ipv6/--no-veth (plain flags) with --with-ipv6/--with-veth, each taking an explicit true/false value (e.g. --with-veth=false), parsed via the same parse_bool_flag() the config file itself already uses (now exported from config_file.h so cli_args.cpp can reuse it). create_network_command() now resolves ipv6/veth as CLI flag -> config's own global.with-ipv6/global.with-veth -> true, so a host that always wants the tap+relay fallback (or no IPv6) can set it once in the config instead of passing the flag on every network creation. -w/--write-config fills in both new keys like the existing six unshare-* bools.
This commit is contained in:
@@ -102,3 +102,26 @@ TEST_CASE("config file -> NamespaceConfig -> bwrap argv: default (unset) config
|
||||
CHECK(contains(argv, flag));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("config file -> AppConfig: global.with-veth/with-ipv6 round-trip", "[integration]") {
|
||||
ScratchXdgDirs scratch;
|
||||
auto config_path = scratch.path() / "config.yaml";
|
||||
|
||||
AppConfig written;
|
||||
written.with_veth = false;
|
||||
written.with_ipv6 = false;
|
||||
REQUIRE(write_config_file(config_path, written));
|
||||
|
||||
auto loaded = load_config_file(config_path);
|
||||
REQUIRE(loaded.has_value());
|
||||
CHECK(loaded->with_veth == std::optional<bool>(false));
|
||||
CHECK(loaded->with_ipv6 == std::optional<bool>(false));
|
||||
|
||||
// Same "unset means enabled" convention as the six unshare-* keys --
|
||||
// create_network_command()'s own resolution (commands.cpp) is
|
||||
// `args.network_with_*_flag.value_or(config.with_*.value_or(true))`.
|
||||
auto loaded_empty = load_config_file(scratch.path() / "nonexistent.yaml");
|
||||
REQUIRE(loaded_empty.has_value());
|
||||
CHECK_FALSE(loaded_empty->with_veth.has_value());
|
||||
CHECK_FALSE(loaded_empty->with_ipv6.has_value());
|
||||
}
|
||||
|
||||
@@ -171,6 +171,41 @@ TEST_CASE("parse_args: -v with -r accumulates volume_specs as (spec, container-p
|
||||
CHECK(result.args.volume_specs[0].second == "/data");
|
||||
}
|
||||
|
||||
TEST_CASE("parse_args: --with-ipv6/--with-veth accept true/false and default to unset", "[unit]") {
|
||||
auto plain = run_parse({"-n", "net1", "--extern"});
|
||||
REQUIRE_FALSE(plain.exit_code.has_value());
|
||||
CHECK_FALSE(plain.args.network_with_ipv6_flag.has_value());
|
||||
CHECK_FALSE(plain.args.network_with_veth_flag.has_value());
|
||||
|
||||
auto disabled = run_parse({"-n", "net1", "--extern", "--with-ipv6=false", "--with-veth=false"});
|
||||
REQUIRE_FALSE(disabled.exit_code.has_value());
|
||||
REQUIRE(disabled.args.network_with_ipv6_flag.has_value());
|
||||
CHECK(*disabled.args.network_with_ipv6_flag == false);
|
||||
REQUIRE(disabled.args.network_with_veth_flag.has_value());
|
||||
CHECK(*disabled.args.network_with_veth_flag == false);
|
||||
|
||||
// Same accepted forms as the config file itself (parse_bool_flag(),
|
||||
// config_file.h) -- not just a literal "true"/"false".
|
||||
auto on = run_parse({"-n", "net1", "--intern", "--with-ipv6=on", "--with-veth=1"});
|
||||
REQUIRE_FALSE(on.exit_code.has_value());
|
||||
REQUIRE(on.args.network_with_ipv6_flag.has_value());
|
||||
CHECK(*on.args.network_with_ipv6_flag == true);
|
||||
REQUIRE(on.args.network_with_veth_flag.has_value());
|
||||
CHECK(*on.args.network_with_veth_flag == true);
|
||||
}
|
||||
|
||||
TEST_CASE("parse_args: --with-ipv6 with an unrecognized value is a parse error", "[unit]") {
|
||||
auto result = run_parse({"-n", "net1", "--extern", "--with-ipv6=maybe"});
|
||||
REQUIRE(result.exit_code.has_value());
|
||||
CHECK(*result.exit_code == 1);
|
||||
}
|
||||
|
||||
TEST_CASE("parse_args: --subnet6 and --with-ipv6=false can't be used together", "[unit]") {
|
||||
auto result = run_parse({"-n", "net1", "--extern", "--subnet6", "fdf0::/64", "--with-ipv6=false"});
|
||||
REQUIRE(result.exit_code.has_value());
|
||||
CHECK(*result.exit_code == 1);
|
||||
}
|
||||
|
||||
TEST_CASE("parse_args: --kill requires a numeric pid", "[unit]") {
|
||||
auto ok = run_parse({"--kill", "5678"});
|
||||
REQUIRE_FALSE(ok.exit_code.has_value());
|
||||
|
||||
@@ -105,7 +105,7 @@ TEST_CASE("allocate_ipv6_subnet: skips a subnet already in use", "[unit]") {
|
||||
}
|
||||
|
||||
TEST_CASE("allocate_ipv6_subnet: an ipv6-disabled existing entry doesn't block reuse of its subnet6", "[unit]") {
|
||||
// A network created with --no-ipv6 has ipv6=false and an empty subnet6
|
||||
// A network created with --with-ipv6=false has ipv6=false and an empty subnet6
|
||||
// -- nothing to collide with, so this is really just confirming
|
||||
// allocate_ipv6_subnet() doesn't crash/misbehave on such an entry.
|
||||
std::vector<NetworkEntry> existing = {{"v4only", NetworkKind::extern_, "10.168.0.0/24", false, "", true}};
|
||||
|
||||
Reference in New Issue
Block a user