Merge pull request #11791 from jbonhag/e/guest-openwrt

Guest support for OpenWrt
This commit is contained in:
Sophia Castellarin 2020-12-22 15:05:48 -06:00 committed by GitHub
commit a8363db300
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 403 additions and 0 deletions

View File

@ -0,0 +1,19 @@
module VagrantPlugins
module GuestOpenWrt
module Cap
class ChangeHostName
def self.change_host_name(machine, name)
comm = machine.communicate
if !comm.test("uci get system.@system[0].hostname | grep '^#{name}$'", sudo: false)
comm.execute <<~EOH
uci set system.@system[0].hostname='#{name}'
uci commit system
/etc/init.d/system reload
EOH
end
end
end
end
end
end

View File

@ -0,0 +1,16 @@
module VagrantPlugins
module GuestOpenWrt
module Cap
class Halt
def self.halt(machine)
begin
machine.communicate.execute("halt")
rescue IOError, Vagrant::Errors::SSHDisconnected
# Ignore, this probably means connection closed because it
# shut down.
end
end
end
end
end
end

View File

@ -0,0 +1,20 @@
require "vagrant/util/shell_quote"
module VagrantPlugins
module GuestOpenWrt
module Cap
class InsertPublicKey
def self.insert_public_key(machine, contents)
contents = contents.chomp
contents = Vagrant::Util::ShellQuote.escape(contents, "'")
machine.communicate.tap do |comm|
comm.execute <<~EOH
printf '#{contents}\\n' >> /etc/dropbear/authorized_keys
EOH
end
end
end
end
end
end

View File

@ -0,0 +1,22 @@
require "vagrant/util/shell_quote"
module VagrantPlugins
module GuestOpenWrt
module Cap
class RemovePublicKey
def self.remove_public_key(machine, contents)
contents = contents.chomp
contents = Vagrant::Util::ShellQuote.escape(contents, "'")
machine.communicate.tap do |comm|
comm.execute <<~EOH
if test -f /etc/dropbear/authorized_keys ; then
sed -i '/^.*#{contents}.*$/d' /etc/dropbear/authorized_keys
fi
EOH
end
end
end
end
end
end

View File

@ -0,0 +1,35 @@
module VagrantPlugins
module GuestOpenWrt
module Cap
class RSync
def self.rsync_installed(machine)
machine.communicate.test("which rsync")
end
def self.rsync_install(machine)
machine.communicate.tap do |comm|
comm.execute <<~EOH
opkg update
opkg install rsync
EOH
end
end
def self.rsync_pre(machine, opts)
machine.communicate.tap do |comm|
comm.execute("mkdir -p '#{opts[:guestpath]}'")
end
end
def self.rsync_command(machine)
"rsync -zz"
end
def self.rsync_post(machine, opts)
# Don't do anything because BusyBox's `find` doesn't support the
# syntax in plugins/synced_folders/rsync/default_unix_cap.rb.
end
end
end
end
end

View File

@ -0,0 +1,23 @@
module VagrantPlugins
module GuestOpenWrt
class Guest
# Name used for guest detection
GUEST_DETECTION_NAME = "openwrt".freeze
def detect?(machine)
machine.communicate.test <<~EOH
if test -e /etc/openwrt_release; then
exit
fi
if test -r /etc/os-release; then
source /etc/os-release && test 'x#{self.class.const_get(:GUEST_DETECTION_NAME)}' = "x$ID" && exit
fi
if test -r /etc/banner; then
cat /etc/banner | grep -qi '#{self.class.const_get(:GUEST_DETECTION_NAME)}' && exit
fi
exit 1
EOH
end
end
end
end

View File

@ -0,0 +1,61 @@
require "vagrant"
module VagrantPlugins
module GuestOpenWrt
class Plugin < Vagrant.plugin("2")
name "OpenWrt guest"
description "OpenWrt guest support."
guest(:openwrt, :linux) do
require_relative "guest"
Guest
end
guest_capability(:openwrt, :insert_public_key) do
require_relative "cap/insert_public_key"
Cap::InsertPublicKey
end
guest_capability(:openwrt, :remove_public_key) do
require_relative "cap/remove_public_key"
Cap::RemovePublicKey
end
guest_capability(:openwrt, :change_host_name) do
require_relative "cap/change_host_name"
Cap::ChangeHostName
end
guest_capability(:openwrt, :rsync_installed) do
require_relative "cap/rsync"
Cap::RSync
end
guest_capability(:openwrt, :rsync_install) do
require_relative "cap/rsync"
Cap::RSync
end
guest_capability(:openwrt, :rsync_pre) do
require_relative "cap/rsync"
Cap::RSync
end
guest_capability(:openwrt, :rsync_command) do
require_relative "cap/rsync"
Cap::RSync
end
guest_capability(:openwrt, :rsync_post) do
require_relative "cap/rsync"
Cap::RSync
end
guest_capability(:openwrt, :halt) do
require_relative "cap/halt"
Cap::Halt
end
end
end
end

View File

