Skip to content

Commit

Permalink
Merge pull request #92 from Sharpie/pe_agent
Browse files Browse the repository at this point in the history
Implement support for frictionless agent installation

Closes #91 
Closes #69
  • Loading branch information
Sharpie committed Oct 12, 2015
2 parents 7ec3914 + 125c435 commit 8db26e5
Show file tree
Hide file tree
Showing 30 changed files with 1,093 additions and 68 deletions.
27 changes: 13 additions & 14 deletions acceptance/pe_build/pe_bootstrap_2015x_spec.rb
@@ -1,7 +1,7 @@
shared_examples 'provider/provisioner/pe_bootstrap/2015x' do |provider, options|
if !File.file?(options[:box])
if options[:boxes].empty?
raise ArgumentError,
"A box file must be downloaded for provider: #{provider}. Try: rake acceptance:setup"
"Box files must be downloaded for provider: #{provider}. Try: rake acceptance:setup"
end

include_context 'acceptance'
Expand All @@ -17,29 +17,28 @@
# The skelton sets up a Vagrantfile which expects the OS under test to be
# available as `box`.
environment.skeleton('2015x_acceptance')
assert_execute('vagrant', 'box', 'add', 'box', options[:box])
options[:boxes].each do |box|
name = File.basename(box).split('-').first
assert_execute('vagrant', 'box', 'add', name, box)
end
end

after(:each) do
# Ensure any VMs that survived tests are cleaned up.
assert_execute('vagrant', 'destroy', '--force', log: false)
end

context 'when installing PE 2015.2.0' do
it 'provisions with pe_build' do
result = assert_execute('vagrant', 'up', "--provider=#{provider}", 'pe-201520-master', 'pe-201520-agent')
end
end

context 'when installing PE 2015.2.1' do
it 'provisions with pe_build' do
assert_execute('vagrant', 'up', "--provider=#{provider}", 'pe-201521-master', 'pe-201521-agent')
context 'when installing PE 2015.2.x' do
it 'provisions masters with pe_bootstrap and agents with pe_agent' do
assert_execute('vagrant', 'up', "--provider=#{provider}", 'pe-20152-master')
assert_execute('vagrant', 'up', "--provider=#{provider}", 'pe-20152-agent')
end
end

context 'when installing PE 2015.latest' do
it 'provisions with pe_build' do
assert_execute('vagrant', 'up', "--provider=#{provider}", 'pe-2015latest-master', 'pe-2015latest-agent')
it 'provisions masters with pe_bootstrap and agents with pe_agent' do
assert_execute('vagrant', 'up', "--provider=#{provider}", 'pe-2015latest-master')
assert_execute('vagrant', 'up', "--provider=#{provider}", 'pe-2015latest-agent')
end
end
end
9 changes: 6 additions & 3 deletions acceptance/pe_build/pe_bootstrap_3x_spec.rb
@@ -1,7 +1,7 @@
shared_examples 'provider/provisioner/pe_bootstrap/3x' do |provider, options|
if !File.file?(options[:box])
if options[:boxes].empty?
raise ArgumentError,
"A box file must be downloaded for provider: #{provider}. Try: rake acceptance:setup"
"Box files must be downloaded for provider: #{provider}. Try: rake acceptance:setup"
end

include_context 'acceptance'
Expand All @@ -17,7 +17,10 @@
# The skelton sets up a Vagrantfile which expects the OS under test to be
# available as `box`.
environment.skeleton('pe_build')
assert_execute('vagrant', 'box', 'add', 'box', options[:box])
options[:boxes].each do |box|
name = File.basename(box).split('-').first
assert_execute('vagrant', 'box', 'add', name, box)
end
end

after(:each) do
Expand Down
9 changes: 6 additions & 3 deletions acceptance/pe_build/pe_bootstrap_latest_spec.rb
@@ -1,7 +1,7 @@
shared_examples 'provider/provisioner/pe_bootstrap/latest' do |provider, options|
if !File.file?(options[:box])
if options[:boxes].empty?
raise ArgumentError,
"A box file must be downloaded for provider: #{provider}. Try: rake acceptance:setup"
"Box files must be downloaded for provider: #{provider}. Try: rake acceptance:setup"
end

include_context 'acceptance'
Expand All @@ -19,7 +19,10 @@

before(:each) do
environment.skeleton('pe_build')
assert_execute('vagrant', 'box', 'add', 'box', options[:box])
options[:boxes].each do |box|
name = File.basename(box).split('-').first
assert_execute('vagrant', 'box', 'add', name, box)
end
end

after(:each) do
Expand Down
60 changes: 16 additions & 44 deletions acceptance/skeletons/2015x_acceptance/Vagrantfile
Expand Up @@ -7,68 +7,41 @@ end

Vagrant.configure('2') do |config|
config.pe_build.download_root = ENV['PE_BUILD_DOWNLOAD_ROOT']
# This is the box name used by the setup helpers in the acceptance tests.
config.vm.box = 'box'
config.vm.provision :shell, :inline => 'service iptables stop'

