* [pve-devel] [PATCH container] api: network: get interfaces from containers
2023-04-18 9:31 [pve-devel] [PATCH container manager] Show dynamic container IPs in GUI Leo Nunner
@ 2023-04-18 9:31 ` Leo Nunner
2023-04-18 9:41 ` Lukas Wagner
2023-04-18 9:31 ` [pve-devel] [PATCH manager] lxc: show dynamically assigned IPs in network tab Leo Nunner
1 sibling, 1 reply; 5+ messages in thread
From: Leo Nunner @ 2023-04-18 9:31 UTC (permalink / raw)
To: pve-devel
Adds an 'interfaces' endpoint in the API
(/nodes/{node}/lxc/{vmid}/interfaces'), which returns a list of
interface names, together with a MAC, IPv4 and IPv6 address. This list
may be expanded in the future. Note that this is only returned for
*running* containers, stopped containers simply return an empty list.
Signed-off-by: Leo Nunner <l.nunner@proxmox.com>
---
src/PVE/API2/LXC.pm | 50 +++++++++++++++++++++++++++++++++++++++++++++
src/PVE/LXC.pm | 26 +++++++++++++++++++++++
2 files changed, 76 insertions(+)
diff --git a/src/PVE/API2/LXC.pm b/src/PVE/API2/LXC.pm
index 50c9eaf..078d506 100644
--- a/src/PVE/API2/LXC.pm
+++ b/src/PVE/API2/LXC.pm
@@ -2495,6 +2495,56 @@ __PACKAGE__->register_method({
return PVE::GuestHelpers::config_with_pending_array($conf, $pending_delete_hash);
}});
+__PACKAGE__->register_method({
+ name => 'ip',
+ path => '{vmid}/interfaces',
+ method => 'GET',
+ protected => 1,
+ permissions => {
+ check => ['perm', '/vms/{vmid}', [ 'VM.Audit' ]],
+ },
+ description => 'Get IP addresses of the specified container interface.',
+ parameters => {
+ additionalProperties => 0,
+ properties => {
+ node => get_standard_option('pve-node'),
+ vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_ctid }),
+ },
+ },
+ returns => {
+ type => "array",
+ items => {
+ type => 'object',
+ properties => {
+ name => {
+ type => 'string',
+ description => 'The name of the interface',
+ optional => 0,
+ },
+ hwaddr => {
+ type => 'string',
+ description => 'The MAC address of the interface',
+ optional => 0,
+ },
+ inet => {
+ type => 'string',
+ description => 'The IPv4 address of the interface',
+ optional => 1,
+ },
+ inet6 => {
+ type => 'string',
+ description => 'The IPv6 address of the interface',
+ optional => 1,
+ },
+ }
+ },
+ },
+ code => sub {
+ my ($param) = @_;
+
+ return PVE::LXC::get_interfaces($param->{vmid});
+ }});
+
__PACKAGE__->register_method({
name => 'mtunnel',
path => '{vmid}/mtunnel',
diff --git a/src/PVE/LXC.pm b/src/PVE/LXC.pm
index c4d53e8..bf57ede 100644
--- a/src/PVE/LXC.pm
+++ b/src/PVE/LXC.pm
@@ -1034,6 +1034,32 @@ sub hotplug_net {
PVE::LXC::Config->write_config($vmid, $conf);
}
+sub get_interfaces {
+ my ($vmid) = @_;
+
+ my $pid = eval { find_lxc_pid($vmid); };
+ return if $@;
+
+ my $output;
+ # enters the network namespace of the container and executes 'ip a'
+ run_command(['nsenter', '-t', $pid, '--net', '--', 'ip', '--json', 'a'],
+ outfunc => sub { $output .= shift; });
+
+ my $config = JSON::decode_json($output);
+
+ my $res;
+ foreach my $interface ($config->@*) {
+ my $obj = { name => $interface->{ifname} };
+ foreach my $ip ($interface->{addr_info}->@*) {
+ $obj->{$ip->{family}} = $ip->{local} . "/" . $ip->{prefixlen};
+ }
+ $obj->{hwaddr} = $interface->{address};
+ push @$res, $obj
+ }
+
+ return $res;
+}
+
sub update_ipconfig {
my ($vmid, $conf, $opt, $eth, $newnet, $rootdir) = @_;
--
2.30.2
^ permalink raw reply [flat|nested] 5+ messages in thread
* [pve-devel] [PATCH manager] lxc: show dynamically assigned IPs in network tab
2023-04-18 9:31 [pve-devel] [PATCH container manager] Show dynamic container IPs in GUI Leo Nunner
2023-04-18 9:31 ` [pve-devel] [PATCH container] api: network: get interfaces from containers Leo Nunner
@ 2023-04-18 9:31 ` Leo Nunner
2023-04-18 9:47 ` Lukas Wagner
1 sibling, 1 reply; 5+ messages in thread
From: Leo Nunner @ 2023-04-18 9:31 UTC (permalink / raw)
To: pve-devel
adds a call to /nodes/{node}/lxc/{vmid}/interfaces and merges the
returned data with the existing configuration. This will update the
IPv4 and IPv6 address, as well as the interface name (in case the
container changed it).
Signed-off-by: Leo Nunner <l.nunner@proxmox.com>
---
RFC: I *hope* that the MAC can serve as the "primary key" here, I'm
guessing that there's a higher chance that the interface name changes than
for the MAC changing…
www/manager6/lxc/Network.js | 57 +++++++++++++++++++++++++++----------
1 file changed, 42 insertions(+), 15 deletions(-)
diff --git a/www/manager6/lxc/Network.js b/www/manager6/lxc/Network.js
index b2cd9410..6c7929ba 100644
--- a/www/manager6/lxc/Network.js
+++ b/www/manager6/lxc/Network.js
@@ -356,25 +356,52 @@ Ext.define('PVE.lxc.NetworkView', {
Proxmox.Utils.setErrorMask(me, true);
+ let nodename = me.pveSelNode.data.node;
+ let vmid = me.pveSelNode.data.vmid;
+
Proxmox.Utils.API2Request({
- url: me.url,
+ url: '/nodes/' + nodename + '/lxc/' + vmid + '/interfaces',
+ method: 'GET',
failure: function(response, opts) {
Proxmox.Utils.setErrorMask(me, gettext('Error') + ': ' + response.htmlStatus);
},
- success: function(response, opts) {
- Proxmox.Utils.setErrorMask(me, false);
- let result = Ext.decode(response.responseText);
- me.dataCache = result.data || {};
- let records = [];
- for (const [key, value] of Object.entries(me.dataCache)) {
- if (key.match(/^net\d+/)) {
- let net = PVE.Parser.parseLxcNetwork(value);
- net.id = key;
- records.push(net);
- }
- }
- me.store.loadData(records);
- me.down('button[name=addButton]').setDisabled(records.length >= 32);
+ success: function(ifResponse, ifOpts) {
+ Proxmox.Utils.API2Request({
+ url: me.url,
+ failure: function(response, opts) {
+ Proxmox.Utils.setErrorMask(me, gettext('Error') + ': ' + response.htmlStatus);
+ },
+ success: function(confResponse, confOpts) {
+ Proxmox.Utils.setErrorMask(me, false);
+
+ let interfaces = [];
+ for (const [, iface] of Object.entries(ifResponse?.result?.data || {})) {
+ interfaces[iface.hwaddr] = iface;
+ }
+
+ let result = Ext.decode(confResponse.responseText);
+ me.dataCache = result.data || {};
+ let records = [];
+ for (const [key, value] of Object.entries(me.dataCache)) {
+ if (key.match(/^net\d+/)) {
+ let net = PVE.Parser.parseLxcNetwork(value);
+ net.id = key;
+
+ let iface;
+ if ((iface = interfaces[net.hwaddr.toLowerCase()])) {
+ net.name = iface.name;
+ net.ip = iface.inet;
+ net.ip6 = iface.inet6;
+ }
+
+ records.push(net);
+ }
+ }
+
+ me.store.loadData(records);
+ me.down('button[name=addButton]').setDisabled(records.length >= 32);
+ },
+ });
},
});
},
--
2.30.2
^ permalink raw reply [flat|nested] 5+ messages in thread