Skip to content
This repository has been archived by the owner on Jun 11, 2024. It is now read-only.

Commit

Permalink
Merge pull request #15 from tkishel/FM-7115_return_cert_with_task_res…
Browse files Browse the repository at this point in the history
…ults

(FM 7115) return device certificates with task results
  • Loading branch information
tphoney authored Jul 4, 2018
2 parents 4b2e146 + 7ceba09 commit cf7c008
Show file tree
Hide file tree
Showing 8 changed files with 189 additions and 73 deletions.
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ group :system_tests do
gem "beaker", *location_for(ENV['BEAKER_VERSION'] || '>= 3')
gem "beaker-pe", require: false
gem "beaker-rspec"
gem "beaker-task_helper"
gem "beaker-hostgenerator"
gem "beaker-abs", *location_for(ENV['BEAKER_ABS_VERSION'] || '~> 0.1')
gem "puppet-blacksmith", '~> 3.4', require: false
Expand Down
5 changes: 2 additions & 3 deletions manifests/run.pp
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,9 @@
$user = '--user=root'
}

# TODO: Consider removing multiple spaces using join(), delete(), rstrip().
$arguments = "device --waitforcert=0 ${user} --verbose"
$arguments = "device ${user} --waitforcert=0 --verbose"

# PUP-7412 Puppet 5.0.0 introduces '--target=root'.
# PUP-7412 Puppet 5.0.0 introduces '--target=<device>'.
$targetable = (versioncmp($::puppetversion, '5.0.0') >= 0)

$random_minute = sprintf('%02d', fqdn_rand(59, 'device_manager'))
Expand Down
64 changes: 45 additions & 19 deletions spec/acceptance/configure_spec.rb
Original file line number Diff line number Diff line change
@@ -1,38 +1,64 @@
require 'spec_helper_acceptance'

describe 'configure' do
context 'basic setup' do
it 'edit site.pp and run the agent' do
context 'device management' do
it 'define device management in site.pp on the master' do
fqdn = fact('fqdn')
pp = <<-EOS
node '#{fqdn}' {
device_manager {'bigip.example.com':
type => 'f5',
url => 'https://admin:[email protected]/',
run_interval => 30,
}
}

manifest = <<-EOS
node '#{fqdn}' {
device_manager {'bigip.example.com':
type => 'f5',
url => 'https://admin:[email protected]/',
run_interval => 30,
}
device_manager {'cisco.example.com':
type => 'cisco_ios',
credentials => {
address => '10.64.21.10',
port => 22,
username => 'root',
password => 'eq3e2jM6m8AVvT9',
enable_password => 'eq3e2jM6m8AVvT9',
},
}
}
node default {}
EOS
make_site_pp(pp)
run_agent(allow_changes: true)
run_agent(allow_changes: false)

define_site_pp(manifest)
end

it 'define device management on the proxy agent' do
run_puppet_agent(allow_changes: true)
run_puppet_agent(allow_changes: false)
end

# check device.conf is created
describe file('/etc/puppetlabs/puppet/device.conf') do
it { is_expected.to be_file }
it { is_expected.to contain %r{[bigip.example.com]} }
it { is_expected.to contain %r{type f5} }
it { is_expected.to contain %r{[cisco.example.com]} }
it { is_expected.to contain %r{type cisco_ios} }
end

# check crontab has an entry
it 'crontab entry' do
describe file('/etc/puppetlabs/puppet/devices/cisco.example.com.conf') do
it { is_expected.to be_file }
it { is_expected.to contain %r{address} }
end

it 'cron for device with run_interval on the proxy agent' do
result = on(default, 'crontab -l').stdout
expect(result).to match(%r{puppet device})
expect(result).to match(%r{bigip.example.com})
end
end

