From 3dd90aa95512e75766019a1ead4470bf6e971bf3 Mon Sep 17 00:00:00 2001 From: Evgeny Sinelnikov Date: Sun, 2 Jul 2017 18:38:20 +0300 Subject: [PATCH 1/6] Add ALT Linux platforms guest detection and support * ALT Linux platforms is an original rpm based distribution forked as Mandrake Russian Edition Spring at 2001 year * Distributions of ALT Linux use etcnet (https://www.altlinux.org/Etcnet) as internal network configuration system needs for configure_networks support --- plugins/guests/alt/cap/change_host_name.rb | 44 +++++++ plugins/guests/alt/cap/configure_networks.rb | 118 ++++++++++++++++++ plugins/guests/alt/cap/flavor.rb | 37 ++++++ plugins/guests/alt/cap/network_scripts_dir.rb | 11 ++ plugins/guests/alt/cap/rsync.rb | 13 ++ plugins/guests/alt/guest.rb | 9 ++ plugins/guests/alt/plugin.rb | 40 ++++++ templates/guests/alt/network_dhcp.erb | 7 ++ templates/guests/alt/network_ipv4address.erb | 3 + templates/guests/alt/network_ipv4route.erb | 5 + templates/guests/alt/network_static.erb | 7 ++ 11 files changed, 294 insertions(+) create mode 100644 plugins/guests/alt/cap/change_host_name.rb create mode 100644 plugins/guests/alt/cap/configure_networks.rb create mode 100644 plugins/guests/alt/cap/flavor.rb create mode 100644 plugins/guests/alt/cap/network_scripts_dir.rb create mode 100644 plugins/guests/alt/cap/rsync.rb create mode 100644 plugins/guests/alt/guest.rb create mode 100644 plugins/guests/alt/plugin.rb create mode 100644 templates/guests/alt/network_dhcp.erb create mode 100644 templates/guests/alt/network_ipv4address.erb create mode 100644 templates/guests/alt/network_ipv4route.erb create mode 100644 templates/guests/alt/network_static.erb diff --git a/plugins/guests/alt/cap/change_host_name.rb b/plugins/guests/alt/cap/change_host_name.rb new file mode 100644 index 000000000..3d0333a37 --- /dev/null +++ b/plugins/guests/alt/cap/change_host_name.rb @@ -0,0 +1,44 @@ +module VagrantPlugins + module GuestALT + module Cap + class ChangeHostName + def self.change_host_name(machine, name) + comm = machine.communicate + + if !comm.test("hostname -f | grep '^#{name}$'", sudo: false) + basename = name.split('.', 2)[0] + comm.sudo <<-EOH.gsub(/^ {14}/, '') + # Save current hostname saved in /etc/hosts + CURRENT_HOSTNAME_FULL="$(hostname -f)" + CURRENT_HOSTNAME_SHORT="$(hostname -s)" + + # New hostname to be saved in /etc/hosts + NEW_HOSTNAME_FULL='#{name}' + NEW_HOSTNAME_SHORT="${NEW_HOSTNAME_FULL%%.*}" + + # Update sysconfig + sed -i 's/\\(HOSTNAME=\\).*/\\1#{name}/' /etc/sysconfig/network + + # Set the hostname - use hostnamectl if available + if command -v hostnamectl; then + hostnamectl set-hostname --static '#{name}' + hostnamectl set-hostname --transient '#{name}' + else + hostname '#{name}' + fi + + # Update ourselves in /etc/hosts + if grep -w "$CURRENT_HOSTNAME_FULL" /etc/hosts; then + sed -i -e "s/\(\s\)$CURRENT_HOSTNAME_FULL\(\s\)/\1$NEW_HOSTNAME_FULL\2/g" -e "s/\(\s\)$CURRENT_HOSTNAME_FULL$/\1$NEW_HOSTNAME_FULL/g" /etc/hosts + fi + if grep -w "$CURRENT_HOSTNAME_SHORT" /etc/hosts; then + sed -i -e "s/\(\s\)$CURRENT_HOSTNAME_SHORT\(\s\)/\1$NEW_HOSTNAME_SHORT\2/g" -e "s/\(\s\)$CURRENT_HOSTNAME_SHORT$/\1$NEW_HOSTNAME_SHORT/g" /etc/hosts + fi + + EOH + end + end + end + end + end +end diff --git a/plugins/guests/alt/cap/configure_networks.rb b/plugins/guests/alt/cap/configure_networks.rb new file mode 100644 index 000000000..acca141db --- /dev/null +++ b/plugins/guests/alt/cap/configure_networks.rb @@ -0,0 +1,118 @@ +require "tempfile" + +require_relative "../../../../lib/vagrant/util/template_renderer" + +module VagrantPlugins + module GuestALT + module Cap + class ConfigureNetworks + include Vagrant::Util + extend Vagrant::Util::GuestInspection::Linux + + def self.configure_networks(machine, networks) + comm = machine.communicate + + network_scripts_dir = machine.guest.capability(:network_scripts_dir) + + commands = {:start => [], :middle => [], :end => []} + interfaces = machine.guest.capability(:network_interfaces) + + # Check if NetworkManager is installed on the system + nmcli_installed = nmcli?(comm) + networks.each.with_index do |network, i| + network[:device] = interfaces[network[:interface]] + extra_opts = machine.config.vm.networks[i].last.dup + + if nmcli_installed + # Now check if the device is actively being managed by NetworkManager + nm_controlled = nm_controlled?(comm, network[:device]) + end + + if !extra_opts.key?(:nm_controlled) + extra_opts[:nm_controlled] = !!nm_controlled + end + + extra_opts[:nm_controlled] = case extra_opts[:nm_controlled] + when true + "yes" + when false, nil + "no" + else + extra_opts[:nm_controlled].to_s + end + + if extra_opts[:nm_controlled] == "yes" && !nmcli_installed + raise Vagrant::Errors::NetworkManagerNotInstalled, device: network[:device] + end + + # Render a new configuration + template_options = network.merge(extra_opts) + options_entry = TemplateRenderer.render("guests/alt/network_#{network[:type]}", options: template_options) + + # Upload the new configuration + options_remote_path = "/tmp/vagrant-network-entry-#{network[:device]}-#{Time.now.to_i}-#{i}" + ipv4_address_remote_path = "/tmp/vagrant-network-ipv4-address-entry-#{network[:device]}-#{Time.now.to_i}-#{i}" + ipv4_route_remote_path = "/tmp/vagrant-network-ipv4-route-entry-#{network[:device]}-#{Time.now.to_i}-#{i}" + + Tempfile.open("vagrant-alt-configure-networks") do |f| + f.binmode + f.write(options_entry) + f.fsync + f.close + machine.communicate.upload(f.path, options_remote_path) + end + + # Add the new interface and bring it back up + iface_path = "#{network_scripts_dir}/ifaces/#{network[:device]}" + + if network[:type].to_sym == :static + ipv4_address_entry = TemplateRenderer.render("guests/alt/network_ipv4address", options: template_options) + + # Upload the new ipv4address configuration + Tempfile.open("vagrant-alt-configure-ipv4-address") do |f| + f.binmode + f.write(ipv4_address_entry) + f.fsync + f.close + machine.communicate.upload(f.path, ipv4_address_remote_path) + end + + ipv4_route_entry = TemplateRenderer.render("guests/alt/network_ipv4route", options: template_options) + + # Upload the new ipv4route configuration + Tempfile.open("vagrant-alt-configure-ipv4-route") do |f| + f.binmode + f.write(ipv4_route_entry) + f.fsync + f.close + machine.communicate.upload(f.path, ipv4_route_remote_path) + end + end + + if nm_controlled + commands[:start] << "nmcli d disconnect iface '#{network[:device]}'" + else + commands[:start] << "/sbin/ifdown '#{network[:device]}'" + end + commands[:middle] << "mkdir -p '#{iface_path}'" + commands[:middle] << "mv -f '#{options_remote_path}' '#{iface_path}/options'" + if network[:type].to_sym == :static + commands[:middle] << "mv -f '#{ipv4_address_remote_path}' '#{iface_path}/ipv4address'" + commands[:middle] << "mv -f '#{ipv4_route_remote_path}' '#{iface_path}/ipv4route'" + end + if extra_opts[:nm_controlled] == "no" + commands[:end] << "/sbin/ifup '#{network[:device]}'" + end + end + if nmcli_installed + commands[:middle] << "(test -f /etc/init.d/NetworkManager && /etc/init.d/NetworkManager restart) || " \ + "((systemctl | grep NetworkManager.service) && systemctl restart NetworkManager)" + end + commands = commands[:start] + commands[:middle] + commands[:end] + comm.sudo(commands.join("\n")) + comm.wait_for_ready(5) + end + end + end + end +end diff --git a/plugins/guests/alt/cap/flavor.rb b/plugins/guests/alt/cap/flavor.rb new file mode 100644 index 000000000..a9b1ae017 --- /dev/null +++ b/plugins/guests/alt/cap/flavor.rb @@ -0,0 +1,37 @@ +module VagrantPlugins + module GuestALT + module Cap + class Flavor + def self.flavor(machine) + # Read the version file + if !comm.test("test -f /etc/os-release") + version = nil + machine.communicate.sudo("grep VERSION_ID /etc/os-release") do |type, data| + if type == :stdout + version = data.split("=")[1].chomp.to_i + end + end + + if version.nil? + return :alt + else + return :"alt_#{version}" + end + else + output = "" + machine.communicate.sudo("cat /etc/altlinux-release") do |_, data| + output = data + end + + # Detect various flavors we care about + if output =~ /(ALT Workstation K|ALT Linux starter kit)\s*8( .+)?/i + return :alt_8 + else + return :alt + end + end + end + end + end + end +end diff --git a/plugins/guests/alt/cap/network_scripts_dir.rb b/plugins/guests/alt/cap/network_scripts_dir.rb new file mode 100644 index 000000000..1a867c4e9 --- /dev/null +++ b/plugins/guests/alt/cap/network_scripts_dir.rb @@ -0,0 +1,11 @@ +module VagrantPlugins + module GuestALT + module Cap + class NetworkScriptsDir + def self.network_scripts_dir(machine) + "/etc/net" + end + end + end + end +end diff --git a/plugins/guests/alt/cap/rsync.rb b/plugins/guests/alt/cap/rsync.rb new file mode 100644 index 000000000..998315142 --- /dev/null +++ b/plugins/guests/alt/cap/rsync.rb @@ -0,0 +1,13 @@ +module VagrantPlugins + module GuestALT + module Cap + class RSync + def self.rsync_install(machine) + machine.communicate.sudo <<-EOH.gsub(/^ {12}/, '') + apt-get install -y -qq install rsync + EOH + end + end + end + end +end diff --git a/plugins/guests/alt/guest.rb b/plugins/guests/alt/guest.rb new file mode 100644 index 000000000..08525d5e6 --- /dev/null +++ b/plugins/guests/alt/guest.rb @@ -0,0 +1,9 @@ +module VagrantPlugins + module GuestALT + class Guest < Vagrant.plugin("2", :guest) + def detect?(machine) + machine.communicate.test("cat /etc/altlinux-release") + end + end + end +end diff --git a/plugins/guests/alt/plugin.rb b/plugins/guests/alt/plugin.rb new file mode 100644 index 000000000..d6375f5ea --- /dev/null +++ b/plugins/guests/alt/plugin.rb @@ -0,0 +1,40 @@ +require "vagrant" + +module VagrantPlugins + module GuestALT + class Plugin < Vagrant.plugin("2") + name "ALT Platform guest" + description "ALT Platform guest support." + + guest(:alt, :redhat) do + require_relative "guest" + Guest + end + + guest_capability(:alt, :change_host_name) do + require_relative "cap/change_host_name" + Cap::ChangeHostName + end + + guest_capability(:alt, :configure_networks) do + require_relative "cap/configure_networks" + Cap::ConfigureNetworks + end + + guest_capability(:alt, :flavor) do + require_relative "cap/flavor" + Cap::Flavor + end + + guest_capability(:alt, :network_scripts_dir) do + require_relative "cap/network_scripts_dir" + Cap::NetworkScriptsDir + end + + guest_capability(:alt, :rsync_install) do + require_relative "cap/rsync" + Cap::RSync + end + end + end +end diff --git a/templates/guests/alt/network_dhcp.erb b/templates/guests/alt/network_dhcp.erb new file mode 100644 index 000000000..8d9f1a93a --- /dev/null +++ b/templates/guests/alt/network_dhcp.erb @@ -0,0 +1,7 @@ +#VAGRANT-BEGIN +# The contents below are automatically generated by Vagrant. Do not modify. +TYPE=eth +NM_CONTROLLED=<%= options.fetch(:nm_controlled, "no") %> +BOOTPROTO=dhcp +ONBOOT=yes +#VAGRANT-END diff --git a/templates/guests/alt/network_ipv4address.erb b/templates/guests/alt/network_ipv4address.erb new file mode 100644 index 000000000..dbd3340b4 --- /dev/null +++ b/templates/guests/alt/network_ipv4address.erb @@ -0,0 +1,3 @@ +#VAGRANT-BEGIN +<%= options[:ip] %>/<%= options[:netmask] %> +#VAGRANT-END diff --git a/templates/guests/alt/network_ipv4route.erb b/templates/guests/alt/network_ipv4route.erb new file mode 100644 index 000000000..fe0bea446 --- /dev/null +++ b/templates/guests/alt/network_ipv4route.erb @@ -0,0 +1,5 @@ +#VAGRANT-BEGIN +<% if options[:gateway] %> +default via <%= options[:gateway] %> +<% end %> +#VAGRANT-END diff --git a/templates/guests/alt/network_static.erb b/templates/guests/alt/network_static.erb new file mode 100644 index 000000000..84ceac55c --- /dev/null +++ b/templates/guests/alt/network_static.erb @@ -0,0 +1,7 @@ +#VAGRANT-BEGIN +# The contents below are automatically generated by Vagrant. Do not modify. +TYPE=eth +NM_CONTROLLED=<%= options.fetch(:nm_controlled, "no") %> +BOOTPROTO=static +ONBOOT=yes +#VAGRANT-END From 88c0cb855f33c605503a004f9ff3a2ed7dff2518 Mon Sep 17 00:00:00 2001 From: Evgeny Sinelnikov Date: Sat, 8 Jul 2017 21:27:19 +0300 Subject: [PATCH 2/6] guests/alt: Update network configuration Fix network mask to CIDR notation and network configure stop and restart commands with NetworkManager --- plugins/guests/alt/cap/configure_networks.rb | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/plugins/guests/alt/cap/configure_networks.rb b/plugins/guests/alt/cap/configure_networks.rb index acca141db..851849700 100644 --- a/plugins/guests/alt/cap/configure_networks.rb +++ b/plugins/guests/alt/cap/configure_networks.rb @@ -47,6 +47,14 @@ module VagrantPlugins # Render a new configuration template_options = network.merge(extra_opts) + + # ALT expects netmasks to be in the CIDR notation, but users may + # specify IPV4 netmasks like "255.255.255.0". This magic converts + # the netmask to the proper value. + if template_options[:netmask] && template_options[:netmask].to_s.include?(".") + template_options[:netmask] = (32-Math.log2((IPAddr.new(template_options[:netmask], Socket::AF_INET).to_i^0xffffffff)+1)).to_i + end + options_entry = TemplateRenderer.render("guests/alt/network_#{network[:type]}", options: template_options) # Upload the new configuration @@ -89,7 +97,7 @@ module VagrantPlugins end end - if nm_controlled + if nm_controlled and extra_opts[:nm_controlled] == "yes" commands[:start] << "nmcli d disconnect iface '#{network[:device]}'" else commands[:start] << "/sbin/ifdown '#{network[:device]}'" @@ -105,8 +113,8 @@ module VagrantPlugins end end if nmcli_installed - commands[:middle] << "(test -f /etc/init.d/NetworkManager && /etc/init.d/NetworkManager restart) || " \ - "((systemctl | grep NetworkManager.service) && systemctl restart NetworkManager)" + commands[:middle] << "((systemctl | grep NetworkManager.service) && systemctl restart NetworkManager) || " \ + "(test -f /etc/init.d/NetworkManager && /etc/init.d/NetworkManager restart)" end commands = commands[:start] + commands[:middle] + commands[:end] comm.sudo(commands.join("\n")) From 26f7a04b86febf34b6654ab55b184dbec2361592 Mon Sep 17 00:00:00 2001 From: Evgeny Sinelnikov Date: Sat, 8 Jul 2017 21:36:18 +0300 Subject: [PATCH 3/6] hosts/alt: Add hosts capabilities for ALT Linux platforms --- plugins/hosts/alt/cap/nfs.rb | 43 ++++++++++++++++++++++++++++++++++++ plugins/hosts/alt/host.rb | 11 +++++++++ plugins/hosts/alt/plugin.rb | 32 +++++++++++++++++++++++++++ 3 files changed, 86 insertions(+) create mode 100644 plugins/hosts/alt/cap/nfs.rb create mode 100644 plugins/hosts/alt/host.rb create mode 100644 plugins/hosts/alt/plugin.rb diff --git a/plugins/hosts/alt/cap/nfs.rb b/plugins/hosts/alt/cap/nfs.rb new file mode 100644 index 000000000..ed68f4a92 --- /dev/null +++ b/plugins/hosts/alt/cap/nfs.rb @@ -0,0 +1,43 @@ +require "vagrant/util/subprocess" +require "vagrant/util/which" + +module VagrantPlugins + module HostALT + module Cap + class NFS + def self.nfs_check_command(env) + if systemd? + return "systemctl status --no-pager nfs-server.service" + else + return "/etc/init.d/nfs status" + end + end + + def self.nfs_start_command(env) + if systemd? + return "systemctl start rpcbind nfs-server.service" + else + return "/etc/init.d/nfs restart" + end + end + + def self.nfs_installed(environment) + if systemd? + system("systemctl --no-pager --no-legend --plain list-unit-files --all --type=service | grep --fixed-strings --quiet nfs-server.service") + else + system("rpm -q nfs-server --quiet 2>&1") + end + end + + protected + + # This tests to see if systemd is used on the system. This is used + # in newer versions of ALT, and requires a change in behavior. + def self.systemd? + result = Vagrant::Util::Subprocess.execute("ps", "-o", "comm=", "1") + return result.stdout.chomp == "systemd" + end + end + end + end +end diff --git a/plugins/hosts/alt/host.rb b/plugins/hosts/alt/host.rb new file mode 100644 index 000000000..2719f2b7e --- /dev/null +++ b/plugins/hosts/alt/host.rb @@ -0,0 +1,11 @@ +require "vagrant" + +module VagrantPlugins + module HostALT + class Host < Vagrant.plugin("2", :host) + def detect?(env) + File.exist?("/etc/altlinux-release") + end + end + end +end diff --git a/plugins/hosts/alt/plugin.rb b/plugins/hosts/alt/plugin.rb new file mode 100644 index 000000000..b8c8886b7 --- /dev/null +++ b/plugins/hosts/alt/plugin.rb @@ -0,0 +1,32 @@ +require "vagrant" + +module VagrantPlugins + module HostALT + class Plugin < Vagrant.plugin("2") + name "ALT Platform host" + description "ALT Platform host support." + + host("alt", "linux") do + require_relative "host" + Host + end + + host_capability("alt", "nfs_installed") do + require_relative "cap/nfs" + Cap::NFS + end + + # Linux-specific helpers we need to determine paths that can + # be overriden. + host_capability("alt", "nfs_check_command") do + require_relative "cap/nfs" + Cap::NFS + end + + host_capability("alt", "nfs_start_command") do + require_relative "cap/nfs" + Cap::NFS + end + end + end +end From 6ef55c172d1c98caefb5b270c2dab98edd3db1f1 Mon Sep 17 00:00:00 2001 From: Evgeny Sinelnikov Date: Sun, 9 Jul 2017 18:16:25 +0300 Subject: [PATCH 4/6] guests/alt: Adjust flavour detect and restart network after set hostname --- plugins/guests/alt/cap/change_host_name.rb | 2 ++ plugins/guests/alt/cap/flavor.rb | 15 ++++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/plugins/guests/alt/cap/change_host_name.rb b/plugins/guests/alt/cap/change_host_name.rb index 3d0333a37..a2c7b8453 100644 --- a/plugins/guests/alt/cap/change_host_name.rb +++ b/plugins/guests/alt/cap/change_host_name.rb @@ -35,6 +35,8 @@ module VagrantPlugins sed -i -e "s/\(\s\)$CURRENT_HOSTNAME_SHORT\(\s\)/\1$NEW_HOSTNAME_SHORT\2/g" -e "s/\(\s\)$CURRENT_HOSTNAME_SHORT$/\1$NEW_HOSTNAME_SHORT/g" /etc/hosts fi + # Restart network + service network restart EOH end end diff --git a/plugins/guests/alt/cap/flavor.rb b/plugins/guests/alt/cap/flavor.rb index a9b1ae017..77723f860 100644 --- a/plugins/guests/alt/cap/flavor.rb +++ b/plugins/guests/alt/cap/flavor.rb @@ -5,6 +5,17 @@ module VagrantPlugins def self.flavor(machine) # Read the version file if !comm.test("test -f /etc/os-release") + name = nil + machine.communicate.sudo("grep NAME /etc/os-release") do |type, data| + if type == :stdout + name = data.split("=")[1].chomp.to_i + end + end + + if name.nil? and name == "Sisyphus" + return :alt + end + version = nil machine.communicate.sudo("grep VERSION_ID /etc/os-release") do |type, data| if type == :stdout @@ -24,7 +35,9 @@ module VagrantPlugins end # Detect various flavors we care about - if output =~ /(ALT Workstation K|ALT Linux starter kit)\s*8( .+)?/i + if output =~ /(ALT SP|ALT Workstation|ALT Workstation K|ALT Linux starter kit)\s*8( .+)?/i + return :alt_8 + elsif output =~ /ALT\s*8( .+)?\s.+/i return :alt_8 else return :alt From 5ff176a82ccd8dc9573b23b5308f6b213c83e8f8 Mon Sep 17 00:00:00 2001 From: Evgeny Sinelnikov Date: Mon, 10 Jul 2017 00:52:24 +0300 Subject: [PATCH 5/6] guests/alt: capability tests for ALT Platforms --- .../guests/alt/cap/change_host_name_test.rb | 42 ++++ .../guests/alt/cap/configure_networks_test.rb | 214 ++++++++++++++++++ .../plugins/guests/alt/cap/flavor_test.rb | 43 ++++ .../alt/cap/network_scripts_dir_test.rb | 21 ++ .../unit/plugins/guests/alt/cap/rsync_test.rb | 29 +++ 5 files changed, 349 insertions(+) create mode 100644 test/unit/plugins/guests/alt/cap/change_host_name_test.rb create mode 100644 test/unit/plugins/guests/alt/cap/configure_networks_test.rb create mode 100644 test/unit/plugins/guests/alt/cap/flavor_test.rb create mode 100644 test/unit/plugins/guests/alt/cap/network_scripts_dir_test.rb create mode 100644 test/unit/plugins/guests/alt/cap/rsync_test.rb diff --git a/test/unit/plugins/guests/alt/cap/change_host_name_test.rb b/test/unit/plugins/guests/alt/cap/change_host_name_test.rb new file mode 100644 index 000000000..51eb814b6 --- /dev/null +++ b/test/unit/plugins/guests/alt/cap/change_host_name_test.rb @@ -0,0 +1,42 @@ +require_relative "../../../../base" + +describe "VagrantPlugins::GuestALT::Cap::ChangeHostName" do + let(:caps) do + VagrantPlugins::GuestALT::Plugin + .components + .guest_capabilities[:alt] + end + + let(:machine) { double("machine") } + let(:comm) { VagrantTests::DummyCommunicator::Communicator.new(machine) } + + before do + allow(machine).to receive(:communicate).and_return(comm) + end + + after do + comm.verify_expectations! + end + + describe ".change_host_name" do + let(:cap) { caps.get(:change_host_name) } + + let(:name) { "banana-rama.example.com" } + + it "sets the hostname" do + comm.stub_command("hostname -f | grep '^#{name}$'", exit_code: 1) + + cap.change_host_name(machine, name) + expect(comm.received_commands[1]).to match(/\/etc\/sysconfig\/network/) + expect(comm.received_commands[1]).to match(/hostnamectl set-hostname --static '#{name}'/) + expect(comm.received_commands[1]).to match(/hostnamectl set-hostname --transient '#{name}'/) + expect(comm.received_commands[1]).to match(/service network restart/) + end + + it "does not change the hostname if already set" do + comm.stub_command("hostname -f | grep '^#{name}$'", exit_code: 0) + cap.change_host_name(machine, name) + expect(comm.received_commands.size).to eq(1) + end + end +end diff --git a/test/unit/plugins/guests/alt/cap/configure_networks_test.rb b/test/unit/plugins/guests/alt/cap/configure_networks_test.rb new file mode 100644 index 000000000..c736a5f3f --- /dev/null +++ b/test/unit/plugins/guests/alt/cap/configure_networks_test.rb @@ -0,0 +1,214 @@ +require_relative "../../../../base" + +describe "VagrantPlugins::GuestALT::Cap::ConfigureNetworks" do + let(:caps) do + VagrantPlugins::GuestALT::Plugin + .components + .guest_capabilities[:alt] + end + + let(:comm) { VagrantTests::DummyCommunicator::Communicator.new(machine) } + let(:config) { double("config", vm: vm) } + let(:guest) { double("guest") } + let(:machine) { double("machine", guest: guest, config: config) } + let(:networks){ [[{}], [{}]] } + let(:vm){ double("vm", networks: networks) } + + before do + allow(machine).to receive(:communicate).and_return(comm) + end + + after do + comm.verify_expectations! + end + + describe ".configure_networks" do + let(:cap) { caps.get(:configure_networks) } + + before do + allow(guest).to receive(:capability) + .with(:flavor) + .and_return(:alt) + + allow(guest).to receive(:capability) + .with(:network_scripts_dir) + .and_return("/etc/net") + + allow(guest).to receive(:capability) + .with(:network_interfaces) + .and_return(["eth1", "eth2"]) + end + + let(:network_1) do + { + interface: 0, + type: "dhcp", + } + end + + let(:network_2) do + { + interface: 1, + type: "static", + ip: "33.33.33.10", + netmask: "255.255.0.0", + gateway: "33.33.0.1", + } + end + + context "with NetworkManager installed" do + before do + allow(cap).to receive(:nmcli?).and_return true + end + + context "with devices managed by NetworkManager" do + before do + allow(cap).to receive(:nm_controlled?).and_return true + end + + context "with nm_controlled option omitted" do + it "downs networks manually, creates ifaces, starts networks manually and restart NetworksManager" do + cap.configure_networks(machine, [network_1, network_2]) + expect(comm.received_commands[0]).to match(/ifdown/) + expect(comm.received_commands[0]).to match(/mkdir.*\/etc\/net\/ifaces/) + expect(comm.received_commands[0]).to match(/ifup/) + expect(comm.received_commands[0]).to match(/NetworkManager/) + expect(comm.received_commands[0]).to_not match(/nmcli/) + end + end + + context "with nm_controlled option set to true" do + let(:networks){ [[{nm_controlled: true}], [{nm_controlled: true}]] } + + it "downs networks via nmcli, creates ifaces and restart NetworksManager" do + cap.configure_networks(machine, [network_1, network_2]) + expect(comm.received_commands[0]).to match(/nmcli.*disconnect/) + expect(comm.received_commands[0]).to match(/mkdir.*\/etc\/net\/ifaces/) + expect(comm.received_commands[0]).to match(/NetworkManager/) + expect(comm.received_commands[0]).to_not match(/(ifdown|ifup)/) + end + end + + context "with nm_controlled option set to false" do + let(:networks){ [[{nm_controlled: false}], [{nm_controlled: false}]] } + + it "downs networks manually, creates ifaces, starts networks manually and restart NetworksManager" do + cap.configure_networks(machine, [network_1, network_2]) + expect(comm.received_commands[0]).to match(/ifdown/) + expect(comm.received_commands[0]).to match(/mkdir.*\/etc\/net\/ifaces/) + expect(comm.received_commands[0]).to match(/ifup/) + expect(comm.received_commands[0]).to match(/NetworkManager/) + expect(comm.received_commands[0]).to_not match(/nmcli/) + end + end + + context "with nm_controlled option set to false on first device" do + let(:networks){ [[{nm_controlled: false}], [{nm_controlled: true}]] } + + it "downs networks, creates ifaces and starts the networks with one managed manually and one NetworkManager controlled" do + cap.configure_networks(machine, [network_1, network_2]) + expect(comm.received_commands[0]).to match(/ifdown/) + expect(comm.received_commands[0]).to match(/nmcli.*disconnect/) + expect(comm.received_commands[0]).to match(/mkdir.*\/etc\/net\/ifaces/) + expect(comm.received_commands[0]).to match(/ifup/) + expect(comm.received_commands[0]).to match(/NetworkManager/) + end + end + end + + context "with devices not managed by NetworkManager" do + before do + allow(cap).to receive(:nm_controlled?).and_return false + end + + context "with nm_controlled option omitted" do + it "creates and starts the networks manually" do + cap.configure_networks(machine, [network_1, network_2]) + expect(comm.received_commands[0]).to match(/ifdown/) + expect(comm.received_commands[0]).to match(/mkdir.*\/etc\/net\/ifaces/) + expect(comm.received_commands[0]).to match(/ifup/) + expect(comm.received_commands[0]).to match(/NetworkManager/) + expect(comm.received_commands[0]).to_not match(/nmcli/) + end + end + + context "with nm_controlled option set to true" do + let(:networks){ [[{nm_controlled: true}], [{nm_controlled: true}]] } + + it "creates and starts the networks via nmcli" do + cap.configure_networks(machine, [network_1, network_2]) + expect(comm.received_commands[0]).to match(/ifdown/) + expect(comm.received_commands[0]).to match(/mkdir.*\/etc\/net\/ifaces/) + expect(comm.received_commands[0]).to match(/NetworkManager/) + expect(comm.received_commands[0]).to_not match(/ifup/) + end + end + + context "with nm_controlled option set to false" do + let(:networks){ [[{nm_controlled: false}], [{nm_controlled: false}]] } + + it "creates and starts the networks via ifup " do + cap.configure_networks(machine, [network_1, network_2]) + expect(comm.received_commands[0]).to match(/ifdown/) + expect(comm.received_commands[0]).to match(/mkdir.*\/etc\/net\/ifaces/) + expect(comm.received_commands[0]).to match(/ifup/) + expect(comm.received_commands[0]).to match(/NetworkManager/) + expect(comm.received_commands[0]).to_not match(/nmcli/) + end + end + + context "with nm_controlled option set to false on first device" do + let(:networks){ [[{nm_controlled: false}], [{nm_controlled: true}]] } + + it "creates and starts the networks with one managed manually and one NetworkManager controlled" do + cap.configure_networks(machine, [network_1, network_2]) + expect(comm.received_commands[0]).to match(/ifdown/) + expect(comm.received_commands[0]).to match(/mkdir.*\/etc\/net\/ifaces/) + expect(comm.received_commands[0]).to match(/ifup/) + expect(comm.received_commands[0]).to match(/NetworkManager/) + expect(comm.received_commands[0]).to_not match(/nmcli.*disconnect/) + end + end + end + end + + context "without NetworkManager installed" do + before do + allow(cap).to receive(:nmcli?).and_return false + end + + context "with nm_controlled option omitted" do + + it "creates and starts the networks manually" do + cap.configure_networks(machine, [network_1, network_2]) + expect(comm.received_commands[0]).to match(/ifdown/) + expect(comm.received_commands[0]).to match(/mkdir.*\/etc\/net\/ifaces/) + expect(comm.received_commands[0]).to match(/ifup/) + expect(comm.received_commands[0]).to_not match(/nmcli/) + expect(comm.received_commands[0]).to_not match(/NetworkManager/) + end + end + + context "with nm_controlled option omitted" do + let(:networks){ [[{nm_controlled: false}], [{nm_controlled: false}]] } + + it "creates and starts the networks manually" do + cap.configure_networks(machine, [network_1, network_2]) + expect(comm.received_commands[0]).to match(/ifdown/) + expect(comm.received_commands[0]).to match(/mkdir.*\/etc\/net\/ifaces/) + expect(comm.received_commands[0]).to match(/ifup/) + expect(comm.received_commands[0]).to_not match(/nmcli/) + expect(comm.received_commands[0]).to_not match(/NetworkManager/) + end + end + + context "with nm_controlled option set" do + let(:networks){ [[{nm_controlled: false}], [{nm_controlled: true}]] } + + it "raises an error" do + expect{ cap.configure_networks(machine, [network_1, network_2]) }.to raise_error(Vagrant::Errors::NetworkManagerNotInstalled) + end + end + end + end +end diff --git a/test/unit/plugins/guests/alt/cap/flavor_test.rb b/test/unit/plugins/guests/alt/cap/flavor_test.rb new file mode 100644 index 000000000..d7dacd728 --- /dev/null +++ b/test/unit/plugins/guests/alt/cap/flavor_test.rb @@ -0,0 +1,43 @@ +require_relative "../../../../base" + +describe "VagrantPlugins::GuestALT::Cap::Flavor" do + let(:caps) do + VagrantPlugins::GuestALT::Plugin + .components + .guest_capabilities[:alt] + end + + let(:machine) { double("machine") } + let(:comm) { VagrantTests::DummyCommunicator::Communicator.new(machine) } + + before do + allow(machine).to receive(:communicate).and_return(comm) + end + + after do + comm.verify_expectations! + end + + describe ".flavor" do + let(:cap) { caps.get(:flavor) } + + { + "ALT Education 8.1" => :alt, + "ALT Workstation 8.1" => :alt, + "ALT Workstation K 8.1 (Centaurea Ruthenica)" => :alt, + "ALT Linux p8 (Hypericum)" => :alt, + "ALT Sisyphus (unstable) (sisyphus)" => :alt, + + "ALT Linux 6.0.1 Spt (separator)" => :alt, + "ALT Linux 7.0.5 School Master" => :alt, + "ALT starter kit (Hypericum)" => :alt, + + "ALT" => :alt, + }.each do |str, expected| + it "returns #{expected} for #{str}" do + comm.stub_command("cat /etc/altlinux-release", stdout: str) + expect(cap.flavor(machine)).to be(expected) + end + end + end +end diff --git a/test/unit/plugins/guests/alt/cap/network_scripts_dir_test.rb b/test/unit/plugins/guests/alt/cap/network_scripts_dir_test.rb new file mode 100644 index 000000000..4aac58069 --- /dev/null +++ b/test/unit/plugins/guests/alt/cap/network_scripts_dir_test.rb @@ -0,0 +1,21 @@ +require_relative "../../../../base" + +describe "VagrantPlugins::GuestALT::Cap::NetworkScriptsDir" do + let(:caps) do + VagrantPlugins::GuestALT::Plugin + .components + .guest_capabilities[:alt] + end + + let(:machine) { double("machine") } + + describe ".network_scripts_dir" do + let(:cap) { caps.get(:network_scripts_dir) } + + let(:name) { "banana-rama.example.com" } + + it "is /etc/net" do + expect(cap.network_scripts_dir(machine)).to eq("/etc/net") + end + end +end diff --git a/test/unit/plugins/guests/alt/cap/rsync_test.rb b/test/unit/plugins/guests/alt/cap/rsync_test.rb new file mode 100644 index 000000000..126db9963 --- /dev/null +++ b/test/unit/plugins/guests/alt/cap/rsync_test.rb @@ -0,0 +1,29 @@ +require_relative "../../../../base" + +describe "VagrantPlugins::GuestALT::Cap:RSync" do + let(:caps) do + VagrantPlugins::GuestALT::Plugin + .components + .guest_capabilities[:alt] + end + + let(:machine) { double("machine") } + let(:comm) { VagrantTests::DummyCommunicator::Communicator.new(machine) } + + before do + allow(machine).to receive(:communicate).and_return(comm) + end + + after do + comm.verify_expectations! + end + + describe ".rsync_install" do + let(:cap) { caps.get(:rsync_install) } + + it "installs rsync" do + cap.rsync_install(machine) + expect(comm.received_commands[0]).to match(/install rsync/) + end + end +end From 015d98e76c394aa1828d0ac33eca8708bcf1c4b3 Mon Sep 17 00:00:00 2001 From: Evgeny Sinelnikov Date: Mon, 10 Jul 2017 03:08:27 +0300 Subject: [PATCH 6/6] guests/alt: Fix flavor and network configure with unit tests --- plugins/guests/alt/cap/flavor.rb | 33 +++++++---- .../guests/alt/cap/configure_networks_test.rb | 7 +-- .../plugins/guests/alt/cap/flavor_test.rb | 57 ++++++++++++++----- 3 files changed, 69 insertions(+), 28 deletions(-) diff --git a/plugins/guests/alt/cap/flavor.rb b/plugins/guests/alt/cap/flavor.rb index 77723f860..9cbff908c 100644 --- a/plugins/guests/alt/cap/flavor.rb +++ b/plugins/guests/alt/cap/flavor.rb @@ -3,41 +3,54 @@ module VagrantPlugins module Cap class Flavor def self.flavor(machine) + comm = machine.communicate + # Read the version file - if !comm.test("test -f /etc/os-release") + if comm.test("test -f /etc/os-release") name = nil - machine.communicate.sudo("grep NAME /etc/os-release") do |type, data| + comm.sudo("grep NAME /etc/os-release") do |type, data| if type == :stdout - name = data.split("=")[1].chomp.to_i + name = data.split("=")[1].gsub!(/\A"|"\Z/, '') end end - if name.nil? and name == "Sisyphus" + if !name.nil? and name == "Sisyphus" return :alt end version = nil - machine.communicate.sudo("grep VERSION_ID /etc/os-release") do |type, data| + comm.sudo("grep VERSION_ID /etc/os-release") do |type, data| if type == :stdout - version = data.split("=")[1].chomp.to_i + verstr = data.split("=")[1] + if verstr == "p8" + version = 8 + elsif verstr =~ /^[[\d]]/ + version = verstr.chomp.to_i + subversion = verstr.chomp.split(".")[1].to_i + if subversion > 90 + version += 1 + end + end end end - if version.nil? + if version.nil? or version == 0 return :alt else return :"alt_#{version}" end else output = "" - machine.communicate.sudo("cat /etc/altlinux-release") do |_, data| + comm.sudo("cat /etc/altlinux-release") do |_, data| output = data end # Detect various flavors we care about - if output =~ /(ALT SP|ALT Workstation|ALT Workstation K|ALT Linux starter kit)\s*8( .+)?/i + if output =~ /(ALT SP|ALT Education|ALT Workstation|ALT Workstation K|ALT Linux starter kit)\s*8(\.[1-9])?( .+)?/i return :alt_8 - elsif output =~ /ALT\s*8( .+)?\s.+/i + elsif output =~ /ALT\s+8(\.[1-9])?( .+)?\s.+/i + return :alt_8 + elsif output =~ /ALT Linux p8( .+)?/i return :alt_8 else return :alt diff --git a/test/unit/plugins/guests/alt/cap/configure_networks_test.rb b/test/unit/plugins/guests/alt/cap/configure_networks_test.rb index c736a5f3f..f19924d0f 100644 --- a/test/unit/plugins/guests/alt/cap/configure_networks_test.rb +++ b/test/unit/plugins/guests/alt/cap/configure_networks_test.rb @@ -67,13 +67,12 @@ describe "VagrantPlugins::GuestALT::Cap::ConfigureNetworks" do end context "with nm_controlled option omitted" do - it "downs networks manually, creates ifaces, starts networks manually and restart NetworksManager" do + it "downs networks via nmcli, creates ifaces and restart NetworksManager" do cap.configure_networks(machine, [network_1, network_2]) - expect(comm.received_commands[0]).to match(/ifdown/) + expect(comm.received_commands[0]).to match(/nmcli.*disconnect/) expect(comm.received_commands[0]).to match(/mkdir.*\/etc\/net\/ifaces/) - expect(comm.received_commands[0]).to match(/ifup/) expect(comm.received_commands[0]).to match(/NetworkManager/) - expect(comm.received_commands[0]).to_not match(/nmcli/) + expect(comm.received_commands[0]).to_not match(/ifdown|ifup/) end end diff --git a/test/unit/plugins/guests/alt/cap/flavor_test.rb b/test/unit/plugins/guests/alt/cap/flavor_test.rb index d7dacd728..65538f0fe 100644 --- a/test/unit/plugins/guests/alt/cap/flavor_test.rb +++ b/test/unit/plugins/guests/alt/cap/flavor_test.rb @@ -21,22 +21,51 @@ describe "VagrantPlugins::GuestALT::Cap::Flavor" do describe ".flavor" do let(:cap) { caps.get(:flavor) } - { - "ALT Education 8.1" => :alt, - "ALT Workstation 8.1" => :alt, - "ALT Workstation K 8.1 (Centaurea Ruthenica)" => :alt, - "ALT Linux p8 (Hypericum)" => :alt, - "ALT Sisyphus (unstable) (sisyphus)" => :alt, + context "without /etc/os-release file" do + { + "ALT 8.1 Server" => :alt_8, + "ALT Education 8.1" => :alt_8, + "ALT Workstation 8.1" => :alt_8, + "ALT Workstation K 8.1 (Centaurea Ruthenica)" => :alt_8, + "ALT Linux p8 (Hypericum)" => :alt_8, - "ALT Linux 6.0.1 Spt (separator)" => :alt, - "ALT Linux 7.0.5 School Master" => :alt, - "ALT starter kit (Hypericum)" => :alt, + "ALT Sisyphus (unstable) (sisyphus)" => :alt, + "ALT Linux Sisyphus (unstable)" => :alt, + "ALT Linux 6.0.1 Spt (separator)" => :alt, + "ALT Linux 7.0.5 School Master" => :alt, + "ALT starter kit (Hypericum)" => :alt, - "ALT" => :alt, - }.each do |str, expected| - it "returns #{expected} for #{str}" do - comm.stub_command("cat /etc/altlinux-release", stdout: str) - expect(cap.flavor(machine)).to be(expected) + "ALT" => :alt, + "Simply" => :alt, + }.each do |str, expected| + it "returns #{expected} for #{str} in /etc/altlinux-release" do + comm.stub_command("test -f /etc/os-release", exit_code: 1) + comm.stub_command("cat /etc/altlinux-release", stdout: str) + expect(cap.flavor(machine)).to be(expected) + end + end + end + + context "with /etc/os-release file" do + { + [ "NAME=\"Sisyphus\"", "VERSION_ID=20161130" ] => :alt, + + [ "NAME=\"ALT Education\"", "VERSION_ID=8.1" ] => :alt_8, + [ "NAME=\"ALT Server\"", "VERSION_ID=8.1" ] => :alt_8, + [ "NAME=\"ALT SPServer\"", "VERSION_ID=8.0" ] => :alt_8, + [ "NAME=\"starter kit\"", "VERSION_ID=p8" ] => :alt_8, + [ "NAME=\"ALT Linux\"", "VERSION_ID=8.0.0" ] => :alt_8, + [ "NAME=\"Simply Linux\"", "VERSION_ID=7.95.0" ] => :alt_8, + + [ "NAME=\"ALT Linux\"", "VERSION_ID=7.0.5" ] => :alt_7, + [ "NAME=\"School Junior\"", "VERSION_ID=7.0.5" ] => :alt_7, + }.each do |strs, expected| + it "returns #{expected} for #{strs[0]} and #{strs[1]} in /etc/os-release" do + comm.stub_command("test -f /etc/os-release", exit_code: 0) + comm.stub_command("grep NAME /etc/os-release", stdout: strs[0]) + comm.stub_command("grep VERSION_ID /etc/os-release", stdout: strs[1]) + expect(cap.flavor(machine)).to be(expected) + end end end end