simp-rake-helpers 5.6.2 → 5.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/lib/simp/packer/iso_vars_json.rb +87 -0
- data/lib/simp/rake/build/auto.rb +6 -31
- data/lib/simp/rake/helpers/assets/rpm_spec/simp6.spec +36 -8
- data/lib/simp/rake/helpers/assets/rpm_spec/simpdefault.spec +36 -8
- data/lib/simp/rake/helpers/version.rb +1 -1
- data/spec/acceptance/00_pkg_rpm_custom_scriptlets_spec.rb +19 -3
- data/spec/acceptance/10_pkg_rpm_spec.rb +52 -8
- data/spec/acceptance/20_pkg_rpm_upgrade_spec.rb +223 -0
- data/spec/acceptance/files/mock_packages/simp-adapter/usr/local/sbin/simp_rpm_helper +334 -245
- data/spec/acceptance/files/package_upgrades/pupmod-simp-testpackage-1.0/CHANGELOG +2 -0
- data/spec/acceptance/files/package_upgrades/pupmod-simp-testpackage-1.0/Rakefile +3 -0
- data/spec/acceptance/files/package_upgrades/pupmod-simp-testpackage-1.0/build/rpm_metadata/requires +2 -0
- data/spec/acceptance/files/package_upgrades/pupmod-simp-testpackage-1.0/data/os/CentOS.yaml +2 -0
- data/spec/acceptance/files/package_upgrades/pupmod-simp-testpackage-1.0/data/os/RedHat.yaml +2 -0
- data/spec/acceptance/files/package_upgrades/pupmod-simp-testpackage-1.0/hiera.yaml +14 -0
- data/spec/acceptance/files/package_upgrades/pupmod-simp-testpackage-1.0/manifests/init.pp +2 -0
- data/spec/acceptance/files/package_upgrades/pupmod-simp-testpackage-1.0/metadata.json +37 -0
- data/spec/acceptance/files/package_upgrades/pupmod-simp-testpackage-2.0/CHANGELOG +5 -0
- data/spec/acceptance/files/package_upgrades/pupmod-simp-testpackage-2.0/Rakefile +3 -0
- data/spec/acceptance/files/package_upgrades/pupmod-simp-testpackage-2.0/build/rpm_metadata/requires +2 -0
- data/spec/acceptance/files/package_upgrades/pupmod-simp-testpackage-2.0/data/os/CentOS.yaml +2 -0
- data/spec/acceptance/files/package_upgrades/pupmod-simp-testpackage-2.0/data/os/RedHat.yaml +2 -0
- data/spec/acceptance/files/package_upgrades/pupmod-simp-testpackage-2.0/hiera.yaml +14 -0
- data/spec/acceptance/files/package_upgrades/pupmod-simp-testpackage-2.0/manifests/init.pp +3 -0
- data/spec/acceptance/files/package_upgrades/pupmod-simp-testpackage-2.0/metadata.json +37 -0
- data/spec/acceptance/nodesets/default.yml +7 -8
- data/spec/acceptance/support/pkg_rpm_helpers.rb +2 -2
- data/spec/lib/simp/packer/iso_vars_json_spec.rb +65 -0
- metadata +29 -5
- data/spec/acceptance/20_pkg_rpm_safely_upgrading_obsolete_modules_spec.rb +0 -175
@@ -0,0 +1,223 @@
|
|
1
|
+
require 'spec_helper_acceptance'
|
2
|
+
require_relative 'support/pkg_rpm_helpers'
|
3
|
+
|
4
|
+
require 'beaker/puppet_install_helper'
|
5
|
+
require 'json'
|
6
|
+
|
7
|
+
RSpec.configure do |c|
|
8
|
+
c.include Simp::BeakerHelpers::SimpRakeHelpers::PkgRpmHelpers
|
9
|
+
c.extend Simp::BeakerHelpers::SimpRakeHelpers::PkgRpmHelpers
|
10
|
+
end
|
11
|
+
|
12
|
+
# This tests RPM upgrade scenarios for components that use
|
13
|
+
# simp-adapter's simp_rpm_helper to copy files from the RPM install
|
14
|
+
# directory to a second destination directory
|
15
|
+
|
16
|
+
|
17
|
+
shared_examples_for 'RPM generator' do
|
18
|
+
it 'should create RPMs' do
|
19
|
+
testpackages.each do |package|
|
20
|
+
on host, %Q(#{run_cmd} "cd #{pkg_root_dir}/#{package}; ) +
|
21
|
+
%Q(rvm use default; bundle update --local || bundle update")
|
22
|
+
rpm_name = package.sub(/-[^-]+$/,'')
|
23
|
+
# In case previous tests haven't been clean
|
24
|
+
on host, "rpm -q #{rpm_name} && rpm -e #{rpm_name}; :"
|
25
|
+
|
26
|
+
on host, %(#{run_cmd} "cd #{pkg_root_dir}/#{package}; #{rake_cmd} pkg:rpm")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
shared_examples_for 'an upgrade path that works safely with simp_rpm_helper' do |first_package_file, second_package_file|
|
32
|
+
let( :rpm_regex ) do
|
33
|
+
/^(?<name>pupmod-[a-z0-9_]+-[a-z0-9_]+)-(?<version>\d+\.\d+\.\d+)-(?<release>\d+)\..*\.rpm$/
|
34
|
+
end
|
35
|
+
|
36
|
+
let( :first_package_version ){ first_package_file.match(rpm_regex)['version'] }
|
37
|
+
let( :first_package_name ){ first_package_file.match(rpm_regex)['name'] }
|
38
|
+
let( :first_package_forge_name ){ first_package_name.sub(/^[^-]+-/,'') }
|
39
|
+
let( :first_package_module_name ){ first_package_forge_name.sub(/^[^-]+-/,'') }
|
40
|
+
let( :first_package_dir_name ){ first_package_name + '-' + first_package_version.sub(/\.\d+-\d+$/,'') }
|
41
|
+
|
42
|
+
let( :second_package_name ){ second_package_file.match(rpm_regex)['name'] }
|
43
|
+
let( :second_package_forge_name ){ second_package_name.sub(/^[^-]+-/,'') }
|
44
|
+
let( :second_package_module_name ){ second_package_forge_name.sub(/^[^-]+-/,'') }
|
45
|
+
let( :second_package_version ){ second_package_file.match(rpm_regex)['version'] }
|
46
|
+
let( :second_package_dir_name ){ second_package_name + '-' + second_package_version.sub(/\.\d+-\d+$/,'') }
|
47
|
+
|
48
|
+
context "When upgrading from #{first_package_file} to #{second_package_file}" do
|
49
|
+
it "should clean out any old installs" do
|
50
|
+
on host, "rpm -e #{first_package_name} &> /dev/null; " +
|
51
|
+
"rpm -e #{second_package_name} &> /dev/null ",
|
52
|
+
accept_all_exit_codes: true
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should install #{first_package_file}" do
|
56
|
+
on host, "cd #{pkg_root_dir}/#{first_package_dir_name.gsub(/\.\d+$/,'')}; "+
|
57
|
+
"rpm -Uvh dist/#{first_package_file}"
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should transfer contents of #{first_package_file} into the code directory" do
|
61
|
+
result = on host, "cat /opt/test/puppet/code/#{first_package_module_name}/metadata.json"
|
62
|
+
metadata = JSON.parse(result.stdout)
|
63
|
+
expect(metadata['name']).to eq first_package_forge_name
|
64
|
+
expect(metadata['version']).to eq first_package_version
|
65
|
+
|
66
|
+
# This verifies all files/dirs from the first package are copied
|
67
|
+
on host, "diff -r /usr/share/simp/modules/#{first_package_module_name} /opt/test/puppet/code/#{first_package_module_name}"
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should upgrade to #{second_package_file}" do
|
71
|
+
on host, "cd #{pkg_root_dir}/#{second_package_dir_name.gsub(/\.\d+$/,'')}; rpm -Uvh dist/#{second_package_file}"
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should transfer contents of #{second_package_file} into the code directory" do
|
75
|
+
result = on host, "cat /opt/test/puppet/code/#{second_package_module_name}/metadata.json"
|
76
|
+
metadata = JSON.parse(result.stdout)
|
77
|
+
expect(metadata['name']).to eq second_package_forge_name
|
78
|
+
expect(metadata['version']).to eq second_package_version
|
79
|
+
|
80
|
+
# This verifies all files/dirs from the second package are copied and
|
81
|
+
# no files/dirs onyn in the old package remain
|
82
|
+
on host, "diff -r /usr/share/simp/modules/#{second_package_module_name} /opt/test/puppet/code/#{second_package_module_name}"
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe 'rake pkg:rpm + component upgrade scenarios' do
|
89
|
+
|
90
|
+
before :all do
|
91
|
+
copy_host_files_into_build_user_homedir(hosts)
|
92
|
+
|
93
|
+
comment 'ensure the Puppet AIO is installed'
|
94
|
+
#FIXME Should install Puppet 5
|
95
|
+
ENV['PUPPET_INSTALL_TYPE'] ||= 'agent'
|
96
|
+
ENV['PUPPET_INSTALL_VERSION'] ||= '1.10.6'
|
97
|
+
run_puppet_install_helper_on(hosts)
|
98
|
+
|
99
|
+
comment 'configure puppet agent to look like a Puppet server for simp_rpm_helper'
|
100
|
+
on hosts, '/opt/puppetlabs/bin/puppet config --section master set user root; ' +
|
101
|
+
'/opt/puppetlabs/bin/puppet config --section master set group root; ' +
|
102
|
+
'/opt/puppetlabs/bin/puppet config --section master set codedir /opt/test/puppet/code; ' +
|
103
|
+
'/opt/puppetlabs/bin/puppet config --section master set confdir /opt/test/puppet/code'
|
104
|
+
|
105
|
+
|
106
|
+
comment 'build and install mock RPMs'
|
107
|
+
mock_pkg_dir = '/home/build_user/host_files/spec/acceptance/files/mock_packages'
|
108
|
+
on hosts, %Q[#{run_cmd} "cd #{mock_pkg_dir}; rm -rf pkg"]
|
109
|
+
on hosts, %Q[#{run_cmd} "cd #{mock_pkg_dir}; bash rpmbuild.sh simp-adapter.spec"]
|
110
|
+
on hosts, %Q[#{run_cmd} "cd #{mock_pkg_dir}; bash rpmbuild.sh pupmod-puppetlabs-stdlib.spec"]
|
111
|
+
on hosts, %Q[#{run_cmd} "cd #{mock_pkg_dir}; bash rpmbuild.sh pupmod-simp-simplib.spec"]
|
112
|
+
on hosts, %Q[#{run_cmd} "cd #{mock_pkg_dir}; bash rpmbuild.sh pupmod-simp-foo.spec"]
|
113
|
+
|
114
|
+
on hosts, %Q[rpm -Uvh "#{mock_pkg_dir}/pkg/dist/*.noarch.rpm"], acceptable_exit_codes: [0,1]
|
115
|
+
end
|
116
|
+
|
117
|
+
hosts.each do |_host|
|
118
|
+
context "on #{_host}" do
|
119
|
+
let!(:host){ _host }
|
120
|
+
|
121
|
+
# This tests standard upgrades, which should
|
122
|
+
context 'with normal module RPM upgrades' do
|
123
|
+
let(:pkg_root_dir) do
|
124
|
+
'/home/build_user/host_files/spec/acceptance/files/package_upgrades'
|
125
|
+
end
|
126
|
+
|
127
|
+
let(:testpackages) do
|
128
|
+
[
|
129
|
+
'pupmod-simp-testpackage-1.0',
|
130
|
+
'pupmod-simp-testpackage-2.0',
|
131
|
+
]
|
132
|
+
end
|
133
|
+
|
134
|
+
context 'RPM build' do
|
135
|
+
it_should_behave_like('RPM generator')
|
136
|
+
end
|
137
|
+
|
138
|
+
context 'RPM upgrades' do
|
139
|
+
it_should_behave_like('an upgrade path that works safely with simp_rpm_helper',
|
140
|
+
'pupmod-simp-testpackage-1.0.0-0.noarch.rpm',
|
141
|
+
'pupmod-simp-testpackage-2.0.0-0.noarch.rpm')
|
142
|
+
end
|
143
|
+
|
144
|
+
context 'RPM erase' do
|
145
|
+
it 'should remove copied files on an erase' do
|
146
|
+
on host, 'rpm -e pupmod-simp-testpackage'
|
147
|
+
on host, 'ls /opt/test/puppet/code/testpackage', acceptable_exit_codes: [2]
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
# These tests demonstrate custom RPM triggers that work around the obsolete
|
153
|
+
# module RPM upgrate + simp_rpm_helper problem described in SIMP-3895:
|
154
|
+
#
|
155
|
+
# https://simp-project.atlassian.net/browse/SIMP-3988
|
156
|
+
#
|
157
|
+
# The expected outcome is that simp_rpm_helper always ensures the correct
|
158
|
+
# content is installed after an upgrade, even during after a package has been
|
159
|
+
# obsoleted. This is accomplished via %triggerpostun -- <name of old package>
|
160
|
+
#
|
161
|
+
# old 1.0 -> old 2.0 = no need for a trigger
|
162
|
+
# old 1.0 -> new 2.0 = must re-run simp_rpm_helper
|
163
|
+
# old 1.0 -> new 3.0 = must re-run simp_rpm_helper
|
164
|
+
# old 2.0 -> new 2.0 = must re-run simp_rpm_helper
|
165
|
+
# old 2.0 -> new 3.0 = must re-run simp_rpm_helper
|
166
|
+
# new 2.0 -> new 3.0 = no need for a trigger
|
167
|
+
#
|
168
|
+
context 'with module RPMs that are susceptible to SIMP-3895' do
|
169
|
+
let(:pkg_root_dir) do
|
170
|
+
'/home/build_user/host_files/spec/acceptance/files/custom_scriptlet_triggers'
|
171
|
+
end
|
172
|
+
|
173
|
+
let(:testpackages) do
|
174
|
+
[
|
175
|
+
'pupmod-old-package-1.0',
|
176
|
+
'pupmod-old-package-2.0',
|
177
|
+
'pupmod-old-package-2.2',
|
178
|
+
'pupmod-new-package-2.1',
|
179
|
+
'pupmod-new-package-3.0',
|
180
|
+
]
|
181
|
+
end
|
182
|
+
|
183
|
+
context 'RPM build' do
|
184
|
+
it_should_behave_like('RPM generator')
|
185
|
+
end
|
186
|
+
|
187
|
+
context 'RPM upgrades' do
|
188
|
+
it_should_behave_like('an upgrade path that works safely with simp_rpm_helper',
|
189
|
+
'pupmod-old-package-1.0.0-0.noarch.rpm',
|
190
|
+
'pupmod-old-package-2.0.0-0.noarch.rpm')
|
191
|
+
|
192
|
+
it_should_behave_like('an upgrade path that works safely with simp_rpm_helper',
|
193
|
+
'pupmod-old-package-1.0.0-0.noarch.rpm',
|
194
|
+
'pupmod-new-package-2.1.0-0.noarch.rpm')
|
195
|
+
|
196
|
+
it_should_behave_like('an upgrade path that works safely with simp_rpm_helper',
|
197
|
+
'pupmod-new-package-2.1.0-0.noarch.rpm',
|
198
|
+
'pupmod-old-package-2.2.0-0.noarch.rpm')
|
199
|
+
|
200
|
+
it_should_behave_like('an upgrade path that works safely with simp_rpm_helper',
|
201
|
+
'pupmod-old-package-1.0.0-0.noarch.rpm',
|
202
|
+
'pupmod-new-package-3.0.0-0.noarch.rpm')
|
203
|
+
|
204
|
+
it_should_behave_like('an upgrade path that works safely with simp_rpm_helper',
|
205
|
+
'pupmod-old-package-2.0.0-0.noarch.rpm',
|
206
|
+
'pupmod-new-package-2.1.0-0.noarch.rpm')
|
207
|
+
|
208
|
+
it_should_behave_like('an upgrade path that works safely with simp_rpm_helper',
|
209
|
+
'pupmod-old-package-2.0.0-0.noarch.rpm',
|
210
|
+
'pupmod-new-package-3.0.0-0.noarch.rpm')
|
211
|
+
|
212
|
+
it_should_behave_like('an upgrade path that works safely with simp_rpm_helper',
|
213
|
+
'pupmod-old-package-2.2.0-0.noarch.rpm',
|
214
|
+
'pupmod-new-package-3.0.0-0.noarch.rpm')
|
215
|
+
|
216
|
+
it_should_behave_like('an upgrade path that works safely with simp_rpm_helper',
|
217
|
+
'pupmod-new-package-2.1.0-0.noarch.rpm',
|
218
|
+
'pupmod-new-package-3.0.0-0.noarch.rpm')
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
@@ -3,8 +3,8 @@
|
|
3
3
|
# Purpose
|
4
4
|
# -------
|
5
5
|
#
|
6
|
-
# This script is meant to be called by the %preun and %
|
7
|
-
# various SIMP Puppet module RPMs.
|
6
|
+
# This script is meant to be called by the %preun and %postttrans sections of
|
7
|
+
# the various SIMP Puppet module RPMs.
|
8
8
|
#
|
9
9
|
# The purpose of the script is to provide helper methods that correctly
|
10
10
|
# scaffold the system in such a way that all SIMP Puppet Modules can be
|
@@ -56,279 +56,307 @@ require 'find'
|
|
56
56
|
# Make sure we can find the Puppet executables
|
57
57
|
ENV['PATH'] += ':/opt/puppetlabs/bin'
|
58
58
|
|
59
|
-
|
60
|
-
def
|
61
|
-
|
59
|
+
class SimpRpmHelper
|
60
|
+
def initialize
|
61
|
+
@program_name = File.basename(__FILE__)
|
62
62
|
|
63
|
-
|
64
|
-
|
65
|
-
system_config.each_line do |line|
|
66
|
-
k,v = line.split('=')
|
67
|
-
config_hash[k.strip] = v.strip
|
63
|
+
# A list of modules that should never be touched once installed
|
64
|
+
@safe_modules = ['site']
|
68
65
|
end
|
69
66
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
#
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
end
|
67
|
+
def debug(msg)
|
68
|
+
# SIMP RPMs do not enable debug when they call this script. So, if
|
69
|
+
# you want to debug an RPM problem with this script, comment out
|
70
|
+
# the line below.
|
71
|
+
return unless @options.debug
|
72
|
+
msg.split("\n").each do |line|
|
73
|
+
puts ">>>#{@program_name} DEBUG: #{line}"
|
74
|
+
end
|
75
|
+
end
|
78
76
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
77
|
+
def info(msg)
|
78
|
+
# When these messages get written out in an RPM upgrade, name of program
|
79
|
+
# is helpful to end user
|
80
|
+
puts "#{@program_name}: #{msg}"
|
81
|
+
end
|
83
82
|
|
84
|
-
|
85
|
-
|
83
|
+
# Get the Puppet configuration parameters currently in use
|
84
|
+
def get_puppet_config
|
85
|
+
system_config = %x{puppet config --section master print}
|
86
86
|
|
87
|
-
|
88
|
-
if git
|
89
|
-
%x{#{git} ls-files . --error-unmatch &> /dev/null}
|
87
|
+
config_hash = Hash.new
|
90
88
|
|
91
|
-
|
89
|
+
system_config.each_line do |line|
|
90
|
+
k,v = line.split('=')
|
91
|
+
config_hash[k.strip] = v.strip
|
92
92
|
end
|
93
93
|
|
94
|
-
|
95
|
-
%x{#{svn} info &> /dev/null}
|
96
|
-
|
97
|
-
return true if $?.success?
|
98
|
-
end
|
94
|
+
return config_hash
|
99
95
|
end
|
100
96
|
|
101
|
-
|
102
|
-
|
97
|
+
# Determine whether the passed path is under management by git or svn
|
98
|
+
def is_managed?(path)
|
99
|
+
# Short circuit if the directory is not present
|
100
|
+
return false unless File.directory?(path)
|
103
101
|
|
104
|
-
|
105
|
-
|
106
|
-
options.config_file = '/etc/simp/adapter_config.yaml'
|
107
|
-
options.preserve = false
|
108
|
-
# These are not settable, but it's nice to have all this material in one place
|
109
|
-
options.puppet_user = @puppet_config['user']
|
110
|
-
options.puppet_group = @puppet_config['group']
|
111
|
-
|
112
|
-
all_opts = OptionParser.new do |opts|
|
113
|
-
opts.banner = "Usage: #{$0} [options]"
|
114
|
-
|
115
|
-
opts.separator ""
|
116
|
-
|
117
|
-
opts.on(
|
118
|
-
"--rpm_dir PATH",
|
119
|
-
"The directory into which the RPM source material is installed"
|
120
|
-
) do |arg|
|
121
|
-
options.rpm_dir = arg.strip
|
122
|
-
options.module_name = File.basename(options.rpm_dir)
|
123
|
-
end
|
102
|
+
git = Facter::Core::Execution.which('git')
|
103
|
+
svn = Facter::Core::Execution.which('svn')
|
124
104
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
" Must be one of 'pre', 'post', 'preun', 'postun'"
|
129
|
-
) do |arg|
|
130
|
-
options.rpm_section = arg.strip
|
131
|
-
end
|
105
|
+
Dir.chdir(path) do
|
106
|
+
if git
|
107
|
+
%x{#{git} ls-files . --error-unmatch &> /dev/null}
|
132
108
|
|
133
|
-
|
134
|
-
|
135
|
-
"The status code passed to the RPM section"
|
136
|
-
) do |arg|
|
137
|
-
options.rpm_status = arg.strip
|
138
|
-
end
|
109
|
+
return true if $?.success?
|
110
|
+
end
|
139
111
|
|
140
|
-
|
141
|
-
|
142
|
-
"--config CONFIG_FILE",
|
143
|
-
"The configuration file to use",
|
144
|
-
" Default: #{options.config_file}"
|
145
|
-
) do |arg|
|
146
|
-
options.config_file = arg.strip
|
147
|
-
end
|
112
|
+
if svn
|
113
|
+
%x{#{svn} info &> /dev/null}
|
148
114
|
|
149
|
-
|
150
|
-
|
151
|
-
"--preserve",
|
152
|
-
"Preserve material in 'target_dir' that is not in 'rpm_dir'"
|
153
|
-
) do |arg|
|
154
|
-
options.preserve = true
|
115
|
+
return true if $?.success?
|
116
|
+
end
|
155
117
|
end
|
156
118
|
|
157
|
-
|
158
|
-
|
159
|
-
"--enforce",
|
160
|
-
"If set, enforce the copy, regardless of the setting in the config file",
|
161
|
-
" Default: false"
|
162
|
-
) do |arg|
|
163
|
-
options.copy_rpm_data = true
|
164
|
-
end
|
119
|
+
return false
|
120
|
+
end
|
165
121
|
|
166
|
-
|
167
|
-
"-t DIR",
|
168
|
-
"--target_dir DIR",
|
169
|
-
"The subdirectory of #{simp_target_dir('')}",
|
170
|
-
"into which to copy the materials.",
|
171
|
-
" Default: #{simp_target_dir.gsub(/#{simp_target_dir('')}/,'')}"
|
172
|
-
) do |arg|
|
173
|
-
options.target_dir = simp_target_dir(arg.strip)
|
174
|
-
end
|
122
|
+
def parse_options(args)
|
175
123
|
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
"Help Message"
|
180
|
-
) do
|
181
|
-
puts opts
|
182
|
-
exit(0)
|
183
|
-
end
|
184
|
-
end
|
124
|
+
@options = OpenStruct.new
|
125
|
+
@options.config_file = '/etc/simp/adapter_config.yaml'
|
126
|
+
@options.preserve = false
|
185
127
|
|
186
|
-
|
187
|
-
|
188
|
-
rescue OptionParser::ParseError => e
|
189
|
-
puts e
|
190
|
-
puts all_opts
|
191
|
-
exit 1
|
192
|
-
end
|
128
|
+
all_opts = OptionParser.new do |opts|
|
129
|
+
opts.banner = "Usage: #{@program_name} [options]"
|
193
130
|
|
194
|
-
|
131
|
+
opts.separator ''
|
195
132
|
|
196
|
-
|
197
|
-
|
133
|
+
opts.on(
|
134
|
+
'--rpm_dir PATH',
|
135
|
+
'The directory into which the RPM source material is installed'
|
136
|
+
) do |arg|
|
137
|
+
@options.rpm_dir = arg.strip
|
138
|
+
@options.module_name = File.basename(@options.rpm_dir)
|
139
|
+
end
|
198
140
|
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
}
|
141
|
+
opts.on(
|
142
|
+
'--rpm_section SECTION',
|
143
|
+
'The section of the RPM from which the script is being called.',
|
144
|
+
" Must be one of 'pre', 'preun', 'postun', 'posttrans'"
|
145
|
+
) do |arg|
|
146
|
+
@options.rpm_section = arg.strip
|
147
|
+
end
|
207
148
|
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
149
|
+
opts.on(
|
150
|
+
'--rpm_status STATUS',
|
151
|
+
'The status code passed to the RPM section'
|
152
|
+
) do |arg|
|
153
|
+
@options.rpm_status = arg.strip
|
213
154
|
end
|
214
|
-
rescue
|
215
|
-
fail("Error: Config file '#{config_file}' could not be processed")
|
216
|
-
end
|
217
|
-
end
|
218
155
|
|
219
|
-
|
220
|
-
|
221
|
-
|
156
|
+
opts.on(
|
157
|
+
'-f CONFIG_FILE',
|
158
|
+
'--config CONFIG_FILE',
|
159
|
+
'The configuration file to use.',
|
160
|
+
" Default: #{@options.config_file}"
|
161
|
+
) do |arg|
|
162
|
+
@options.config_file = arg.strip
|
163
|
+
end
|
222
164
|
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
165
|
+
opts.on(
|
166
|
+
'-p',
|
167
|
+
'--preserve',
|
168
|
+
"Preserve material in 'target_dir' that is not in 'rpm_dir'"
|
169
|
+
) do |arg|
|
170
|
+
@options.preserve = true
|
229
171
|
end
|
230
172
|
|
231
|
-
|
232
|
-
|
233
|
-
|
173
|
+
opts.on(
|
174
|
+
'-e',
|
175
|
+
'--enforce',
|
176
|
+
'If set, enforce the copy, regardless of the setting in the config file',
|
177
|
+
' Default: false'
|
178
|
+
) do |arg|
|
179
|
+
@options.copy_rpm_data = true
|
180
|
+
end
|
234
181
|
|
235
|
-
|
236
|
-
|
182
|
+
opts.on(
|
183
|
+
'-t DIR',
|
184
|
+
'--target_dir DIR',
|
185
|
+
"The subdirectory of #{simp_target_dir('')}",
|
186
|
+
'into which to copy the materials.',
|
187
|
+
" Default: #{simp_target_dir.gsub(/#{simp_target_dir('')}/,'')}"
|
188
|
+
) do |arg|
|
189
|
+
@options.target_dir = simp_target_dir(arg.strip)
|
190
|
+
end
|
237
191
|
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
192
|
+
opts.on(
|
193
|
+
'-v',
|
194
|
+
'--verbose',
|
195
|
+
'Print out debug info when processing.'
|
196
|
+
) do
|
197
|
+
@options.debug = true
|
198
|
+
end
|
245
199
|
|
246
|
-
|
247
|
-
|
200
|
+
opts.on(
|
201
|
+
'-h',
|
202
|
+
'--help',
|
203
|
+
'Help Message'
|
204
|
+
) do
|
205
|
+
puts opts
|
206
|
+
@options.help_requested = true
|
207
|
+
end
|
208
|
+
end
|
248
209
|
|
249
|
-
|
250
|
-
|
251
|
-
|
210
|
+
begin
|
211
|
+
all_opts.parse!(args)
|
212
|
+
rescue OptionParser::ParseError => e
|
213
|
+
msg = "Error: #{e}\n\n#{all_opts}"
|
214
|
+
raise(msg)
|
215
|
+
end
|
252
216
|
|
253
|
-
|
254
|
-
fail('Error: Could not find a Puppet code directory for installation')
|
217
|
+
validate_options(all_opts.to_s)
|
255
218
|
end
|
256
219
|
|
257
|
-
|
220
|
+
# Process the config, validate the entries and do some munging
|
221
|
+
# Sets @options hash.
|
222
|
+
def process_config
|
223
|
+
# Defaults
|
224
|
+
config = {
|
225
|
+
'target_directory' => 'auto',
|
226
|
+
'copy_rpm_data' => false
|
227
|
+
}
|
228
|
+
|
229
|
+
if File.exist?(@options.config_file)
|
230
|
+
begin
|
231
|
+
system_config = YAML.load_file(@options.config_file)
|
232
|
+
if system_config
|
233
|
+
config.merge!(system_config)
|
234
|
+
end
|
235
|
+
rescue
|
236
|
+
raise("Error: Config file '#{@options.config_file}' could not be processed")
|
237
|
+
end
|
238
|
+
end
|
258
239
|
|
259
|
-
|
260
|
-
|
240
|
+
if @options.copy_rpm_data.nil?
|
241
|
+
@options.copy_rpm_data = (config['copy_rpm_data'].to_s == 'true')
|
242
|
+
end
|
261
243
|
|
262
|
-
|
263
|
-
|
244
|
+
if @options.target_dir.nil? && config['target_directory']
|
245
|
+
if config['target_directory'] == 'auto'
|
246
|
+
@options.target_dir = simp_target_dir
|
247
|
+
else
|
248
|
+
unless config['target_directory'][0].chr == '/'
|
249
|
+
raise("Error: 'target_directory' in '#{@options.config_file}' must be an absolute path")
|
250
|
+
end
|
264
251
|
|
265
|
-
|
266
|
-
|
252
|
+
@options.target_dir = config['target_directory'].strip
|
253
|
+
end
|
254
|
+
end
|
267
255
|
end
|
268
256
|
|
269
|
-
|
270
|
-
|
257
|
+
def puppet_codedir
|
258
|
+
# Figure out where the Puppet code should go
|
259
|
+
# Puppet 4+
|
260
|
+
code_dir = puppet_config['codedir']
|
261
|
+
if !code_dir || code_dir.empty?
|
262
|
+
code_dir = puppet_config['confdir']
|
263
|
+
end
|
264
|
+
|
265
|
+
return code_dir
|
271
266
|
end
|
272
267
|
|
273
|
-
|
274
|
-
|
268
|
+
def puppet_config
|
269
|
+
unless @puppet_config
|
270
|
+
@puppet_config = get_puppet_config
|
271
|
+
end
|
272
|
+
@puppet_config
|
275
273
|
end
|
276
274
|
|
277
|
-
valid_rpm_sections = ['pre','post','preun','postun']
|
278
275
|
|
279
|
-
|
280
|
-
|
276
|
+
def puppet_group
|
277
|
+
puppet_config['group']
|
281
278
|
end
|
282
279
|
|
283
|
-
|
284
|
-
|
285
|
-
|
280
|
+
# Return the target installation directory
|
281
|
+
def simp_target_dir(subdir=File.join('simp','modules'))
|
282
|
+
install_target = puppet_codedir
|
283
|
+
|
284
|
+
if install_target.empty?
|
285
|
+
raise('Error: Could not find a Puppet code directory for installation')
|
286
286
|
end
|
287
|
-
end
|
288
287
|
|
289
|
-
|
290
|
-
|
288
|
+
install_target = File.join(install_target,'environments', subdir)
|
289
|
+
|
290
|
+
return install_target
|
291
291
|
end
|
292
292
|
|
293
|
-
|
294
|
-
|
295
|
-
|
293
|
+
# Input Validation
|
294
|
+
def validate_options(usage)
|
295
|
+
return if @options.help_requested
|
296
296
|
|
297
|
-
|
297
|
+
unless @options.rpm_dir
|
298
|
+
raise("Error: 'rpm_dir' is required\n#{usage}")
|
299
|
+
end
|
298
300
|
|
299
|
-
@
|
300
|
-
|
301
|
-
|
301
|
+
unless @options.rpm_status
|
302
|
+
raise("Error: 'rpm_status' is required\n#{usage}")
|
303
|
+
end
|
302
304
|
|
303
|
-
|
304
|
-
|
305
|
+
unless @options.rpm_section
|
306
|
+
raise("Error: 'rpm_section' is required\n#{usage}")
|
307
|
+
end
|
305
308
|
|
306
|
-
#
|
307
|
-
|
309
|
+
# We allow 'post' for backward compatibility with SIMP RPMs that use
|
310
|
+
# this, but copying over files in the 'post' during an upgrade is
|
311
|
+
# problematic. If the old package has files that are not in the new
|
312
|
+
# package, these files will not be removed in the destination directory.
|
313
|
+
# This is because during %post, the old package files have not yet
|
314
|
+
# been removed from the source directory by RPM. So, the 'rsync'
|
315
|
+
# operation copies over the OBE files from the old package.
|
316
|
+
valid_rpm_sections = ['pre','post','preun','postun', 'posttrans']
|
317
|
+
|
318
|
+
unless valid_rpm_sections.include?(@options.rpm_section)
|
319
|
+
raise("Error: 'rpm_section' must be one of '#{valid_rpm_sections.join("', '")}'\n#{usage}")
|
320
|
+
end
|
308
321
|
|
309
|
-
|
310
|
-
|
322
|
+
if (@options.rpm_section == 'posttrans') || (@options.rpm_section == 'preun') || (@options.rpm_section == 'post')
|
323
|
+
unless File.directory?(@options.rpm_dir)
|
324
|
+
raise("Error: Could not find 'rpm_dir': '#{@options.rpm_dir}'")
|
325
|
+
end
|
326
|
+
end
|
311
327
|
|
312
|
-
|
313
|
-
|
314
|
-
|
328
|
+
unless @options.rpm_status =~ /^\d+$/
|
329
|
+
raise("Error: 'rpm_status' must be an integer\n#{usage}")
|
330
|
+
end
|
331
|
+
|
332
|
+
end
|
333
|
+
|
334
|
+
def handle_install
|
335
|
+
debug("Processing install, upgrade, or downgrade of #{@options.module_name}")
|
336
|
+
if @safe_modules.include?(@options.module_name)
|
315
337
|
# Make sure that we preserve anything in the safe modules on installation
|
316
|
-
options.preserve = true
|
338
|
+
@options.preserve = true
|
317
339
|
|
318
|
-
if options.rpm_status == '2'
|
340
|
+
if @options.rpm_status == '2'
|
319
341
|
# Short circuit on upgrading safe modules, just don't touch them!
|
320
|
-
|
321
|
-
|
342
|
+
target_module_dir = File.join(@options.target_dir, @options.module_name)
|
343
|
+
if File.directory?(target_module_dir)
|
344
|
+
debug("Skipping upgrade of 'safe' module directory #{target_module_dir}")
|
345
|
+
return
|
322
346
|
end
|
323
347
|
end
|
324
348
|
end
|
325
349
|
|
350
|
+
raise('Error: Could not determine puppet group') if puppet_group.empty?
|
351
|
+
rsync = Facter::Core::Execution.which('rsync')
|
352
|
+
raise("Error: Could not find 'rsync' command!") unless rsync
|
353
|
+
|
326
354
|
# Create the directories, with the proper mode, all the way down
|
327
|
-
dir_paths = options.target_dir.split(File::SEPARATOR).reject(&:empty?)
|
355
|
+
dir_paths = @options.target_dir.split(File::SEPARATOR).reject(&:empty?)
|
328
356
|
top_dir = File::SEPARATOR + dir_paths.shift
|
329
357
|
unless File.directory?(top_dir)
|
330
358
|
FileUtils.mkdir(top_dir, :mode => 0750)
|
331
|
-
FileUtils.chown('root',
|
359
|
+
FileUtils.chown('root', puppet_group, top_dir)
|
332
360
|
end
|
333
361
|
|
334
362
|
orig_dir = Dir.pwd
|
@@ -336,7 +364,7 @@ unless is_managed?(File.join(options.target_dir, options.module_name)) || !optio
|
|
336
364
|
dir_paths.each do |dir|
|
337
365
|
unless File.directory?(dir)
|
338
366
|
FileUtils.mkdir(dir, :mode => 0750)
|
339
|
-
FileUtils.chown('root',
|
367
|
+
FileUtils.chown('root', puppet_group, dir)
|
340
368
|
end
|
341
369
|
|
342
370
|
Dir.chdir(dir)
|
@@ -345,62 +373,123 @@ unless is_managed?(File.join(options.target_dir, options.module_name)) || !optio
|
|
345
373
|
|
346
374
|
cmd = %(#{rsync} -a --force)
|
347
375
|
|
348
|
-
if options.preserve
|
376
|
+
if @options.preserve
|
349
377
|
cmd += %( --ignore-existing)
|
350
378
|
else
|
351
|
-
|
379
|
+
cmd += %( --delete)
|
352
380
|
end
|
353
381
|
|
354
|
-
cmd += %(
|
382
|
+
cmd += %( --verbose) if @options.debug
|
383
|
+
|
384
|
+
cmd += %( #{@options.rpm_dir} #{@options.target_dir})
|
355
385
|
cmd += %( 2>&1)
|
356
386
|
|
387
|
+
info("Copying '#{@options.module_name}' files into '#{@options.target_dir}'")
|
388
|
+
debug("Executing: #{cmd}")
|
357
389
|
output = %x{#{cmd}}
|
390
|
+
debug("Output:\n#{output}")
|
358
391
|
unless $?.success?
|
359
|
-
|
392
|
+
raise(%(Error: Copy of '#{@options.module_name}' into '#{@options.target_dir}' using '#{cmd}' failed with the following error:\n #{output.gsub("\n","\n ")}))
|
360
393
|
end
|
361
394
|
|
362
|
-
FileUtils.chown_R(nil, "#{
|
395
|
+
FileUtils.chown_R(nil, "#{puppet_group}", @options.target_dir)
|
363
396
|
end
|
364
397
|
|
365
|
-
|
366
|
-
|
367
|
-
if options.rpm_section == 'preun' && options.rpm_status == '0'
|
398
|
+
def handle_uninstall
|
399
|
+
debug("Processing uninstall of #{@options.module_name}")
|
368
400
|
# Play it safe, this needs to have at least 'environments/simp' in it!
|
369
|
-
if options.target_dir.split(File::SEPARATOR).reject(&:empty?).size < 3
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
401
|
+
if @options.target_dir.split(File::SEPARATOR).reject(&:empty?).size < 3
|
402
|
+
raise("Error: Not removing directory '#{@options.target_dir}' for safety")
|
403
|
+
end
|
404
|
+
|
405
|
+
if @safe_modules.include?(@options.module_name)
|
406
|
+
target_module_dir = File.join(@options.target_dir, @options.module_name)
|
407
|
+
debug("Skipping removal of 'safe' module directory #{target_module_dir}")
|
408
|
+
return
|
409
|
+
end
|
410
|
+
|
411
|
+
info("Removing '#{@options.module_name}' files from '#{@options.target_dir}'")
|
412
|
+
|
413
|
+
# Find out what we have
|
414
|
+
ref_list = []
|
415
|
+
Dir.chdir(@options.rpm_dir) do
|
416
|
+
Find.find('.').each do |file|
|
417
|
+
if File.symlink?(file)
|
418
|
+
ref_list << file
|
419
|
+
Find.prune
|
384
420
|
end
|
385
421
|
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
422
|
+
ref_list << file
|
423
|
+
end
|
424
|
+
end
|
425
|
+
|
426
|
+
# Delete from the bottom up to clear out the directories first
|
427
|
+
# before removing them
|
428
|
+
ref_list.reverse!
|
429
|
+
ref_list.map{|x| x.sub!(/^./, @options.module_name)}
|
430
|
+
|
431
|
+
# Only delete items that are in the reference repo
|
432
|
+
Dir.chdir(@options.target_dir) do
|
433
|
+
ref_list.each do |to_rm|
|
434
|
+
if File.symlink?(to_rm)
|
435
|
+
debug("Removing symlink #{to_rm}")
|
436
|
+
FileUtils.rm_f(to_rm)
|
437
|
+
elsif File.directory?(to_rm) && (Dir.entries(to_rm).delete_if {|dir|
|
438
|
+
dir == '.' || dir == '..'}.size == 0)
|
439
|
+
debug("Removing directory #{to_rm}")
|
440
|
+
FileUtils.rmdir(to_rm)
|
441
|
+
elsif File.exist?(to_rm)
|
442
|
+
debug("Removing file #{to_rm}")
|
443
|
+
FileUtils.rm_f(to_rm)
|
402
444
|
end
|
403
445
|
end
|
404
446
|
end
|
405
447
|
end
|
448
|
+
|
449
|
+
def run(args)
|
450
|
+
parse_options(args)
|
451
|
+
return 0 if @options.help_requested
|
452
|
+
|
453
|
+
process_config
|
454
|
+
debug("Running with config=#{@options.to_s}")
|
455
|
+
|
456
|
+
# If the target directory is managed, we're done
|
457
|
+
target_module_dir = File.join(@options.target_dir, @options.module_name)
|
458
|
+
unless is_managed?(target_module_dir) || !@options.copy_rpm_data
|
459
|
+
|
460
|
+
debug("Processing unmanaged target directory #{target_module_dir}")
|
461
|
+
|
462
|
+
if (@options.rpm_section == 'posttrans') || (@options.rpm_section == 'post')
|
463
|
+
# A regular installation, upgrade or downgrade
|
464
|
+
# This *should* happen in the RPM %posttrans, but we allow this to
|
465
|
+
# occur in the %post for backward compatibility with SIMP RPMs that
|
466
|
+
# erroneously try to affect a copy in the %post. (Copying over the
|
467
|
+
# files in the RPM %post during an upgrade/downgrade is problematic.
|
468
|
+
# If the old package has files that are not in the new package,
|
469
|
+
# these files will not yet have been removed in the source
|
470
|
+
# directory, and thus end up in the target directory.)
|
471
|
+
handle_install
|
472
|
+
elsif @options.rpm_section == 'preun' && @options.rpm_status == '0'
|
473
|
+
# A regular uninstall
|
474
|
+
# This needs to happen *before* RPM removes the files (%preun with
|
475
|
+
# status 0), since we need to compare with what's on disk to undo
|
476
|
+
# the copy done during the RPM install via handle_install()
|
477
|
+
handle_uninstall
|
478
|
+
end
|
479
|
+
end
|
480
|
+
return 0
|
481
|
+
rescue RuntimeError => e
|
482
|
+
$stderr.puts(e)
|
483
|
+
return 1
|
484
|
+
rescue Exception => e
|
485
|
+
$stderr.puts(e)
|
486
|
+
e.backtrace.first(10).each{|l| $stderr.puts l }
|
487
|
+
return 1
|
488
|
+
end
|
406
489
|
end
|
490
|
+
|
491
|
+
if __FILE__ == $0
|
492
|
+
helper = SimpRpmHelper.new
|
493
|
+
exit helper.run(ARGV)
|
494
|
+
end
|
495
|
+
|