it 'run puppet device' do
# check the cert is created
# sign the cert
context 'device certificate' do
it 'purge device on the master and the proxy agent' do
run_puppet_node_purge('cisco.example.com')
reset_agent_device_cache('cisco.example.com')
end
end
end
4 changes: 3 additions & 1 deletion spec/acceptance/nodesets/vmpooler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ HOSTS:
pe_upgrade_ver:
hypervisor: vmpooler
# hypervisor: none
# ip: m80hs0ndpo6lki0.delivery.puppetlabs.net
# ip: xxxxxxxxxxxxxxx.delivery.puppetlabs.net
platform: el-7-x86_64
template: centos-7-x86_64
roles:
Expand All @@ -19,3 +19,5 @@ CONFIG:
nfs_server: none
consoleport: 443
pooling_api: http://vmpooler.delivery.puppetlabs.net/
ssh:
keys: "~/.ssh/id_rsa-acceptance"
28 changes: 28 additions & 0 deletions spec/acceptance/run_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
require 'spec_helper_acceptance'

describe 'run' do
context 'puppet device' do
it 'generate certificate request for device on the proxy agent' do
run_puppet_device_generate_csr('cisco.example.com')
end
it 'sign certificate request on the master' do
run_puppet_cert_sign('cisco.example.com')
end
it 'run puppet device on the proxy agent' do
run_puppet_device('cisco.example.com', allow_changes: false)
end
end

