Merge pull request #3830 from cstrahan/nixos-guest
Add NixOS guest support
This commit is contained in:
commit
05ccf88c5f
|
@ -0,0 +1,41 @@
|
|||
require 'tempfile'
|
||||
|
||||
require "vagrant/util/template_renderer"
|
||||
|
||||
module VagrantPlugins
|
||||
module GuestNixos
|
||||
module Cap
|
||||
class ChangeHostName
|
||||
include Vagrant::Util
|
||||
|
||||
def self.change_host_name(machine, name)
|
||||
# upload the config file
|
||||
hostname_module = TemplateRenderer.render("guests/nixos/hostname", :name => name)
|
||||
upload(machine, hostname_module, "/etc/nixos/vagrant-hostname.nix")
|
||||
end
|
||||
|
||||
# Upload a file.
|
||||
def self.upload(machine, content, remote_path)
|
||||
local_temp = Tempfile.new("vagrant-upload")
|
||||
local_temp.binmode
|
||||
local_temp.write(content)
|
||||
local_temp.close
|
||||
remote_temp = mktemp(machine)
|
||||
machine.communicate.upload(local_temp.path, "#{remote_temp}")
|
||||
local_temp.delete
|
||||
machine.communicate.sudo("mv #{remote_temp} #{remote_path}")
|
||||
end
|
||||
|
||||
# Create a temp file.
|
||||
def self.mktemp(machine)
|
||||
path = nil
|
||||
|
||||
machine.communicate.execute("mktemp --suffix -vagrant-upload") do |type, result|
|
||||
path = result.chomp if type == :stdout
|
||||
end
|
||||
path
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,129 @@
|
|||
require 'tempfile'
|
||||
require 'ipaddr'
|
||||
|
||||
require "vagrant/util/template_renderer"
|
||||
|
||||
module VagrantPlugins
|
||||
module GuestNixos
|
||||
module Cap
|
||||
class ConfigureNetworks
|
||||
include Vagrant::Util
|
||||
|
||||
def self.configure_networks(machine, networks)
|
||||
# set the prefix length.
|
||||
networks.each do |network|
|
||||
network[:prefix_length] = (network[:netmask] && netmask_to_cidr(network[:netmask]))
|
||||
end
|
||||
|
||||
# set the device names.
|
||||
assign_device_names(machine, networks)
|
||||
|
||||
# upload the config file
|
||||
network_module = TemplateRenderer.render("guests/nixos/network", :networks => networks)
|
||||
upload(machine, network_module, "/etc/nixos/vagrant-network.nix")
|
||||
end
|
||||
|
||||
# Set :device on each network.
|
||||
# Attempts to use biosdevname when available to detect interface names,
|
||||
# and falls back to ifconfig otherwise.
|
||||
def self.assign_device_names(machine, networks)
|
||||
if machine.communicate.test("command -v biosdevname")
|
||||
# use biosdevname to get info about the interfaces
|
||||
interfaces = get_interfaces(machine)
|
||||
if machine.provider.capability?(:nic_mac_addresses)
|
||||
# find device name by MAC lookup.
|
||||
mac_addresses = machine.provider.capability(:nic_mac_addresses)
|
||||
networks.each do |network|
|
||||
mac_address = mac_addresses[network[:interface]+1]
|
||||
interface = interfaces.detect {|nic| nic[:mac_address].gsub(":","") == mac_address} if mac_address
|
||||
network[:device] = interface[:kernel] if interface
|
||||
end
|
||||
else
|
||||
# assume interface numbers correspond to (ethN+1).
|
||||
networks.each do |network|
|
||||
interface = interfaces.detect {|nic| nic[:ethn] == network[:interface]}
|
||||
network[:device] = interface[:kernel] if interface
|
||||
end
|
||||
end
|
||||
else
|
||||
# assume interface numbers correspond to the order of interfaces.
|
||||
interfaces = get_interface_names(machine)
|
||||
networks.each do |network|
|
||||
network[:device] = interfaces[network[:interface]]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.get_interface_names(machine)
|
||||
output = nil
|
||||
machine.communicate.execute("ifconfig -a") do |type, result|
|
||||
output = result.chomp if type == :stdout
|
||||
end
|
||||
names = output.scan(/^[^:\s]+/).reject {|name| name =~ /^lo/ }
|
||||
names
|
||||
end
|
||||
|
||||
# Upload a file.
|
||||
def self.upload(machine, content, remote_path)
|
||||
local_temp = Tempfile.new("vagrant-upload")
|
||||
local_temp.binmode
|
||||
local_temp.write(content)
|
||||
local_temp.close
|
||||
remote_temp = mktemp(machine)
|
||||
machine.communicate.upload(local_temp.path, "#{remote_temp}")
|
||||
local_temp.delete
|
||||
machine.communicate.sudo("mv #{remote_temp} #{remote_path}")
|
||||
end
|
||||
|
||||
# Create a temp file.
|
||||
def self.mktemp(machine)
|
||||
path = nil
|
||||
|
||||
machine.communicate.execute("mktemp --suffix -vagrant-upload") do |type, result|
|
||||
path = result.chomp if type == :stdout
|
||||
end
|
||||
path
|
||||
end
|
||||
|
||||
# using biosdevname, get all interfaces as a list of hashes, where:
|
||||
# :kernel - the kernel's name for the device,
|
||||
# :ethn - the calculated ethN-style name converted to integer.
|
||||
# :mac_address - the permanent mac address. ethN-style name converted to integer.
|
||||
def self.get_interfaces(machine)
|
||||
interfaces = []
|
||||
|
||||
# get all adapters, as named by the kernel
|
||||
output = nil
|
||||
machine.communicate.sudo("biosdevname -d") do |type, result|
|
||||
output = result if type == :stdout
|
||||
end
|
||||
kernel_if_names = output.scan(/Kernel name: ([^\n]+)/).flatten
|
||||
mac_addresses = output.scan(/Permanent MAC: ([^\n]+)/).flatten
|
||||
|
||||
# get ethN-style names
|
||||
ethns = []
|
||||
kernel_if_names.each do |name|
|
||||
machine.communicate.sudo("biosdevname --policy=all_ethN -i #{name}") do |type, result|
|
||||
ethns << result.gsub(/[^\d]/,'').to_i if type == :stdout
|
||||
end
|
||||
end
|
||||
|
||||
# populate the interface list
|
||||
kernel_if_names.each_index do |i|
|
||||
interfaces << {
|
||||
:kernel => kernel_if_names[i],
|
||||
:ethn => ethns[i],
|
||||
:mac_address => mac_addresses[i]
|
||||
}
|
||||
end
|
||||
|
||||
interfaces
|
||||
end
|
||||
|
||||
def self.netmask_to_cidr(mask)
|
||||
IPAddr.new(mask).to_i.to_s(2).count("1")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,11 @@
|
|||
require "vagrant"
|
||||
|
||||
module VagrantPlugins
|
||||
module GuestNixos
|
||||
class Guest < Vagrant.plugin("2", :guest)
|
||||
def detect?(machine)
|
||||
machine.communicate.test("test -f /run/current-system/nixos-version")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,25 @@
|
|||
require "vagrant"
|
||||
|
||||
module VagrantPlugins
|
||||
module GuestNixos
|
||||
class Plugin < Vagrant.plugin("2")
|
||||
name "NixOS guest"
|
||||
description "NixOS guest support."
|
||||
|
||||
guest("nixos", "linux") do
|
||||
require File.expand_path("../guest", __FILE__)
|
||||
Guest
|
||||
end
|
||||
|
||||
guest_capability("nixos", "configure_networks") do
|
||||
require_relative "cap/configure_networks"
|
||||
Cap::ConfigureNetworks
|
||||
end
|
||||
|
||||
guest_capability("nixos", "change_host_name") do
|
||||
require_relative "cap/change_host_name"
|
||||
Cap::ChangeHostName
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,6 @@
|
|||
{ config, pkgs, ... }:
|
||||
{
|
||||
<% if name %>
|
||||
networking.hostName = "<%= name %>";
|
||||
<% end %>
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
{ config, pkgs, ... }:
|
||||
{
|
||||
networking.interfaces = [
|
||||
<% networks.select {|n| n[:device]}.each do |network| %>
|
||||
{
|
||||
name = "<%= network[:device] %>";
|
||||
<% if network[:type] == :static %>
|
||||
ipAddress = "<%= network[:ip] %>";
|
||||
<% end %>
|
||||
<% if network[:prefix_length] %>
|
||||
prefixLength = <%= network[:prefix_length] %>;
|
||||
<% end %>
|
||||
}
|
||||
<% end %>
|
||||
];
|
||||
}
|
Loading…
Reference in New Issue