1
0
mirror of https://github.com/systemd/systemd.git synced 2024-12-22 17:35:35 +03:00

Merge pull request #12160 from yuwata/wait-online-allow-configuring

wait-online: add --any option
This commit is contained in:
Yu Watanabe 2019-04-02 06:10:36 +09:00 committed by GitHub
commit dd09a9ec0f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 96 additions and 35 deletions

View File

@ -35,8 +35,9 @@
configured. By default, it will wait for all links it is aware of
and which are managed by
<citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
to be fully configured or failed, and for at least one link to
gain a carrier.</para>
to be fully configured or failed, and for at least one link to be online. Here, online means that
the link's operational state is equal or higher than <literal>degraded</literal>. The threshold
can be configured by <option>--operational-state=</option> option.</para>
</refsect1>
<refsect1>
@ -49,13 +50,12 @@
<term><option>-i</option> <replaceable>INTERFACE</replaceable><optional>:<replaceable>OPERSTATE</replaceable></optional></term>
<term><option>--interface=</option><replaceable>INTERFACE</replaceable><optional>:<replaceable>OPERSTATE</replaceable></optional></term>
<listitem><para>Network interface to wait for before deciding
if the system is online. This is useful when a system has
several interfaces which will be configured, but a particular
one is necessary to access some network resources. This option
may be used more than once to wait for multiple network
interfaces. When used, all other interfaces are ignored.
Optinally, required minimum operational state can be
<listitem><para>Network interface to wait for before deciding if the system is online. This
is useful when a system has several interfaces which will be configured, but a particular
one is necessary to access some network resources. When used, all other interfaces are ignored.
This option may be used more than once to wait for multiple network interfaces. When this
option is specified multiple times, then <command>systemd-networkd-wait-online</command> waits
for all specified interfaces to be online. Optinally, required minimum operational state can be
specified after a colon <literal>:</literal>. Please see
<citerefentry><refentrytitle>networkctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
for possible operational states. If the operational state is not specified here, then
@ -81,7 +81,18 @@
<citerefentry><refentrytitle>networkctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
for possible operational states. If set, the specified value overrides
<varname>RequiredForOnline=</varname> settings in <filename>.network</filename> files.
But this does not override operational states specified in <option>--interface</option> option.
But this does not override operational states specified in <option>--interface=</option> option.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--any</option></term>
<listitem><para>Even if several interfaces are in configuring state,
<command>systemd-networkd-wait-online</command> exits with success when at least one interface
becomes online. When this option is specified with <option>--interface=</option>, then
<command>systemd-networkd-wait-online</command> waits for one of the specified interfaces to be
online. This option is useful when some interfaces may not have carrier on boot.
</para></listitem>
</varlistentry>

View File

