From 3dd90aa95512e75766019a1ead4470bf6e971bf3 Mon Sep 17 00:00:00 2001 From: Evgeny Sinelnikov Date: Sun, 2 Jul 2017 18:38:20 +0300 Subject: [PATCH] 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