@ -0,0 +1,33 @@
require_relative "../../../../base"
describe "VagrantPlugins::GuestOpenWrt::Cap::ChangeHostName" do
let(:caps) do
VagrantPlugins::GuestOpenWrt::Plugin
.components
.guest_capabilities[:openwrt]
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) }
it "changes the hostname if appropriate" do
cap.change_host_name(machine, "testhost")
expect(comm.received_commands[0]).to match(/uci get system\.@system\[0\].hostname | grep '^testhost$'/)
expect(comm.received_commands[1]).to match(/uci set system.@system\[0\].hostname='testhost'/)
expect(comm.received_commands[1]).to match(/uci commit system/)
expect(comm.received_commands[1]).to match(/\/etc\/init.d\/system reload/)
end
end
end

View File

@ -0,0 +1,37 @@
require_relative "../../../../base"
describe "VagrantPlugins::GuestOpenWrt::Cap::Halt" do
let(:plugin) { VagrantPlugins::GuestOpenWrt::Plugin.components.guest_capabilities[:openwrt].get(:halt) }
let(:machine) { double("machine") }
let(:communicator) { VagrantTests::DummyCommunicator::Communicator.new(machine) }
let(:shutdown_command){ "halt" }
before do
allow(machine).to receive(:communicate).and_return(communicator)
end
after do
communicator.verify_expectations!
end
describe ".halt" do
it "sends a shutdown signal" do
communicator.expect_command(shutdown_command)
plugin.halt(machine)
end
it "ignores an IOError" do
communicator.stub_command(shutdown_command, raise: IOError)
expect {
plugin.halt(machine)
}.to_not raise_error
end
it "ignores a Vagrant::Errors::SSHDisconnected" do
communicator.stub_command(shutdown_command, raise: Vagrant::Errors::SSHDisconnected)
expect {
plugin.halt(machine)
}.to_not raise_error
end
end
end

View File

@ -0,0 +1,30 @@
require_relative "../../../../base"
describe "VagrantPlugins::GuestOpenWrt::Cap::InsertPublicKey" do
let(:caps) do
VagrantPlugins::GuestOpenWrt::Plugin
.components
.guest_capabilities[:openwrt]
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 ".insert_public_key" do
let(:cap) { caps.get(:insert_public_key) }
it "inserts the public key" do
cap.insert_public_key(machine, "ssh-rsa ...")
expect(comm.received_commands[0]).to match(/printf 'ssh-rsa ...\\n' >> \/etc\/dropbear\/authorized_keys/)
end
end
end

View File

@ -0,0 +1,31 @@
require_relative "../../../../base"
describe "VagrantPlugins::GuestOpenWrt::Cap::RemovePublicKey" do
let(:caps) do
VagrantPlugins::GuestOpenWrt::Plugin
.components
.guest_capabilities[:openwrt]
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 ".remove_public_key" do
let(:cap) { caps.get(:remove_public_key) }
it "removes the public key" do
cap.remove_public_key(machine, "ssh-rsa keyvalue comment")
expect(comm.received_commands[0]).to match(/if test -f \/etc\/dropbear\/authorized_keys ; then/)
expect(comm.received_commands[0]).to match(/sed -i '\/\^.*ssh-rsa keyvalue comment.*\$\/d' \/etc\/dropbear\/authorized_keys/)
expect(comm.received_commands[0]).to match(/fi/)
end
end
end

View File

@ -0,0 +1,76 @@
require_relative "../../../../base"
describe "VagrantPlugins::VagrantPlugins::Cap::Rsync" do
let(:caps) do
VagrantPlugins::GuestOpenWrt::Plugin
.components
.guest_capabilities[:openwrt]
end
let(:machine) { double("machine") }
let(:comm) { VagrantTests::DummyCommunicator::Communicator.new(machine) }
let(:guest_directory) { "/guest/directory/path" }
before do
allow(machine).to receive(:communicate).and_return(comm)
end
after do
comm.verify_expectations!
end
describe ".rsync_installed" do
let(:cap) { caps.get(:rsync_installed) }
describe "when rsync is in the path" do
it "is true" do
comm.stub_command("which rsync", stdout: '/usr/bin/rsync', exit_code: 0)
expect(cap.rsync_installed(machine)).to be true
end
end
describe "when rsync is not in the path" do
it "is false" do
comm.stub_command("which rsync", stdout: '', exit_code: 1)
expect(cap.rsync_installed(machine)).to be false
end
end
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(/opkg update/)
expect(comm.received_commands[0]).to match(/opkg install rsync/)
end
end
describe ".rsync_command" do
let(:cap) { caps.get(:rsync_command) }
it "provides the rsync command to use" do
expect(cap.rsync_command(machine)).to eq("rsync -zz")
end
end
describe ".rsync_pre" do
let(:cap) { caps.get(:rsync_pre) }
it "creates target directory on guest" do
cap.rsync_pre(machine, :guestpath => guest_directory)
expect(comm.received_commands[0]).to match(/mkdir -p '\/guest\/directory\/path'/)
end
end
describe ".rsync_post" do
let(:cap) { caps.get(:rsync_post) }
it "is a no-op" do
cap.rsync_post(machine, {})
expect(comm).to_not receive(:execute)
end
end
end