From e74c568b07b50b97873fb4ee1d776dedefbd54d6 Mon Sep 17 00:00:00 2001 From: Michael Biebl Date: Fri, 1 Oct 2021 23:05:04 +0200 Subject: New upstream version 1.32.12 --- examples/C/glib/meson.build | 23 +++-- examples/C/glib/vpn-import-libnm.c | 163 +++++++++++++++++++++++++++++++++ examples/C/qt/meson.build | 16 ++-- examples/python/dbus/create-bond.py | 18 ++-- examples/python/dbus/vpn.py | 11 +-- examples/python/gi/ovs-external-ids.py | 7 +- 6 files changed, 200 insertions(+), 38 deletions(-) create mode 100644 examples/C/glib/vpn-import-libnm.c (limited to 'examples') diff --git a/examples/C/glib/meson.build b/examples/C/glib/meson.build index 41c46ca8..8899a90f 100644 --- a/examples/C/glib/meson.build +++ b/examples/C/glib/meson.build @@ -1,20 +1,23 @@ # SPDX-License-Identifier: LGPL-2.1-or-later examples = [ - ['add-connection-gdbus', [libnm_enum_sources[1]], [uuid_dep]], - ['add-connection-libnm', [], [libnm_dep]], - ['get-active-connections-gdbus', [libnm_enum_sources[1]], []], - ['get-ap-info-libnm', [], [libnm_dep]], - ['list-connections-gdbus', [], []], - ['list-connections-libnm', [], [libnm_dep]], - ['monitor-nm-running-gdbus', [], []], - ['monitor-nm-state-gdbus', [], []], + ['add-connection-gdbus', [uuid_dep]], + ['add-connection-libnm', []], + ['get-active-connections-gdbus', []], + ['get-ap-info-libnm', []], + ['list-connections-gdbus', []], + ['list-connections-libnm', []], + ['monitor-nm-running-gdbus', []], + ['monitor-nm-state-gdbus', []], + ['vpn-import-libnm', []], ] foreach example: examples executable( example[0], - [example[0] + '.c'] + example[1], - dependencies: [libnm_nm_default_dep] + example[2], + [example[0] + '.c'], + dependencies: [ + libnm_dep, + ] + example[1], ) endforeach diff --git a/examples/C/glib/vpn-import-libnm.c b/examples/C/glib/vpn-import-libnm.c new file mode 100644 index 00000000..55ed5175 --- /dev/null +++ b/examples/C/glib/vpn-import-libnm.c @@ -0,0 +1,163 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * The example shows how to import VPN connection from a file. + * + * @author: Jagadeesh Kotra + * + * Compile with: + * gcc -Wall vpn-import-libnm.c -o vpn-import-libnm `pkg-config --cflags --libs libnm` + */ + +#include +#include + +/*****************************************************************************/ + +static NMConnection * +vpn_connection_import(const char *filename) +{ + NMConnection *conn = NULL; + GSList * plugins; + GSList * iter; + + g_print("Try to import file \"%s\"...\n", filename); + + plugins = nm_vpn_plugin_info_list_load(); + + for (iter = plugins; iter; iter = iter->next) { + GError * error = NULL; + NMVpnPluginInfo * plugin = iter->data; + NMVpnEditorPlugin *editor; + const char * plugin_name = nm_vpn_plugin_info_get_name(plugin); + + g_print("plugin[%s]: trying import...\n", plugin_name); + + editor = nm_vpn_plugin_info_load_editor_plugin(plugin, &error); + if (error) { + g_print("plugin[%s]: error loading plugin: %s\n", plugin_name, error->message); + g_clear_error(&error); + continue; + } + + conn = nm_vpn_editor_plugin_import(editor, filename, &error); + if (error) { + g_print("plugin[%s]: error importing file: %s\n", plugin_name, error->message); + g_clear_error(&error); + continue; + } + + if (!nm_connection_normalize(conn, NULL, NULL, &error)) { + g_print("plugin[%s]: imported connection invalid: %s\n", plugin_name, error->message); + g_clear_error(&error); + g_clear_object(&conn); + continue; + } + + g_print("plugin[%s]: imported connection \"%s\" (%s)\n", + plugin_name, + nm_connection_get_id(conn), + nm_connection_get_uuid(conn)); + break; + } + g_slist_free_full(plugins, g_object_unref); + + if (!conn) { + g_print("Failure to import the file with any plugin\n"); + return NULL; + } + + return conn; +} + +/*****************************************************************************/ + +typedef struct { + GMainLoop * loop; + GError * error; + NMRemoteConnection *rconn; +} RequestData; + +static void +add_cb(GObject *source, GAsyncResult *result, gpointer user_data) +{ + RequestData *rdata = user_data; + + rdata->rconn = nm_client_add_connection_finish(NM_CLIENT(source), result, &rdata->error); + g_main_loop_quit(rdata->loop); +} + +static NMRemoteConnection * +connection_add(NMConnection *conn) +{ + GError * error = NULL; + NMClient * client; + RequestData rdata; + + g_print("Adding connection \"%s\" (%s)\n", + nm_connection_get_id(conn), + nm_connection_get_uuid(conn)); + + client = nm_client_new(NULL, &error); + if (!client) { + g_print("Failure to connect with NetworkManager: %s\n", error->message); + return NULL; + } + + g_print("Adding connection \"%s\" (%s)\n", + nm_connection_get_id(conn), + nm_connection_get_uuid(conn)); + + rdata = (RequestData){ + .loop = g_main_loop_new(NULL, FALSE), + .rconn = NULL, + .error = NULL, + }; + + nm_client_add_connection_async(client, conn, TRUE, NULL, add_cb, &rdata); + + g_main_loop_run(rdata.loop); + + g_clear_pointer(&rdata.loop, g_main_loop_unref); + + if (rdata.error != NULL) { + g_print("Error: %s\n", rdata.error->message); + g_clear_error(&rdata.error); + } else { + g_print("Connection successfully added: %s\n", nm_object_get_path(NM_OBJECT(rdata.rconn))); + } + + g_clear_object(&client); + + return rdata.rconn; +} + +/*****************************************************************************/ + +int +main(int argc, char **argv) +{ + NMRemoteConnection *rconn; + NMConnection * conn; + const char * filename; + gboolean success; + + if (argc < 2) { + g_print("program takes exactly one(1) argument.\n"); + return 1; + } + + filename = argv[1]; + + conn = vpn_connection_import(filename); + if (!conn) + return 1; + + rconn = connection_add(conn); + + success = (rconn != NULL); + + g_clear_object(&conn); + g_clear_object(&rconn); + + return success ? 0 : 1; +} diff --git a/examples/C/qt/meson.build b/examples/C/qt/meson.build index 7e4e1274..8b905bd6 100644 --- a/examples/C/qt/meson.build +++ b/examples/C/qt/meson.build @@ -6,13 +6,6 @@ examples = [ ['change-ipv4-addresses', []], ] -deps = [ - dbus_dep, - qt_core_dep, - qt_dbus_dep, - qt_network_dep, -] - moc = find_program('moc-qt4', required: false) if not moc.found() moc = qt_core_dep.get_pkgconfig_variable('moc_location') @@ -34,8 +27,13 @@ foreach example: examples executable( example[0], example[0] + '.cpp', - include_directories: libnm_core_inc, - dependencies: deps, + include_directories: libnm_core_public_inc, + dependencies: [ + dbus_dep, + qt_core_dep, + qt_dbus_dep, + qt_network_dep, + ], link_depends: example[1], ) endforeach diff --git a/examples/python/dbus/create-bond.py b/examples/python/dbus/create-bond.py index 4ebec24a..fe35fcc0 100755 --- a/examples/python/dbus/create-bond.py +++ b/examples/python/dbus/create-bond.py @@ -40,8 +40,8 @@ def create_bond(bond_name): "autoconnect-slaves": 1, } ) - s_ip4 = dbus.Dictionary({"method": "auto"}) - s_ip6 = dbus.Dictionary({"method": "ignore"}) + s_ip4 = dbus.Dictionary({"method": "disabled"}) + s_ip6 = dbus.Dictionary({"method": "disabled"}) con = dbus.Dictionary( {"bond": s_bond, "connection": s_con, "ipv4": s_ip4, "ipv6": s_ip6} @@ -97,18 +97,22 @@ print("Activating bond: %s (%s)" % (bond_name, ac)) loop = GLib.MainLoop() -def properties_changed(props): - if "State" in props: - if props["State"] == 2: +def properties_changed(interface_name, changed_properties, invalidated_properties): + if ( + interface_name == "org.freedesktop.NetworkManager.Connection.Active" + and "State" in changed_properties + ): + state = changed_properties["State"] + if state == 2: print("Successfully connected") loop.quit() - if props["State"] == 3 or props["State"] == 4: + if state == 3 or state == 4: print("Bond activation failed") loop.quit() obj = bus.get_object("org.freedesktop.NetworkManager", ac) -iface = dbus.Interface(obj, "org.freedesktop.NetworkManager.Connection.Active") +iface = dbus.Interface(obj, "org.freedesktop.DBus.Properties") iface.connect_to_signal("PropertiesChanged", properties_changed) loop.run() diff --git a/examples/python/dbus/vpn.py b/examples/python/dbus/vpn.py index f86bf1ad..794fb022 100755 --- a/examples/python/dbus/vpn.py +++ b/examples/python/dbus/vpn.py @@ -10,11 +10,8 @@ # The uuid of the connection to activate CONNECTION_UUID = "c08142a4-00d9-45bd-a3b1-7610fe146374" -# UID to use. Note that NM only allows the owner of the connection to activate it. -# UID=1000 -UID = 0 - -import sys, os, dbus +import dbus +import sys from dbus.mainloop.glib import DBusGMainLoop from gi.repository import GLib @@ -127,10 +124,6 @@ def activate_connection(connection_path, device_path): ) -# Change the UID first if required -if UID != 0: - os.setuid(UID) - # Are we configured? if not len(CONNECTION_UUID): print("missing connection UUID") diff --git a/examples/python/gi/ovs-external-ids.py b/examples/python/gi/ovs-external-ids.py index 63f9695e..3bc9de8f 100755 --- a/examples/python/gi/ovs-external-ids.py +++ b/examples/python/gi/ovs-external-ids.py @@ -68,7 +68,7 @@ def can_sudo(): ).returncode == 0 ) - except: + except Exception: return False @@ -222,7 +222,6 @@ def die_usage(msg): def parse_args(argv): - had_dash_dash = False args = { "mode": MODE_GET, "select_arg": None, @@ -615,7 +614,9 @@ def do_apply(nmc, device, ids_arg, do_test): die("FAILURE to get applied connection after reapply") _print() - connection_print(connection, MODE_APPLY, [], device.get_path(), prefix="AFTER: ") + connection_print( + connection_after, MODE_APPLY, [], device.get_path(), prefix="AFTER: " + ) _print() ovs_print_external_ids("AFTER-OVS-VSCTL: ") -- cgit 1.3.0-6-gf8a5 From 88c227d90a6b7b388c5c85d72802a0ca8f05ed5c Mon Sep 17 00:00:00 2001 From: Michael Biebl Date: Thu, 13 Jan 2022 22:30:39 +0100 Subject: New upstream version 1.34.0 --- examples/python/dbus/add-connection-compat.py | 2 +- examples/python/dbus/add-connection.py | 2 +- examples/python/dbus/create-bond.py | 2 +- examples/python/dbus/update-ip4-method.py | 2 +- examples/python/dbus/wifi-active-ap.py | 2 +- examples/python/dbus/wifi-hotspot.py | 2 +- examples/python/gi/add_connection.py | 2 +- examples/python/gi/nm-up-many.py | 345 ++++++++++++++++++++++++++ examples/python/gi/update-ip4-method.py | 2 +- examples/ruby/add-connection.rb | 2 +- 10 files changed, 354 insertions(+), 9 deletions(-) create mode 100755 examples/python/gi/nm-up-many.py (limited to 'examples') diff --git a/examples/python/dbus/add-connection-compat.py b/examples/python/dbus/add-connection-compat.py index d5218514..9463ec68 100755 --- a/examples/python/dbus/add-connection-compat.py +++ b/examples/python/dbus/add-connection-compat.py @@ -11,7 +11,7 @@ # add-connection.py, which only supports NM 1.0 and later. # # Configuration settings are described at -# https://developer.gnome.org/NetworkManager/1.0/ref-settings.html +# https://networkmanager.dev/docs/api/latest/ref-settings.html # import socket, struct, dbus, uuid diff --git a/examples/python/dbus/add-connection.py b/examples/python/dbus/add-connection.py index cfb46de2..7c0d1f5c 100755 --- a/examples/python/dbus/add-connection.py +++ b/examples/python/dbus/add-connection.py @@ -12,7 +12,7 @@ # NetworkManager as well. # # Configuration settings are described at -# https://developer.gnome.org/NetworkManager/1.0/ref-settings.html +# https://networkmanager.dev/docs/api/latest/ref-settings.html # import dbus, uuid diff --git a/examples/python/dbus/create-bond.py b/examples/python/dbus/create-bond.py index fe35fcc0..618c6696 100755 --- a/examples/python/dbus/create-bond.py +++ b/examples/python/dbus/create-bond.py @@ -8,7 +8,7 @@ # This example configures a Bond from ethernet devices and activates it # # NetworkManager D-Bus API: -# https://developer.gnome.org/NetworkManager/stable/spec.html +# https://networkmanager.dev/docs/api/latest/spec.html # import dbus, sys, uuid diff --git a/examples/python/dbus/update-ip4-method.py b/examples/python/dbus/update-ip4-method.py index d84e01b2..e52846bb 100755 --- a/examples/python/dbus/update-ip4-method.py +++ b/examples/python/dbus/update-ip4-method.py @@ -11,7 +11,7 @@ # for a similar example using the backward-compatible properties # # Configuration settings are described at -# https://developer.gnome.org/NetworkManager/1.0/ref-settings.html +# https://networkmanager.dev/docs/api/latest/ref-settings.html # import dbus, sys diff --git a/examples/python/dbus/wifi-active-ap.py b/examples/python/dbus/wifi-active-ap.py index bc8f1ea5..52ee73b9 100755 --- a/examples/python/dbus/wifi-active-ap.py +++ b/examples/python/dbus/wifi-active-ap.py @@ -8,7 +8,7 @@ # This example prints the current wifi access point # # Configuration settings are described at -# https://developer.gnome.org/NetworkManager/1.0/ref-settings.html +# https://networkmanager.dev/docs/api/latest/ref-settings.html # import dbus, sys diff --git a/examples/python/dbus/wifi-hotspot.py b/examples/python/dbus/wifi-hotspot.py index a441e7e9..b75d8b2e 100755 --- a/examples/python/dbus/wifi-hotspot.py +++ b/examples/python/dbus/wifi-hotspot.py @@ -8,7 +8,7 @@ # This example starts or stops a wifi hotspot # # Configuration settings are described at -# https://developer.gnome.org/NetworkManager/1.0/ref-settings.html +# https://networkmanager.dev/docs/api/latest/ref-settings.html # import dbus, sys, time diff --git a/examples/python/gi/add_connection.py b/examples/python/gi/add_connection.py index e6e1d5a6..74fed3fc 100755 --- a/examples/python/gi/add_connection.py +++ b/examples/python/gi/add_connection.py @@ -10,7 +10,7 @@ # # Documentation links: # https://developer.gnome.org/libnm/1.0/ -# https://developer.gnome.org/NetworkManager/1.0/ref-settings.html +# https://networkmanager.dev/docs/api/latest/ref-settings.html # import gi diff --git a/examples/python/gi/nm-up-many.py b/examples/python/gi/nm-up-many.py new file mode 100755 index 00000000..e5faad19 --- /dev/null +++ b/examples/python/gi/nm-up-many.py @@ -0,0 +1,345 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: LGPL-2.1-or-later + +# A example script to activate many profiles in parallel. +# +# It uses entirely asynchronous API. At various points the +# script explicitly iterates the main context, which is unlike +# a more complex application that uses the GMainContext, which +# probably would run the context only at one point as long as +# the application is running (from the main function). + +import gi +import os +import sys +import time + +gi.require_version("NM", "1.0") +from gi.repository import NM, GLib + + +class MyError(Exception): + pass + + +NUM_PARALLEL_STARTING = 10 +NUM_PARALLEL_IN_PROGRESS = 50 + +s = os.getenv("NUM_PARALLEL_STARTING") +if s: + NUM_PARALLEL_STARTING = int(s) + +s = os.getenv("NUM_PARALLEL_IN_PROGRESS") +if s: + NUM_PARALLEL_IN_PROGRESS = int(s) + + +start_time = time.monotonic() + + +def log(msg): + # use nm_utils_print(), so that the log messages are in synch with + # LIBNM_CLIENT_DEBUG=trace messages. + NM.utils_print(0, "[%015.10f] %s\n" % (time.monotonic() - start_time, msg)) + + +def nmc_new(io_priority=GLib.PRIORITY_DEFAULT, cancellable=None): + # create a NMClient instance using the async initialization + # (but the function itself iterates the main context until + # the initialization completes). + + result = [] + + def cb(source_object, res): + + try: + source_object.init_finish(res) + except Exception as e: + result.append(e) + else: + result.append(None) + + nmc = NM.Client() + nmc.init_async(io_priority, cancellable, cb) + while not result: + nmc.get_main_context().iteration(may_block=True) + + if result[0]: + raise result[0] + + log("initialized NMClient cache") + + return nmc + + +def nmc_destroy(nmc_transfer_ref): + + # Just for fun, show how to completely cleanup a NMClient instance. + # An NMClient instance registers D-Bus signals and unrefing the instance + # will cancel/unsubscribe those signals, but there might still be some + # pending operations scheduled on the main context. That means, after + # unrefing the NMClient instance, we may need to iterate the GMainContext + # a bit longer, go get rid of all resources (otherwise, the GMainContext + # itself cannot be destroyed and leaks). + # + # We can use nm_client_get_context_busy_watcher() for that, by subscribing + # a weak reference and iterating the context as long as the object is + # alive. + + nmc = nmc_transfer_ref[0] + del nmc_transfer_ref[0] + + alive = [1] + + def weak_ref_cb(alive): + del alive[0] + + nmc.get_context_busy_watcher().weak_ref(weak_ref_cb, alive) + main_context = nmc.get_main_context() + + del nmc + + while alive: + main_context.iteration(may_block=True) + + log("NMClient instance cleaned up") + + +def find_connections(nmc, argv): + + # parse the inpurt argv and select the connection profiles to activate. + # The arguments are either "connection.id" or "connection.uuid", possibly + # qualified by "id" or "uuid". + + result = [] + + while True: + if not argv: + break + arg_type = argv.pop(0) + if arg_type in ["id", "uuid"]: + if not argv: + raise MyError('missing specifier after "%s"' % (arg_type)) + arg_param = argv.pop(0) + else: + arg_param = arg_type + arg_type = "*" + + cc = [] + for c in nmc.get_connections(): + if arg_type in ["id", "*"] and arg_param == c.get_id(): + cc.append(c) + if arg_type in ["uuid", "*"] and arg_param == c.get_uuid(): + cc.append(c) + + if not cc: + raise MyError( + 'Could not find a matching connection "%s" "%s"' % (arg_type, arg_param) + ) + if len(cc) > 1: + raise MyError( + 'Could not find a unique matching connection "%s" "%s", instead %d profiles found' + % (arg_type, arg_param, len(cc)) + ) + + if cc[0] not in result: + # we allow duplicates, but combine them. + result.extend(cc) + + for c in result: + log( + "requested connection: %s (%s) (%s)" + % (c.get_id(), c.get_uuid(), c.get_path()) + ) + + return result + + +class Activation(object): + ACTIVATION_STATE_START = "start" + ACTIVATION_STATE_STARTING = "starting" + ACTIVATION_STATE_WAITING = "waiting" + ACTIVATION_STATE_DONE = "done" + + def __init__(self, con): + self.con = con + self.state = Activation.ACTIVATION_STATE_START + self.result_msg = None + self.result_ac = None + self.ac_result = None + self.wait_id = None + + def __str__(self): + return "%s (%s)" % (self.con.get_id(), self.con.get_uuid()) + + def is_done(self, log=log): + + if self.state == Activation.ACTIVATION_STATE_DONE: + return True + + if self.state != Activation.ACTIVATION_STATE_WAITING: + return False + + def _log_result(self, msg, done_with_success=False): + log("connection %s done: %s" % (self, msg)) + self.state = Activation.ACTIVATION_STATE_DONE + self.done_with_success = done_with_success + return True + + ac = self.result_ac + if not ac: + return _log_result(self, "failed activation call (%s)" % (self.result_msg,)) + + if ac.get_client() is None: + return _log_result(self, "active connection disappeared") + + if ac.get_state() > NM.ActiveConnectionState.ACTIVATED: + return _log_result( + self, "connection failed to activate (state %s)" % (ac.get_state()) + ) + + if ac.get_state() == NM.ActiveConnectionState.ACTIVATED: + return _log_result( + self, "connection successfully activated", done_with_success=True + ) + + return False + + def start(self, nmc, cancellable=None, activated_callback=None, log=log): + + # Call nmc.activate_connection_async() and return a user data + # with the information about the pending operation. + + assert self.state == Activation.ACTIVATION_STATE_START + + self.state = Activation.ACTIVATION_STATE_STARTING + + log("activation %s start asynchronously" % (self)) + + def cb_activate_connection(source_object, res): + assert self.state == Activation.ACTIVATION_STATE_STARTING + try: + ac = nmc.activate_connection_finish(res) + except Exception as e: + self.result_msg = str(e) + log( + "activation %s started asynchronously failed: %s" + % (self, self.result_msg) + ) + else: + self.result_msg = "success" + self.result_ac = ac + log( + "activation %s started asynchronously success: %s" + % (self, ac.get_path()) + ) + self.state = Activation.ACTIVATION_STATE_WAITING + if activated_callback is not None: + activated_callback(self) + + nmc.activate_connection_async( + self.con, None, None, cancellable, cb_activate_connection + ) + + def wait(self, done_callback=None, log=log): + + assert self.state == Activation.ACTIVATION_STATE_WAITING + assert self.result_ac + assert self.wait_id is None + + def cb_wait(ac, state): + if self.is_done(log=log): + self.result_ac.disconnect(self.wait_id) + self.wait_id = None + done_callback(self) + + log("waiting for %s to fully activate" % (self)) + self.wait_id = self.result_ac.connect("notify", cb_wait) + + +class Manager(object): + def __init__(self, nmc, cons): + + self.nmc = nmc + + self.ac_start = [Activation(c) for c in cons] + self.ac_starting = [] + self.ac_waiting = [] + self.ac_done = [] + + def _log(self, msg): + + lists = [self.ac_start, self.ac_starting, self.ac_waiting, self.ac_done] + + n = sum(len(l) for l in lists) + n = str(len(str(n))) + + prefix = "/".join((("%0" + n + "d") % len(l)) for l in lists) + log("%s: %s" % (prefix, msg)) + + def ac_run(self): + + loop = GLib.MainLoop(self.nmc.get_main_context()) + + while self.ac_start or self.ac_starting or self.ac_waiting: + + rate_limit_parallel_in_progress = ( + len(self.ac_starting) + len(self.ac_waiting) >= NUM_PARALLEL_IN_PROGRESS + ) + + if ( + not rate_limit_parallel_in_progress + and self.ac_start + and len(self.ac_starting) < NUM_PARALLEL_STARTING + ): + activation = self.ac_start.pop(0) + self.ac_starting.append(activation) + + def cb_activated(activation2): + self.ac_starting.remove(activation2) + if activation2.is_done(log=self._log): + self.ac_done.append(activation2) + else: + self.ac_waiting.append(activation2) + + def cb_done(activation3): + self.ac_waiting.remove(activation3) + self.ac_done.append(activation3) + loop.quit() + + activation2.wait(done_callback=cb_done, log=self._log) + loop.quit() + + activation.start( + self.nmc, activated_callback=cb_activated, log=self._log + ) + continue + + loop.run() + + res_list = [ac.done_with_success for ac in self.ac_done] + + log( + "%s out of %s activations are now successfully activated" + % (sum(res_list), len(self.ac_done)) + ) + + return all(res_list) + + +def main(): + nmc = nmc_new() + + cons = find_connections(nmc, sys.argv[1:]) + + all_good = Manager(nmc, cons).ac_run() + + nmc_transfer_ref = [nmc] + del nmc + nmc_destroy(nmc_transfer_ref) + + sys.exit(0 if all_good else 1) + + +if __name__ == "__main__": + main() diff --git a/examples/python/gi/update-ip4-method.py b/examples/python/gi/update-ip4-method.py index 811d10b4..036606c4 100755 --- a/examples/python/gi/update-ip4-method.py +++ b/examples/python/gi/update-ip4-method.py @@ -9,7 +9,7 @@ # using the libnm GObject-based convenience APIs. # # Configuration settings are described at -# https://developer.gnome.org/NetworkManager/1.0/ref-settings.html +# https://networkmanager.dev/docs/api/latest/ref-settings.html # import gi diff --git a/examples/ruby/add-connection.rb b/examples/ruby/add-connection.rb index 5ff0ac36..f8978ece 100755 --- a/examples/ruby/add-connection.rb +++ b/examples/ruby/add-connection.rb @@ -18,7 +18,7 @@ require 'ipaddr' # details # # Configuration settings are described here: -# https://developer.gnome.org/NetworkManager/1.0/ref-settings.html +# https://networkmanager.dev/docs/api/latest/ref-settings.html # # Helper functions -- cgit 1.3.0-6-gf8a5