config.vm.define 'pe-201520-master' do |node|
config.vm.define 'pe-20152-master' do |node|
node.vm.hostname = 'pe-201520-master.pe-bootstrap.vlan'
node.vm.box = 'centos'
# All-in-one master nodes need a generous amount of RAM for all the Java.
set_resources node, 4096, 1
node.vm.provision :shell, :inline => 'service iptables stop'

node.vm.network 'private_network', :ip => '10.20.1.100'
node.vm.provision :shell, :inline => 'echo "10.20.1.101 pe-201520-agent.pe-bootstrap.vlan" >> /etc/hosts'

node.vm.provision :pe_bootstrap do |p|
p.version = '2015.2.0'
p.role = :master
end
end

config.vm.define 'pe-201520-agent' do |node|
node.vm.hostname = 'pe-201520-agent.pe-bootstrap.vlan'

node.vm.network 'private_network', :ip => '10.20.1.101'
node.vm.provision :shell, :inline => 'echo "10.20.1.100 pe-201520-master.pe-bootstrap.vlan" >> /etc/hosts'

node.vm.provision :pe_bootstrap do |p|
p.version = '2015.2.0'
p.role = :agent
p.master = 'pe-201520-master.pe-bootstrap.vlan'
end
end

config.vm.define 'pe-201521-master' do |node|
node.vm.hostname = 'pe-201521-master.pe-bootstrap.vlan'
# All-in-one master nodes need a generous amount of RAM for all the Java.
set_resources node, 4096, 1

node.vm.network 'private_network', :ip => '10.20.1.102'
node.vm.provision :shell, :inline => 'echo "10.20.1.103 pe-201521-agent.pe-bootstrap.vlan" >> /etc/hosts'
node.vm.provision :shell, :inline => 'echo "10.20.1.101 pe-20152-agent.pe-bootstrap.vlan" >> /etc/hosts'

node.vm.provision :pe_bootstrap do |p|
p.version = '2015.2.1'
p.role = :master
end
end

config.vm.define 'pe-201521-agent' do |node|
node.vm.hostname = 'pe-201521-agent.pe-bootstrap.vlan'
config.vm.define 'pe-20152-agent' do |node|
node.vm.hostname = 'pe-20152-agent.pe-bootstrap.vlan'
node.vm.box = 'ubuntu'

node.vm.network 'private_network', :ip => '10.20.1.103'
node.vm.provision :shell, :inline => 'echo "10.20.1.102 pe-201521-master.pe-bootstrap.vlan" >> /etc/hosts'
node.vm.network 'private_network', :ip => '10.20.1.101'
node.vm.provision :shell, :inline => 'echo "10.20.1.100 pe-20152-master.pe-bootstrap.vlan" >> /etc/hosts'

node.vm.provision :pe_bootstrap do |p|
p.version = '2015.2.1'
p.role = :agent
p.master = 'pe-201521-master.pe-bootstrap.vlan'
node.vm.provision :pe_agent do |p|
p.master_vm = 'pe-20152-master'
end
end

config.vm.define 'pe-2015latest-master' do |node|
node.vm.hostname = 'pe-2015latest-master.pe-bootstrap.vlan'
node.vm.box = 'centos'
# All-in-one master nodes need a generous amount of RAM for all the Java.
set_resources node, 4096, 1
node.vm.provision :shell, :inline => 'service iptables stop'

node.vm.network 'private_network', :ip => '10.20.1.104'
node.vm.provision :shell, :inline => 'echo "10.20.1.105 pe-2015latest-agent.pe-bootstrap.vlan" >> /etc/hosts'
Expand All @@ -81,14 +54,13 @@ Vagrant.configure('2') do |config|

config.vm.define 'pe-2015latest-agent' do |node|
node.vm.hostname = 'pe-2015latest-agent.pe-bootstrap.vlan'
node.vm.box = 'ubuntu'

node.vm.network 'private_network', :ip => '10.20.1.105'
node.vm.provision :shell, :inline => 'echo "10.20.1.104 pe-2015latest-master.pe-bootstrap.vlan" >> /etc/hosts'

node.vm.provision :pe_bootstrap do |p|
p.version_file = 'LATEST'
p.role = :agent
p.master = 'pe-2015latest-master.pe-bootstrap.vlan'
node.vm.provision :pe_agent do |p|
p.master_vm = 'pe-2015latest-master'
end
end
end
2 changes: 1 addition & 1 deletion acceptance/skeletons/pe_build/Vagrantfile
Expand Up @@ -8,7 +8,7 @@ end
Vagrant.configure('2') do |config|
config.pe_build.download_root = ENV['PE_BUILD_DOWNLOAD_ROOT']
# This is the box name used by the setup helpers in the acceptance tests.
config.vm.box = 'box'
config.vm.box = 'centos'

