So awesome! Thank you very much. I also tested this with success on the staging version. That will be a great improvement!
I also appreciate the detail in your answer, which made it easy to test.
Based on the hint regarding resin-wifi-connect I’ve also devised a workaround we can apply in the current version:
It turns out that we can almost just configure the second wifi from within the container. What’s holding us back is the fact that wpa_supplicant is running (on the host) on all managed interfaces. I discovered this, thanks to your ssh authorized_hosts hint (perfect for troubleshooting). So when you try to run wpa_supplicant in the container, it can’t auth (probably because the host is “stealing” / interrupting the process).
So the workaround is to remove the “other” interfaces from management, by wpa_supplicant, via dbus.
The below reads all interfaces and “unmanages” any inactive interfaces. Inactive in this sense, is basically any Wifi links not already connected. You are then free to configure them as you wish from inside the container (it could use a rewrite / cleanup, but posting it here in case it helps others):
let dbus = require('dbus-native');
process.env['DBUS_SESSION_BUS_ADDRESS'] = 'unix:path=/host/run/dbus/system_bus_socket';
function unmanageUnusedInterfaces() {
return new Promise((resolve, reject) => {
let unmanagedInterfaces = [];
getWpaInterfacePaths()
.then((interfacePaths) => {
Promise.all(
interfacePaths.map((interfacePath) => {
return new Promise((resolve, reject) => {
getWpaInterfaceState(interfacePath)
.then((result) => {
if (result == 'inactive') {
getWpaInterfaceNameFromPath(interfacePath)
.then((interfaceName) => {
unmanageWpaInterface(interfacePath)
.then((result) => {
unmanagedInterfaces.push(interfaceName);
resolve();
});
});
} else {
resolve();
}
})
})
})
)
.then(() => {
resolve(unmanagedInterfaces);
});
});
});
}
function getWpaInterfacePaths() {
let sessionBus = dbus.sessionBus();
return new Promise((resolve, reject) => {
sessionBus.invoke({
path: "/fi/w1/wpa_supplicant1",
interface: "org.freedesktop.DBus.Properties",
member: "Get",
destination: "fi.w1.wpa_supplicant1",
signature: "ss",
body: [
"fi.w1.wpa_supplicant1",
"Interfaces"
]
}, function (err, result) {
sessionBus.connection.end();
if (err) {
reject(err);
} else {
resolve(result[1][0]);
}
});
});
}
function getWpaInterfaceNameFromPath(path) {
let sessionBus = dbus.sessionBus();
return new Promise((resolve, reject) => {
sessionBus.invoke({
path: path,
interface: "org.freedesktop.DBus.Properties",
member: "Get",
destination: "fi.w1.wpa_supplicant1",
signature: "ss",
body: [
"fi.w1.wpa_supplicant1.Interface",
"Ifname"
]
}, function (err, result) {
sessionBus.connection.end();
if (err) {
reject(err);
} else {
resolve(result[1][0]);
}
});
});
}
function getWpaInterfaceState(path) {
let sessionBus = dbus.sessionBus();
return new Promise((resolve, reject) => {
sessionBus.invoke({
path: path,
interface: "org.freedesktop.DBus.Properties",
member: "Get",
destination: "fi.w1.wpa_supplicant1",
signature: "ss",
body: [
"fi.w1.wpa_supplicant1.Interface",
"State"
]
}, function (err, result) {
sessionBus.connection.end();
if (err) {
reject(err);
} else {
resolve(result[1][0]);
}
});
});
}
function unmanageWpaInterface(path) {
let sessionBus = dbus.sessionBus();
return new Promise((resolve, reject) => {
sessionBus.invoke({
path: "/fi/w1/wpa_supplicant1",
interface: "fi.w1.wpa_supplicant1",
member: "RemoveInterface",
destination: "fi.w1.wpa_supplicant1",
signature: "o",
body: [
path
]
}, function (err, result) {
sessionBus.connection.end();
if (err) {
reject(err);
} else {
resolve(result);
}
});
});
}
module.exports = {
unmanageUnusedInterfaces: unmanageUnusedInterfaces
};