Skip to content

Commit 811e06a

Browse files
author
Ciprian Badescu
committed
(PUP-1537) add mark property for package
This commit adds `mark` property for package providers on Debian(dpkg/apt/fink/aptitude) and Solaris(pgk) as alternative of using "held" value for `ensure`. Using "held" value for `ensure` works as before, but it shows deprecation warning and will be removed in further release. Allowed values for `mark` are "hold/none", default to "none". Mark can be specified with or without `ensure`, if `ensure` is missing it will default to "present". Mark cannot be specified together with "purged", "absent" or "held" values for `ensure`.
1 parent 4c86c04 commit 811e06a

File tree

11 files changed

+238
-30
lines changed

11 files changed

+238
-30
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
test_name "dpkg ensure held package is latest installed"
2+
confine :to, :platform => /debian-8-amd64/
3+
tag 'audit:low'
4+
5+
require 'puppet/acceptance/common_utils'
6+
extend Puppet::Acceptance::PackageUtils
7+
extend Puppet::Acceptance::ManifestUtils
8+
9+
10+
package = "nginx"
11+
12+
agents.each do |agent|
13+
teardown do
14+
package_absent(agent, package, '--force-yes')
15+
end
16+
end
17+
18+
step"Ensure that package is installed first if not present" do
19+
expected_package_version = on(agent.name, "apt-cache policy #{package} | sed -n -e 's/Candidate: //p'").stdout
20+
package_manifest = resource_manifest('package', package, mark: "hold")
21+
22+
apply_manifest_on(agent, package_manifest) do |result|
23+
installed_package_version = on(agent.name, "apt-cache policy #{package} | sed -n -e 's/Installed: //p'").stdout
24+
assert_match(expected_package_version, installed_package_version)
25+
end
26+
end
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
test_name "dpkg ensure held package should preserve version if package is allready installed"
2+
confine :to, :platform => /debian-8-amd64/
3+
tag 'audit:low'
4+
5+
require 'puppet/acceptance/common_utils'
6+
extend Puppet::Acceptance::PackageUtils
7+
extend Puppet::Acceptance::ManifestUtils
8+
9+
package = "openssl"
10+
11+
step "Ensure held should lock to specific installed version" do
12+
existing_installed_version = on(agent.name, "dpkg -s #{package} | sed -n -e 's/Version: //p'").stdout
13+
existing_installed_version.delete!(' ')
14+
15+
package_manifest_held = resource_manifest('package', package, mark: "hold")
16+
apply_manifest_on(agent, package_manifest_held) do
17+
installed_version = on(agent.name, "apt-cache policy #{package} | sed -n -e 's/Installed: //p'").stdout
18+
installed_version.delete!(' ')
19+
assert_match(existing_installed_version, installed_version)
20+
end
21+
end

lib/puppet/provider/package/apt.rb

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,12 @@ def install
7070
cmd += install_options if @resource[:install_options]
7171
cmd << :install << str
7272

73-
aptget(*cmd)
73+
self.unhold if self.properties[:mark] == :hold
74+
begin
75+
aptget(*cmd)
76+
ensure
77+
self.hold if @resource[:mark] == :hold
78+
end
7479
end
7580

7681
# What's the latest package version available?
@@ -100,12 +105,24 @@ def run_preseed
100105

101106
def uninstall
102107
self.run_preseed if @resource[:responsefile]
103-
aptget "-y", "-q", :remove, @resource[:name]
108+
self.unhold if self.properties[:mark] == :hold
109+
begin
110+
aptget "-y", "-q", :remove, @resource[:name]
111+
rescue StandardError, LoadError => e
112+
self.hold if self.properties[:mark] == :hold
113+
raise e
114+
end
104115
end
105116

106117
def purge
107118
self.run_preseed if @resource[:responsefile]
108-
aptget '-y', '-q', :remove, '--purge', @resource[:name]
119+
self.unhold if self.properties[:mark] == :hold
120+
begin
121+
aptget '-y', '-q', :remove, '--purge', @resource[:name]
122+
rescue StandardError, LoadError => e
123+
self.hold if self.properties[:mark] == :hold
124+
raise e
125+
end
109126
# workaround a "bug" in apt, that already removed packages are not purged
110127
super
111128
end