@ -59,7 +59,7 @@ static int manager_link_is_online(Manager *m, Link *l, LinkOperationalState s) {
return 1;
}
bool manager_all_configured(Manager *m) {
bool manager_configured(Manager *m) {
bool one_ready = false;
Iterator i;
const char *ifname;
@ -67,24 +67,33 @@ bool manager_all_configured(Manager *m) {
Link *l;
int r;
/* wait for all the links given on the command line to appear */
HASHMAP_FOREACH_KEY(p, ifname, m->interfaces, i) {
LinkOperationalState s = PTR_TO_INT(p);
if (!hashmap_isempty(m->interfaces)) {
/* wait for all the links given on the command line to appear */
HASHMAP_FOREACH_KEY(p, ifname, m->interfaces, i) {
LinkOperationalState s = PTR_TO_INT(p);
l = hashmap_get(m->links_by_name, ifname);
if (!l) {
log_debug("still waiting for %s", ifname);
return false;
l = hashmap_get(m->links_by_name, ifname);
if (!l) {
log_debug("still waiting for %s", ifname);
if (!m->any)
return false;
continue;
}
if (manager_link_is_online(m, l, s) <= 0) {
if (!m->any)
return false;
continue;
}
one_ready = true;
}
if (manager_link_is_online(m, l, s) <= 0)
return false;
/* all interfaces given by the command line are online, or
* one of the specified interfaces is online. */
return one_ready;
}
if (!hashmap_isempty(m->interfaces))
/* all interfaces given by the command line are online. */
return true;
/* wait for all links networkd manages to be in admin state 'configured'
* and at least one link to gain a carrier */
HASHMAP_FOREACH(l, m->links, i) {
@ -94,7 +103,7 @@ bool manager_all_configured(Manager *m) {
}
r = manager_link_is_online(m, l, _LINK_OPERSTATE_INVALID);
if (r < 0)
if (r < 0 && !m->any)
return false;
if (r > 0)
/* we wait for at least one link to be ready,
@ -180,7 +189,7 @@ static int on_rtnl_event(sd_netlink *rtnl, sd_netlink_message *mm, void *userdat
if (r < 0)
return r;
if (manager_all_configured(m))
if (manager_configured(m))
sd_event_exit(m->event, 0);
return 1;
@ -248,7 +257,7 @@ static int on_network_event(sd_event_source *s, int fd, uint32_t revents, void *
log_link_warning_errno(l, r, "Failed to update monitor information: %m");
}
if (manager_all_configured(m))
if (manager_configured(m))
sd_event_exit(m->event, 0);
return 0;
@ -280,7 +289,8 @@ static int manager_network_monitor_listen(Manager *m) {
}
int manager_new(Manager **ret, Hashmap *interfaces, char **ignore,
LinkOperationalState required_operstate, usec_t timeout) {
LinkOperationalState required_operstate,
bool any, usec_t timeout) {
_cleanup_(manager_freep) Manager *m = NULL;
int r;
@ -294,6 +304,7 @@ int manager_new(Manager **ret, Hashmap *interfaces, char **ignore,
.interfaces = interfaces,
.ignore = ignore,
.required_operstate = required_operstate,
.any = any,
};
r = sd_event_default(&m->event);

View File

@ -21,6 +21,7 @@ struct Manager {
char **ignore;
LinkOperationalState required_operstate;
bool any;
sd_netlink *rtnl;
sd_event_source *rtnl_event_source;
@ -33,8 +34,9 @@ struct Manager {
void manager_free(Manager *m);
int manager_new(Manager **ret, Hashmap *interfaces, char **ignore,
LinkOperationalState required_operstate, usec_t timeout);
LinkOperationalState required_operstate,
bool any, usec_t timeout);
DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
bool manager_all_configured(Manager *m);
bool manager_configured(Manager *m);

View File

@ -19,6 +19,7 @@ static usec_t arg_timeout = 120 * USEC_PER_SEC;
static Hashmap *arg_interfaces = NULL;
static char **arg_ignore = NULL;
static LinkOperationalState arg_required_operstate = _LINK_OPERSTATE_INVALID;
static bool arg_any = false;
STATIC_DESTRUCTOR_REGISTER(arg_interfaces, hashmap_free_free_keyp);
STATIC_DESTRUCTOR_REGISTER(arg_ignore, strv_freep);
@ -41,6 +42,7 @@ static int help(void) {
" --ignore=INTERFACE Don't take these interfaces into account\n"
" -o --operational-state=OPERSTATE\n"
" Required operational state\n"
" --any Wait until at least one of the interfaces is online\n"
" --timeout=SECS Maximum time to wait for network connectivity\n"
"\nSee the %s for details.\n"
, program_invocation_short_name
@ -101,6 +103,7 @@ static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
ARG_IGNORE,
ARG_ANY,
ARG_TIMEOUT,
};
@ -111,6 +114,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "interface", required_argument, NULL, 'i' },
{ "ignore", required_argument, NULL, ARG_IGNORE },
{ "operational-state", required_argument, NULL, 'o' },
{ "any", no_argument, NULL, ARG_ANY },
{ "timeout", required_argument, NULL, ARG_TIMEOUT },
{}
};
@ -158,6 +162,10 @@ static int parse_argv(int argc, char *argv[]) {
arg_required_operstate = s;
break;
}
case ARG_ANY:
arg_any = true;
break;
case ARG_TIMEOUT:
r = parse_sec(optarg, &arg_timeout);
if (r < 0)
@ -192,11 +200,11 @@ static int run(int argc, char *argv[]) {
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
r = manager_new(&m, arg_interfaces, arg_ignore, arg_required_operstate, arg_timeout);
r = manager_new(&m, arg_interfaces, arg_ignore, arg_required_operstate, arg_any, arg_timeout);
if (r < 0)
return log_error_errno(r, "Could not create manager: %m");
if (manager_all_configured(m))
if (manager_configured(m))
goto success;
notify_message = notify_start("READY=1\n"

View File

@ -0,0 +1,5 @@
[Match]
Name=test1
[Network]
IPv6AcceptRA=no

View File

@ -0,0 +1,5 @@
[Match]
Name=bridge99
[Network]
IPv6AcceptRA=no

View File

@ -71,7 +71,6 @@ def expectedFailureIfRoutingPolicyIPProtoIsNotAvailable():
return f
def setUpModule():
os.makedirs(network_unit_file_path, exist_ok=True)
os.makedirs(networkd_ci_path, exist_ok=True)
@ -186,8 +185,10 @@ class Utilities():
if sleep_sec > 0:
time.sleep(sleep_sec)
def wait_online(self, links_with_operstate, timeout='20s'):
args = [wait_online_bin, f' --timeout={timeout}'] + [f'--interface={link}' for link in links_with_operstate]
def wait_online(self, links_with_operstate, timeout='20s', bool_any=False):
args = [wait_online_bin, f'--timeout={timeout}'] + [f'--interface={link}' for link in links_with_operstate]
if bool_any:
args += ['--any']
subprocess.check_call(args)
class NetworkdNetDevTests(unittest.TestCase, Utilities):
@ -248,6 +249,7 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
units = [
'10-dropin-test.netdev',
'11-dummy.netdev',
'11-dummy.network',
'12-dummy.netdev',
'15-name-conflict-test.netdev',
'21-macvlan.netdev',
@ -259,6 +261,7 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
'25-bond.netdev',
'25-bond-balanced-tlb.netdev',
'25-bridge.netdev',
'25-bridge.network',
'25-erspan-tunnel-local-any.netdev',
'25-erspan-tunnel.netdev',
'25-fou-gretap.netdev',
@ -367,6 +370,22 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
else:
print('ethtool does not support driver field at least for dummy interfaces, skipping test for Driver field of networkctl.')
def test_wait_online_any(self):
self.copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge.network', '11-dummy.netdev', '11-dummy.network')
self.start_networkd(0)
self.wait_online(['bridge99', 'test1:degraded'], bool_any=True)
self.assertTrue(self.link_exits('bridge99'))
self.assertTrue(self.link_exits('test1'))
output = subprocess.check_output(['networkctl', 'status', 'bridge99']).rstrip().decode('utf-8')
print(output)
self.assertRegex(output, 'State: (?:off|no-carrier) \(configuring\)')
output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8')
print(output)
self.assertRegex(output, 'State: degraded \(configured\)')
def test_bridge(self):
self.copy_unit_to_networkd_unit_path('25-bridge.netdev')
self.start_networkd()