context 'puppet task' do
it 'run device_manager::run_puppet_device task on the master' do
host_cert_name = fact('fqdn')
device_cert_name = 'cisco.example.com'
params = "target=#{device_cert_name}"
device_cert_fingerprint = run_puppet_cert_fingerprint(device_cert_name)
# Note: run_puppet_task from beaker-task_helper executes "puppet task" "on(master".
result = run_puppet_task(task_name: 'device_manager::run_puppet_device', host: host_cert_name, params: params)
expect(result).to match(%r{status : success})
expect(result).to match(%r{fingerprint : #{device_cert_fingerprint}})
end
end
end
6 changes: 3 additions & 3 deletions spec/defines/init_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@
it { is_expected.to contain_device_manager__run__via_cron__device(title) }
it {
is_expected.to contain_cron('run puppet device').with(
'command' => '/opt/puppetlabs/puppet/bin/puppet device --waitforcert=0 --user=root --verbose',
'command' => '/opt/puppetlabs/puppet/bin/puppet device --user=root --waitforcert=0 --verbose',
)
}
end
Expand Down Expand Up @@ -137,7 +137,7 @@
it { is_expected.to contain_device_manager__run__via_cron__device(title) }
it {
is_expected.to contain_cron("run puppet device target #{title}").with(
'command' => "/opt/puppetlabs/puppet/bin/puppet device --waitforcert=0 --user=root --verbose --target=#{title}",
'command' => "/opt/puppetlabs/puppet/bin/puppet device --user=root --waitforcert=0 --verbose --target=#{title}",
'hour' => '*',
)
}
Expand Down Expand Up @@ -207,7 +207,7 @@
it { is_expected.to contain_device_manager__run__via_exec__device(title) }
it {
is_expected.to contain_exec("run puppet device target #{title}").with(
'command' => %("/opt/puppetlabs/puppet/bin/puppet" device --waitforcert=0 --user=root --verbose --target=#{title}),
'command' => %("/opt/puppetlabs/puppet/bin/puppet" device --user=root --waitforcert=0 --verbose --target=#{title}),
)
}
end
Expand Down
109 changes: 69 additions & 40 deletions spec/spec_helper_acceptance.rb
Original file line number Diff line number Diff line change
@@ -1,33 +1,83 @@
require 'beaker-rspec/spec_helper'
require 'beaker-rspec/helpers/serverspec'
require 'beaker-task_helper'
require 'beaker/puppet_install_helper'
require 'beaker/module_install_helper'
require 'pry'

run_puppet_install_helper
install_module_on(hosts)
install_module_dependencies_on(hosts)
if ENV['BEAKER_provision'] != 'no'
run_puppet_install_helper
install_module_on(hosts)
install_module_dependencies_on(hosts)
end

RSpec.configure do |c|
c.before :suite do
run_puppet_access_login(user: 'admin')
unless ENV['BEAKER_TESTMODE'] == 'local'
unless ENV['BEAKER_provision'] == 'no'
install_module_from_forge('puppetlabs-cisco_ios', '0.2.0')
install_module_from_forge('f5-f5', '1.8.0')
end
hosts.each do |host|
end
end
end
end

def make_site_pp(pp)
base_path = '/etc/puppetlabs/code/environments/production/'
path = File.join(base_path, 'manifests')
def define_site_pp(manifest)
path = '/etc/puppetlabs/code/environments/production/manifests'
on master, "mkdir -p #{path}"
create_remote_file(master, File.join(path, 'site.pp'), pp)
return if ENV['PUPPET_INSTALL_TYPE'] != 'foss'
create_remote_file(master, File.join(path, 'site.pp'), manifest)
return unless ENV['PUPPET_INSTALL_TYPE'] == 'foss'
on master, "chown -R #{master['user']}:#{master['group']} #{path}"
on master, "chmod -R 0755 #{path}"
on master, "service #{master['puppetservice']} restart"
wait_for_master(3)
end

def run_device(options = { allow_changes: true })
acceptable_exit_codes = if options[:allow_changes] == false
0
else
[0, 2]
end
on(default, puppet('device', '--verbose', '--trace'), acceptable_exit_codes: acceptable_exit_codes) do |result|
# on(default, puppet('device','--verbose','--color','false','--user','root','--trace','--server',master.to_s), { :acceptable_exit_codes => acceptable_exit_codes }) do |result|
def run_puppet_node_purge(cert_name)
on(master, puppet('node', 'purge', cert_name), acceptable_exit_codes: [0, 1]).stdout
end

def run_puppet_cert_sign(cert_name = nil)
if cert_name
on(master, puppet('cert', 'sign', cert_name), acceptable_exit_codes: [0, 1]).stdout
else
on(master, puppet('cert', 'sign', '--all'), acceptable_exit_codes: [0, 1]).stdout
end
end

def run_puppet_cert_fingerprint(cert_name)
fingerprint = nil
result = on(master, puppet('cert', 'fingerprint', cert_name), acceptable_exit_codes: 0).stdout
if (matched = result.chomp.match(%r{\(\w+\) (?<fingerprint>.*)$}))
fingerprint = matched[:fingerprint]
end
fingerprint
end

def reset_agent_device_cache(cert_name)
on default, "rm -rf /opt/puppetlabs/puppet/cache/devices/#{cert_name}"
end

def run_puppet_agent(options = { allow_changes: true })
acceptable_exit_codes = (options[:allow_changes] == false) ? 0 : [0, 2]
on(default, puppet('agent', '-t'), acceptable_exit_codes: acceptable_exit_codes)
end

def run_puppet_device_generate_csr(cert_name)
acceptable_exit_codes = 1
on(default, puppet('device', '--verbose', '--waitforcert=0', '--target', cert_name), acceptable_exit_codes: acceptable_exit_codes) do |result|
expect(result.stdout).to match(%r{Exiting; no certificate found and waitforcert is disabled})
end
end

# Use '--trace', '--color', 'false' for more information.

def run_puppet_device(cert_name, options = { allow_changes: true })
acceptable_exit_codes = (options[:allow_changes] == false) ? 0 : [0, 2]
on(default, puppet('device', '--verbose', '--waitforcert=0', '--target', cert_name), acceptable_exit_codes: acceptable_exit_codes) do |result|
if options[:allow_changes] == false
expect(result.stdout).not_to match(%r{^Notice: /Stage\[main\]})
end
Expand All @@ -36,31 +86,10 @@ def run_device(options = { allow_changes: true })
end
end

def run_resource(resource_type, resource_title = nil)
def run_puppet_device_resource(cert_name, resource_type, resource_title = nil)
if resource_title
on(master, puppet('device', '--target', 'target', '--resource', resource_type, resource_title, '--trace'), acceptable_exit_codes: [0, 1]).stdout
on(default, puppet('device', '--trace', '--target', cert_name, '--resource', resource_type, resource_title), acceptable_exit_codes: [0, 1]).stdout
else
on(master, puppet('device', '--target', 'target', '--resource', resource_type, '--trace'), acceptable_exit_codes: [0, 1]).stdout
end
end

def run_agent(options = { allow_changes: true })
acceptable_exit_codes = if options[:allow_changes] == false
0
else
[0, 2]
end
on(default, puppet('agent', '-t'), acceptable_exit_codes: acceptable_exit_codes)
end

RSpec.configure do |c|
c.before :suite do
unless ENV['BEAKER_TESTMODE'] == 'local'
unless ENV['BEAKER_provision'] == 'no'
install_module_from_forge('f5-f5', '1.8.0')
end
hosts.each do |host|
end
end
on(default, puppet('device', '--trace', '--target', cert_name, '--resource', resource_type), acceptable_exit_codes: [0, 1]).stdout
end
end
45 changes: 38 additions & 7 deletions tasks/run_puppet_device.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
require 'json'
require 'open3'
require 'puppet'
require 'puppet/ssl/certificate'
require 'puppet/ssl/host'
require 'puppet/util/network_device/config'
require 'timeout'

Expand All @@ -26,9 +28,31 @@ def read_device_configuration(target)
devices
end

# Read a device certificate and return its fingerprints.

def read_device_certificate_fingerprints(cert_name)
cert_file = File.join(Puppet[:devicedir], cert_name, 'ssl', 'certs', "#{cert_name}.pem")
if File.file?(cert_file)
begin
certificate = Puppet::SSL::Certificate.from_s(Puppet::FileSystem.read(cert_file))
rescue OpenSSL::X509::CertificateError
certificate = nil
end
end
return nil unless certificate
fingerprints = {}
fingerprints['default'] = certificate.fingerprint
ssl_host = Puppet::SSL::Host.new
mdas = ssl_host.suitable_message_digest_algorithms
mdas.each do |mda|
fingerprints[mda.to_s] = certificate.fingerprint(mda)
end
fingerprints
end

# Run 'puppet device' for each device, or just the target device.

def run_device_manager(devices, noop, timeout)
def run_puppet_device(devices, noop, timeout)
os = Facter.value(:os) || {}
osfamily = os['family']
if osfamily == 'windows'
Expand All @@ -37,6 +61,8 @@ def run_device_manager(devices, noop, timeout)
else
puppet_command = '/opt/puppetlabs/puppet/bin/puppet'
end
# PUP-1391 Puppet 5.4.0 does not require '--user=root'.
user = (Gem::Version.new(Puppet.version) > Gem::Version.new('5.4.0')) ? '' : '--user=root'
results = {}
results['error_count'] = 0

Expand All @@ -50,7 +76,7 @@ def run_device_manager(devices, noop, timeout)
result = ''

begin
Open3.popen2e(puppet_command, 'device', '--waitforcert=0', '--user=root', '--verbose', target, noop) do |_, oe, w|
Open3.popen2e(puppet_command, 'device', user, '--waitforcert=0', '--verbose', target, noop) do |_, oe, w|
begin
Timeout.timeout(timeout) do
until oe.eof?
Expand Down Expand Up @@ -87,10 +113,15 @@ def run_device_manager(devices, noop, timeout)
results['error_count'] = results['error_count'] + 1
end

results[device_name] = {
status: status,
result: result,
}
results[device_name] = {}
fingerprints = read_device_certificate_fingerprints(device_name)
if fingerprints
results[device_name]['fingerprint'] = fingerprints['default']
# Returning all fingerprints obscures other results.
# results[device_name]['fingerprints'] = fingerprints
end
results[device_name]['status'] = status
results[device_name]['result'] = result
end

results
Expand Down Expand Up @@ -151,6 +182,6 @@ def return_results(params, results)
if devices.count.zero?
return_configuration_error(params)
else
results = run_device_manager(devices, noop, timeout)
results = run_puppet_device(devices, noop, timeout)
return_results(params, results)
end

0 comments on commit cf7c008

Please sign in to comment.