lib/puppet/provider/package/dpkg.rb

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ def self.instances
4444
# Note: self:: is required here to keep these constants in the context of what will
4545
# eventually become this Puppet::Type::Package::ProviderDpkg class.
4646
self::DPKG_QUERY_FORMAT_STRING = %Q{'${Status} ${Package} ${Version}\\n'}
47-
self::FIELDS_REGEX = %r{^(\S+) +(\S+) +(\S+) (\S+) (\S*)$}
47+
self::FIELDS_REGEX = %r{^'?(\S+) +(\S+) +(\S+) (\S+) (\S*)$}
4848
self::FIELDS= [:desired, :error, :status, :name, :ensure]
4949

5050
# @param line [String] one line of dpkg-query output
@@ -67,7 +67,7 @@ def self.parse_line(line)
6767
elsif ['config-files', 'half-installed', 'unpacked', 'half-configured'].include?(hash[:status])
6868
hash[:ensure] = :absent
6969
end
70-
hash[:ensure] = :held if hash[:desired] == 'hold'
70+
hash[:mark] = :hold if hash[:desired] == 'hold'
7171
else
7272
Puppet.debug("Failed to match dpkg-query line #{line.inspect}")
7373
end
@@ -83,8 +83,6 @@ def install
8383
end
8484
args = []
8585

86-
# We always unhold when installing to remove any prior hold.
87-
self.unhold
8886

8987
if @resource[:configfiles] == :keep
9088
args << '--force-confold'
@@ -93,7 +91,12 @@ def install
9391
end
9492
args << '-i' << file
9593

96-
dpkg(*args)
94+
self.unhold if self.properties[:mark] == :hold
95+
begin
96+
dpkg(*args)
97+
ensure
98+
self.hold if @resource[:mark] == :hold
99+
end
97100
end
98101

99102
def update
@@ -137,17 +140,33 @@ def query
137140
end
138141

139142
def uninstall
140-
dpkg "-r", @resource[:name]
143+
self.unhold if self.properties[:mark] == :hold
144+
begin
145+
dpkg "-r", @resource[:name]
146+
rescue StandardError, LoadError => e
147+
self.hold if self.properties[:mark] == :hold
148+
raise e
149+
end
141150
end
142151

143152
def purge
144-
dpkg "--purge", @resource[:name]
153+
self.unhold if self.properties[:mark] == :hold
154+
begin
155+
dpkg "--purge", @resource[:name]
156+
rescue StandardError, LoadError => e
157+
self.hold if self.properties[:mark] == :hold
158+
raise e
159+
end
145160
end
146161

147-
def hold
162+
def deprecated_hold
148163
if package_not_installed?
149164
self.install
150165
end
166+
hold
167+
end
168+
169+
def hold
151170
Tempfile.open('puppet_dpkg_set_selection') do |tmpfile|
152171
tmpfile.write("#{@resource[:name]} hold\n")
153172
tmpfile.flush

lib/puppet/provider/package/fink.rb

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,12 @@ def install
3737

3838
cmd << :install << str
3939

40-
finkcmd(cmd)
40+
self.unhold if self.properties[:mark] == :hold
41+
begin
42+
finkcmd(cmd)
43+
ensure
44+
self.hold if @resource[:mark] == :hold
45+
end
4146
end
4247

4348
# What's the latest package version available?
@@ -70,10 +75,22 @@ def update
7075
end
7176

7277
def uninstall
73-
finkcmd "-y", "-q", :remove, @model[:name]
78+
self.unhold if self.properties[:mark] == :hold
79+
begin
80+
finkcmd "-y", "-q", :remove, @model[:name]
81+
rescue StandardError, LoadError => e
82+
self.hold if self.properties[:mark] == :hold
83+
raise e
84+
end
7485
end
7586

7687
def purge
77-
aptget '-y', '-q', 'remove', '--purge', @resource[:name]
88+
self.unhold if self.properties[:mark] == :hold
89+
begin
90+
aptget '-y', '-q', 'remove', '--purge', @resource[:name]
91+
rescue StandardError, LoadError => e
92+
self.hold if self.properties[:mark] == :hold
93+
raise e
94+
end
7895
end
7996
end

lib/puppet/provider/package/pkg.rb

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ def self.ifo_flag(flags)
4949
).merge(
5050
case flags[1..1]
5151
when 'f'
52-
{:ensure => 'held'}
52+
{:mark => :hold}
5353
when '-'
5454
{}
5555
else
@@ -107,6 +107,10 @@ def self.parse_line(line)
107107
end).merge({:provider => self.name})
108108
end
109109