config.vm.define 'pe-3x' do |node|
node.vm.hostname = 'pe-3x.pe-bootstrap.vlan'
Expand Down
9 changes: 9 additions & 0 deletions lib/pe_build/cap.rb
Expand Up @@ -17,6 +17,15 @@ class DetectFailed < Vagrant::Errors::VagrantError
require 'pe_build/cap/detect_installer/solaris'
end

module Facts
require 'pe_build/cap/facts/redhat'
require 'pe_build/cap/facts/debian'
require 'pe_build/cap/facts/ubuntu'
require 'pe_build/cap/facts/suse'
require 'pe_build/cap/facts/solaris'
require 'pe_build/cap/facts/windows'
end

module RunInstall
require 'pe_build/cap/run_install/posix'
require 'pe_build/cap/run_install/windows'
Expand Down
119 changes: 119 additions & 0 deletions lib/pe_build/cap/facts/base.rb
@@ -0,0 +1,119 @@
require 'json'

# Base class for retrieving facts from guest VMs
#
# This class implements a Guest Capability for Fact retrieval. Puppet will be
# queried, if installed. Otherwise, a minimal set of base facts willPuppetbe
# returned by {#basic_facts}.
#
# @abstract Subclass and override {#architecture}, {#os_info} and
# {#release_info} to implement for a particular guest operating system.
#
# @since 0.13.0
class PEBuild::Cap::Facts::Base

# Retrieve facts from a guest VM
#
# See {#load_facts} for implementation details.
#
# @return [Hash] A hash of facts.
def self.pebuild_facts(machine)
new(machine).load_facts
end

attr_reader :machine

def initialize(machine)
@machine = machine
end

def puppet_path
@puppet_path ||= find_puppet
end

# Load Facts from the guest VM
#
# @return [Hash] A hash of facts from Puppet, if installed.
# @return [Hash] A hash containing the results of {#basic_facts} if
# Facter is not installed.
def load_facts
unless puppet_path.nil?
certname = sudo("#{puppet_path} agent --configprint certname")[:stdout].chomp
raw_facts = JSON.load(sudo("#{puppet_path} facts find --render-as json --terminus facter #{certname}")[:stdout])
facts = raw_facts['values']
# Keep the certname of the agent.
facts['certname'] = certname
else
# Puppet isn't installed yet, so we gather a minimal set of info.
facts = basic_facts
end

# JSON.load can do funny things. Sort by top-level key.
Hash[facts.sort]
end

# Determine basic info about a guest
#
# This function returns a minimal set of basic facts which should be
# sufficient to determine what software to install on the guest.
#
# @return [Hash] A hash containing the `architecture` and `os` facts.
def basic_facts
{
'architecture' => architecture,
'os' => {
'release' => release_info
}.update(os_info)
}
end

# Returns the native architecture of the OS
#
# @return [String] An architecture, such as `i386` or `x86_64`.
def architecture
raise NotImplementedError
end

# Returns info about the OS type
#
# @return [Hash] A hash containing the `family` of the operating system and,
# optionally, the `name`.
def os_info
raise NotImplementedError
end

# Returns info about the OS version
#
# @return [Hash] A hash containing the `full` version strying of the
# operating system and, optionally, the `minor` and `major`
# release versions.
def release_info
raise NotImplementedError
end

private

# Override this method to implement a more sophisticated search for the
# Puppet executable.
def find_puppet
return 'puppet' if @machine.communicate.test('puppet --version')
return nil
end

# TODO: Split this out into a shared module.
def sudo(cmd)
stdout = ''
stderr = ''

retval = machine.communicate.sudo(cmd) do |type, data|
if type == :stderr
stderr << data.chomp
else
stdout << data.chomp
end
end

{:stdout => stdout, :stderr => stderr, :retval => retval}
end

end
37 changes: 37 additions & 0 deletions lib/pe_build/cap/facts/debian.rb
@@ -0,0 +1,37 @@
require_relative 'posix'

# Facts implementation for Debian guests
#
# @since 0.13.0
class PEBuild::Cap::Facts::Debian < PEBuild::Cap::Facts::POSIX

# (see PEBuild::Cap::Facts::Base#os_info)
#
# Returns `family` as `Debian` and `name` as `Debian`.
#
# @see PEBuild::Cap::Facts::Base#os_info
def os_info
{
'name' => 'Debian',
'family' => 'Debian'
}
end

# (see PEBuild::Cap::Facts::Base#release_info)
#
# Reads `/etc/debian_version` and generates a `full` version along with
# `major` and `minor` components.
#
# @see PEBuild::Cap::Facts::Base#release_info
def release_info
release_file = sudo('cat /etc/debian_version')[:stdout]
version = release_file.match(/(\d+\.\d+)/)[1]

{
'major' => version.split('.', 2)[0],
'minor' => version.split('.', 2)[1],
'full' => version
}
end

end

0 comments on commit 8db26e5

Please sign in to comment.