New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
libvirt: Add different options for VM IP detection #586
Conversation
deployment.libvirtd.privateIPv4 = mkOption { | ||
default = "dhcp"; | ||
type = types.str; | ||
description = "IP to use to ssh into the machine. Put 'dhcp' to let nixops get the IP from libvirt's dhcp (works with default libvirt network); put 'arp' to let nixops detect IP in the host's ARP table (works with most setups)"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Split into multiple lines using
description = ''
'';
09ad555
to
eb849b3
Compare
eb849b3
to
031ca1b
Compare
@domenkozar I have fixed what you suggested. |
Suggest this might help with issue #500 (or at least similar issues). For me, I'm not using libvirtd for dhcp, so queries with virsh fail, but the arp possibilities here would work. Of course, from a completely self-interested point of view, I'd like to see this merged 😄 |
Using libvirt, openvswitch and dhcp (dnsmasq) on the router, with the arp setting, trying to create a new vm still gets stuck looking for an arp. However, I can clear it by pinging it's IP from the host. I'm guessing that's because openvswitch is dealing with all the networking to the VM, so the host never gets the chance to add the IP to it's ARP tables. Ugh, there should be a nicer way to deal with all of this... |
Yeah, for arp to work, the VM and the host need to have exchanged at least one packet, which does not always happen. That's why I tend to use only static IPs |
I'm just looking into inverse arps and similar schemes (but it usually needs special permissions, presumably because we're grabbing layer 2 / raw sockets). Ping sweeps would be another possibility:
libvirtd and various vswitches must be a fairly common use case. ping sweeping a subnet seems like a sledgehammer approach to discovering an IP but at the moment I haven't found a better approach to doing this. My idea at the moment would be, on merge of the arp functionality you've built, to add another option to All this seems a bit ugly though. Better suggestions? |
I kind of like this idea ^^ Wouldn't it be enough do ping sweep only just before trying to get the IP from the arp table ? |
Yeah, that would be more or less how I'd implement it. The only issue I can see is if we don't get an IP in time for the ping sweep to find it. I guess if its an option, we can do it on every test of the arp table, because you'd likely only enable this if you know your virtual network isn't going to be witnessed directly by the host. |
Perhaps that's what you meant, actually. |
Pretty much, yes :) |
I guess we wait for the merge. @domenkozar ? |
continue | ||
else: | ||
ip_with_subnet = lines[i + 2] | ||
ip = ip_with_subnet.split('/')[0] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not really a review;
but I wanted to be able to quickly start and restart vms; and since the vms were using dhcp lookups to query services running on the other vms, I ended up adding code like this here in my fork (to avoid having to wait for leases to expire (I think this was (at least part of) the problem (also occurred with your arp method, and was fixed by similar code))
self._logged_exec(
["virsh", "-c", "qemu:///system",
"net-update", net, "add",
"ip-dhcp-host",
"<host mac='{0}' name='{1}' ip='{2}' />".format(
mac, self.name, ip),
"--live", "--config"
])
along with something like this in nixops destroy (which is stop in libvirtd.py)
map(lambda (net, mac):
self._logged_exec(
["virsh", "-c", "qemu:///system",
"net-update", net, "delete",
"ip-dhcp-host",
"<host mac='{0}' name='{1}' ip='{2}' />".format(
mac, self.name, self.private_ipv4),
"--live", "--config"
]),
nets
)
all this to say, is a similar issue why you are interested in static ips/ would this change make sense or is there a hidden drawback I don't see?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
accidentally opened pull request with referenced changes here https://github.com/NixOS/nixops/pull/610/files :P
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My PR adds different methods for nixops to get the VM IP, but does nothing to give the VM a particular IP.
Your change would totally make sense in another PR that would aim at giving the VM a given static IP. It is rather complementary to what I'm doing here, and would be a logical next step.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wait no, I had not looked at the context of your code. What you are doing is rather weird since it tells libvirt to give to the VM the IP it already has. Moreover, it has unreasonable assumptions like the fact that the given network has a dhcp server, which is exactly what I'm trying to get rid of.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't disagree it's weird (leads to pollution of network xml if you don't shut them down properly), problem I had that this fixes is quickly restarting setups like this :
infrastructure-libvirtd.nix
let
defaultConfig =
{
deployment.targetEnv = "libvirtd";
deployment.libvirtd.privateIPv4 = "dhcp";
};
in
{
apiServer = defaultConfig;
postgresqlServer = defaultConfig;
}
network.nix
apiServer =
{ config, pkgs, ... }:
systemd.services.postgrest = {
description = "Wraps postgresql database with REST api";
# Start the service after the network is available
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
# The actual command to run
ExecStart = "${postgrest}/bin/postgrest postgres://root@postgresqlServer:5432/postgres \\
--port 3030 \\
--schema public \\
--anonymous root \\
--pool 200";
};
postgresqlServer =
{ config, pkgs ? import <nixpkgs> {}, ... }:
{ ...etc. etc. }
which I suppose you would fix by replacing the hostname (postgresqlServer in this case) by a static ip address (which idk how to do at this point)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
...okay I see what you're saying, thanks, I apologize for newbness.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't, your idea was reasonable. Sorry if I sounded rough. I would definitely be interested in a PR implementing that once this PR is merged.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm looked into this some more and it doesn't seem like there's an easy way to do this through libvirt api without upstream change to said api.
https://www.redhat.com/archives/libvir-list/2016-June/msg01564.html
setting static ip address for guests only works on type=ethernet interfaces. (and I'm not sure if even that is true with qemu)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also just getting rid of --config (and keeping --live flag) removes the need to to the update/delete in nixops destroy (stop). (I think, may require restarting network :P)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd be keen to see this merged before doing this (if it's actually a good idea), but might we pull out IP detection as a separate abstract class, which has instances for each (broad) method of obtaining an IP? I can see these nested ifs getting a little out of hand the more configuration options are added here. Is there an argument for doing this more broadly? I'm guessing other hosting systems provide a more reliable way to obtain your IP. As mentioned, would be keen to see this merged first, so I can do a little work on it, and use it without having to pull from your fork! |
I'm closing this because I'm not using nixops anymore. If anyone still wants this, you can fetch the branch from my fork and make a new PR yourself. |
This PR adds different methods for detecting the VM's IP address, in case DHCP is not used for example.
It also removes the hacky way to get static MACs since we can get the devices' MAC from libvirt. I understand this could cause libvirt's DHCP to more often assign different IPs to a given machine across deployments. I however believe that people needing a static IP should not have to rely on a DHCP anyways (I'm working on enabling that too).