110+
def deprecated_hold
111+
hold
112+
end
113+
110114
def hold
111115
pkg(:freeze, @resource[:name])
112116
end
@@ -201,8 +205,6 @@ def latest
201205
def install(nofail = false)
202206
name = @resource[:name]
203207
should = @resource[:ensure]
204-
# always unhold if explicitly told to install/update
205-
self.unhold
206208
is = self.query
207209
if is[:ensure].to_sym == :absent
208210
command = 'install'
@@ -216,7 +218,12 @@ def install(nofail = false)
216218
unless should.is_a? Symbol
217219
name += "@#{should}"
218220
end
219-
r = exec_cmd(command(:pkg), command, *args, name)
221+
self.unhold if self.properties[:mark] == :hold
222+
begin
223+
r = exec_cmd(command(:pkg), command, *args, name)
224+
ensure
225+
self.hold if @resource[:mark] == :hold
226+
end
220227
return r if nofail
221228
raise Puppet::Error, _("Unable to update %{package}") % { package: r[:out] } if r[:exit] != 0
222229
end
@@ -230,7 +237,13 @@ def uninstall
230237
cmd << '-r'
231238
end
232239
cmd << @resource[:name]
233-
pkg cmd
240+
self.unhold if self.properties[:mark] == :hold
241+
begin
242+
pkg cmd
243+
rescue StandardError, LoadError => e
244+
self.hold if self.properties[:mark] == :hold
245+
raise e
246+
end
234247
end
235248

236249
# update the package to the latest version available

lib/puppet/type/package.rb

Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,8 @@ module Puppet
5454
feature :holdable, "The provider is capable of placing packages on hold
5555
such that they are not automatically upgraded as a result of
5656
other package dependencies unless explicit action is taken by
57-
a user or another package. Held is considered a superset of
58-
installed.",
59-
:methods => [:hold]
57+
a user or another package.",
58+
:methods => [:hold, :unhold]
6059
feature :install_only, "The provider accepts options to only install packages never update (kernels, etc.)"
6160
feature :install_options, "The provider accepts options to be
6261
passed to the installer command."
@@ -101,7 +100,7 @@ module Puppet
101100
end
102101

103102
newvalue(:held, :event => :package_held, :required_features => :holdable) do
104-
provider.hold
103+
provider.deprecated_hold
105104
end
106105

107106
# Alias the 'present' value.
@@ -611,5 +610,59 @@ def refresh
611610
provider.reinstall
612611
end
613612
end
613+
614+
newproperty(:mark, :required_features => :holdable) do
615+
mark_doc='Valid values are: hold/none'
616+
desc <<-EOT
617+
Set to hold to tell Debian apt/Solaris pkg to hold the package version
618+
619+
#{mark_doc}
620+
Default is "none". Mark can be specified with or without `ensure`,
621+
if `ensure` is missing will default to "present".
622+
623+
Mark cannot be specified together with "purged", "absent" or "held"
624+
values for `ensure`.
625+
EOT
626+
newvalues(:hold, :none)
627+
munge do |value|
628+
case value
629+
when "hold", :hold
630+
:hold
631+
when "none", :none
632+
:none
633+
else
634+
raise ArgumentError, _('Invalid hold value %{value}. %{doc}') % { value: value.inspect, doc: mark_doc}
635+
end
636+
end
637+
638+
def insync?(is)
639+
@should[0] == is
640+
end
641+
642+
def should
643+
@should[0] if @should && @should.is_a?(Array) && @should.size == 1
644+
end
645+
646+
def retrieve
647+
provider.properties[:mark]
648+
end
649+
650+
def sync
651+
if @should[0] == :hold
652+
provider.hold
653+
else
654+
provider.unhold
655+
end
656+
end
657+
end
658+
659+
validate do
660+
if :held == @parameters[:ensure].should
661+
warning "\"ensure=>held\" has been deprecated and will be removed in a future version, use \"mark=hold\" instead "
662+
end
663+
if @parameters[:mark] && [:absent, :purged, :held].include?(@parameters[:ensure].should)
664+
raise ArgumentError, _("You cannot use \"mark\" property while \"ensure\" is one of [\"absent\", \"purged\", \"held\"]")
665+
end
666+
end
614667
end
615668
end

0 commit comments

Comments
 (0)