Skip to content

Commit 012cd99

Browse files
Provide the option to only update the live value (#15)
There are some sysctl values which, when set in /etc/sysctl.conf, may cause operational harm to a system. This patch provides the ability to only update the live value and make the disk persistence optional. Additionally: - Now use prefetching to get the sysctl values - Updated self.instances to obtain information about all sysctl values which provides a more accurate representation of the system when using `puppet resource` - Fail if the user attempts to set a value that is not valid on the system unless `silent` is set. - Updated all tests - Refactored Travis CI Tests - Added OpenSUSE support Closes #14
1 parent 1795545 commit 012cd99

File tree

12 files changed

+369
-123
lines changed

12 files changed

+369
-123
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
Gemfile.lock
12
pkg
23
coverage
34
.bundle/
@@ -9,6 +10,7 @@ spec/fixtures/manifests
910
spec/fixtures/modules
1011
yardoc/
1112
.yardoc/
13+
log/
1214

1315
## Ruby
1416
.rvmrc*

.travis.yml

Lines changed: 8 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,20 @@
11
language: ruby
22
sudo: required
33
rvm:
4-
- 1.8.7
5-
- 1.9.3
6-
- 2.0.0
4+
- 2.1.9
5+
- 2.3.1
6+
77
notifications:
88
email:
99
- raphael.pinson@camptocamp.com
1010
env:
11-
# base env
12-
# Most tests with oldest supported ruby-augeas
13-
- PUPPET=3.0.0 RUBY_AUGEAS=0.3.0 AUGEAS=1.1.0
14-
- PUPPET=3.2.0 RUBY_AUGEAS=0.3.0 AUGEAS=1.1.0
15-
- PUPPET=3.4 RUBY_AUGEAS=0.3.0 AUGEAS=1.1.0
16-
# Test the latest ruby-augeas (~>)
17-
- PUPPET=3.2.0 RUBY_AUGEAS=0.5
18-
# Use this build to publish on the forge
19-
- PUPPET=3.4 RUBY_AUGEAS=0.5 FORGE_PUBLISH=true
20-
# Test other versions of Augeas
21-
- PUPPET=3.4 RUBY_AUGEAS=0.3.0 AUGEAS=0.10.0
22-
- PUPPET=3.4 RUBY_AUGEAS=0.3.0 AUGEAS=1.0.0
23-
- PUPPET=3.4 RUBY_AUGEAS=0.3.0 AUGEAS=1.1.0
24-
- PUPPET=2.7.0 RUBY_AUGEAS=0.3.0 AUGEAS=1.2.0
25-
- PUPPET=3.4 RUBY_AUGEAS=0.3.0 AUGEAS=1.2.0
26-
# Issue #83: test old Augeas with new lenses
27-
- PUPPET=3.4 RUBY_AUGEAS=0.3.0 AUGEAS=1.0.0 LENSES=HEAD
28-
- PUPPET=3.4 RUBY_AUGEAS=0.3.0 AUGEAS=1.1.0 LENSES=HEAD
29-
- PUPPET=3.4 RUBY_AUGEAS=0.5 AUGEAS=1.0.0 LENSES=HEAD
30-
- PUPPET=3.4 RUBY_AUGEAS=0.5 AUGEAS=1.1.0 LENSES=HEAD
31-
# Test latest Puppet version
32-
- PUPPET=4.0 RUBY_AUGEAS=0.5
33-
11+
# Most common LTS Puppet Version
12+
- PUPPET=4.7 RUBY_AUGEAS=0.5 FORGE_PUBLISH=true
13+
# Current LTS Puppet Version
14+
- PUPPET=4.10 RUBY_AUGEAS=0.5
3415

3516
matrix:
3617
fast_finish: true
37-
exclude:
38-
# base exclude
39-
# No support for Ruby 2.0 before Puppet 3.2.0 and ruby-augeas 0.5
40-
- rvm: 2.0.0
41-
env: PUPPET=3.0.0 RUBY_AUGEAS=0.3.0
42-
- rvm: 2.0.0
43-
env: PUPPET=3.2.0 RUBY_AUGEAS=0.3.0
44-
- rvm: 2.0.0
45-
env: PUPPET=3.4 RUBY_AUGEAS=0.3.0
46-
- rvm: 2.0.0
47-
env: PUPPET=3.4 RUBY_AUGEAS=0.3.0 AUGEAS=0.10.0
48-
- rvm: 2.0.0
49-
env: PUPPET=3.4 RUBY_AUGEAS=0.3.0 AUGEAS=1.0.0
50-
- rvm: 2.0.0
51-
env: PUPPET=3.4 RUBY_AUGEAS=0.3.0 AUGEAS=1.1.0
52-
- rvm: 2.0.0
53-
env: PUPPET=3.0.0 RUBY_AUGEAS=0.3.0 AUGEAS=1.1.0
54-
- rvm: 2.0.0
55-
env: PUPPET=3.4 RUBY_AUGEAS=0.3.0 AUGEAS=1.2.0
56-
- rvm: 2.0.0
57-
env: PUPPET=3.4 RUBY_AUGEAS=0.3.0 AUGEAS=1.0.0 LENSES=HEAD
58-
- rvm: 2.0.0
59-
env: PUPPET=3.4 RUBY_AUGEAS=0.3.0 AUGEAS=1.1.0 LENSES=HEAD
60-
# No support for Ruby 1.8 in Puppet 4
61-
- rvm: 1.8.7
62-
env: PUPPET=4.0 RUBY_AUGEAS=0.5
63-
6418

6519
install:
6620
- "travis_retry ./.travis.sh"
@@ -78,5 +32,5 @@ deploy:
7832
# all_branches is required to use tags
7933
all_branches: true
8034
# Only publish if our main Ruby target builds
81-
rvm: 1.9.3
35+
rvm: 2.1.9
8236
condition: "$FORGE_PUBLISH = true"

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
11
# Changelog
22

3+
## 2.2.0
4+
- Removed Travis tests for Puppet < 4.7 since that is the most common LTS
5+
release and Puppet 3 is well out of support
6+
- Added OpenBSD and FreeBSD to the compatibility list
7+
- Added a :persist option for enabling saving to the /etc/sysctl.conf file
8+
- Added the capability to update either the live value *or* the disk value
9+
independently
10+
- Now use prefetching to get the sysctl values
11+
- Updated self.instances to obtain information about *all* sysctl values which
12+
provides a more accurate representation of the system when using `puppet
13+
resource`
14+
- Updated all tests
15+
316
## 2.1.0
417
- Added a :silent option for deliberately ignoring failures when applying the
518
live sysctl setting.

Gemfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ group :development, :unit_tests do
3939
gem 'puppet-lint-file_ensure-check', :require => false
4040
gem 'puppet-lint-version_comparison-check', :require => false
4141
gem 'rspec-puppet-facts', :require => false
42+
gem 'beaker-rspec', :require => false
43+
gem 'simp-beaker-helpers', :require => false
4244

4345
gem 'coveralls', :require => false unless RUBY_VERSION =~ /^1\.8/
4446
gem 'simplecov', '~> 0.7.0', :require => false

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,14 @@ Type documentation can be generated with `puppet doc -r type` or viewed on the
104104
apply => false,
105105
}
106106

107+
### only update the value with the `sysctl` command, do not persist to disk
108+
109+
sysctl { "net.ipv4.ip_forward":
110+
ensure => present,
111+
value => "1",
112+
persist => false,
113+
}
114+
107115
### ignore the application of a yet to be activated sysctl value
108116

109117
sysctl { "net.ipv6.conf.all.autoconf":

lib/puppet/provider/sysctl/augeas.rb

Lines changed: 121 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,24 @@ def self.sysctl_get(key)
3939

4040
confine :feature => :augeas
4141

42-
def self.instances
43-
augopen do |aug|
44-
resources = []
42+
def self.instances(reference_resource = nil)
43+
return @resource_cache if @resource_cache
44+
45+
resources = nil
46+
47+
augopen(reference_resource) do |aug|
48+
resources ||= []
49+
4550
aug.match("$target/*").each do |spath|
46-
resource = {:ensure => :present}
51+
resource = {
52+
:ensure => :present,
53+
:persist => :true
54+
}
4755

4856
basename = spath.split("/")[-1]
4957
resource[:name] = basename.split("[")[0]
5058
next unless resource[:name]
51-
next if resource[:name] == "#comment"
59+
next if (resource[:name] == "#comment")
5260

5361
resource[:value] = aug.get("#{spath}")
5462

@@ -62,32 +70,104 @@ def self.instances
6270
end
6371
end
6472

65-
resources << new(resource)
73+
resources << resource
74+
end
75+
end
76+
77+
# Grab everything else
78+
resources ||= []
79+
80+
sysctl('-a').each_line do |line|
81+
value = line.split('=')
82+
83+
key = value.shift.strip
84+
85+
value = value.join('=').strip
86+
87+
existing_index = resources.index{ |x| x[:name] == key }
88+
89+
if existing_index
90+
resources[existing_index][:apply] = :true
91+
else
92+
resources << {
93+
:name => key,
94+
:ensure => :present,
95+
:value => value,
96+
:apply => :true,
97+
:persist => :false
98+
}
99+
end
100+
end
101+
102+
if resources
103+
@resource_cache = resources.map{|x| x = new(x)}
104+
return @resource_cache
105+
end
106+
end
107+
108+
def self.prefetch(resources)
109+
# We need to pass a reference resource so that the proper target is in
110+
# scope.
111+
instances(resources.first.last).each do |prov|
112+
if resource = resources[prov.name]
113+
resource.provider = prov
66114
end
67-
resources
68115
end
69116
end
70117

71-
def create
72-
# the value to pass to augeas can come either from the 'value' or the
73-
# 'val' type parameter.
74-
value = resource[:value] || resource[:val]
118+
def create
119+
if resource[:persist] == :true
120+
if !valid_resource?(resource[:name]) && (resource[:silent] == :false)
121+
raise Puppet::Error, "Error: `#{resource[:name]}` is not a valid sysctl key"
122+
end
75123

76-
augopen! do |aug|
77-
# Prefer to create the node next to a commented out entry
78-
commented = aug.match("$target/#comment[.=~regexp('#{resource[:name]}([^a-z\.].*)?')]")
79-
aug.insert(commented.first, resource[:name], false) unless commented.empty?
80-
aug.set(resource_path, value)
81-
setvars(aug)
124+
# the value to pass to augeas can come either from the 'value' or the
125+
# 'val' type parameter.
126+
value = resource[:value] || resource[:val]
82127

83-
if resource[:comment]
84-
aug.insert('$resource', "#comment", true)
85-
aug.set("$target/#comment[following-sibling::*[1][self::#{resource[:name]}]]",
86-
"#{resource[:name]}: #{resource[:comment]}")
128+
augopen! do |aug|
129+
# Prefer to create the node next to a commented out entry
130+
commented = aug.match("$target/#comment[.=~regexp('#{resource[:name]}([^a-z\.].*)?')]")
131+
aug.insert(commented.first, resource[:name], false) unless commented.empty?
132+
aug.set(resource_path, value)
133+
setvars(aug)
87134
end
88135
end
89136
end
90137

138+
def valid_resource?(name)
139+
@property_hash.is_a?(Hash) && !@property_hash.empty? && (@property_hash[:apply] == :true)
140+
end
141+
142+
def exists?
143+
# If in silent mode, short circuit the process on an invalid key
144+
#
145+
# This only matters when creating entries since invalid missing entries
146+
# might be used to clean up /etc/sysctl.conf
147+
if resource[:ensure] != :absent
148+
if !valid_resource?(resource[:name])
149+
if resource[:silent] == :true
150+
debug("augeasproviders_sysctl: `#{resource[:name]}` is not a valid sysctl key")
151+
return true
152+
else
153+
raise Puppet::Error, "Error: `#{resource[:name]}` is not a valid sysctl key"
154+
end
155+
end
156+
end
157+
158+
if @property_hash[:ensure] == :present
159+
# Short circuit this if there's nothing to do
160+
if (resource[:ensure] == :absent) && (@property_hash[:persist] == :false)
161+
return false
162+
else
163+
return true
164+
end
165+
else
166+
super
167+
end
168+
end
169+
170+
91171
define_aug_method!(:destroy) do |aug, resource|
92172
aug.rm("$target/#comment[following-sibling::*[1][self::#{resource[:name]}]][. =~ regexp('#{resource[:name]}:.*')]")
93173
aug.rm('$resource')
@@ -131,11 +211,26 @@ def live_value
131211
end
132212

133213
def flush
134-
super
135-
value = resource[:value] || resource[:val]
136-
if resource[:apply] == :true && !value.nil?
137-
silent = (resource[:silent] == :true)
138-
self.class.sysctl_set(resource[:name], value, silent)
214+
if resource[:ensure] == :absent
215+
super
216+
else
217+
if resource[:apply] == :true
218+
value = resource[:value] || resource[:val]
219+
if value
220+
silent = (resource[:silent] == :true)
221+
self.class.sysctl_set(resource[:name], value, silent)
222+
end
223+
end
224+
225+
# Ensures that we only save to disk when we're supposed to
226+
if resource[:persist] == :true
227+
# Create the entry on disk if it's not already there
228+
if @property_hash[:persist] == :false
229+
create
230+
end
231+
232+
super
233+
end
139234
end
140235
end
141236
end

lib/puppet/type/sysctl.rb

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,25 @@
1515

1616
module SysctlValueSync
1717
def insync?(is)
18-
if resource[:apply] == :true
19-
@live_value = provider.live_value
20-
equal(should, is) and equal(should, @live_value)
18+
_is_insync = true
19+
20+
if provider.valid_resource?(resource[:name])
21+
if resource[:apply] == :true
22+
@live_value = provider.live_value
23+
24+
_is_insync = equal(should, @live_value)
25+
end
26+
27+
if _is_insync && (resource[:persist] == :true)
28+
_is_insync = equal(should, is)
29+
end
2130
else
22-
equal(should, is)
31+
# We won't get here unless exists? has been short circuited so we can
32+
# rely on that to raise an approprite error.
33+
debug("augeasproviders_sysctl: skipping insync? due to invalid resource `#{resource[:name]}`")
2334
end
35+
36+
return _is_insync
2437
end
2538

2639
def change_to_s(current, new)
@@ -30,15 +43,19 @@ def change_to_s(current, new)
3043
elsif equal(@live_value, new)
3144
return "changed configuration value from '#{current}' to '#{new}'"
3245
else
33-
return "changed configuration value from '#{current}' to '#{new}' and live value from '#{@live_value}' to '#{new}'"
46+
if resource[:persist] == :true
47+
return "changed configuration value from '#{current}' to '#{new}' and live value from '#{@live_value}' to '#{new}'"
48+
else
49+
return "changed live value from '#{@live_value}' to '#{new}'"
50+
end
3451
end
3552
else
3653
return "changed configuration value from '#{current}' to '#{new}'"
3754
end
3855
end
3956

4057
def equal(a, b)
41-
a.gsub(/\s+/, ' ') == b.gsub(/\s+/, ' ')
58+
a && b && (a.gsub(/\s+/, ' ') == b.gsub(/\s+/, ' '))
4259
end
4360
end
4461

@@ -77,6 +94,12 @@ def equal(a, b)
7794
defaultto(:true)
7895
end
7996

97+
newparam(:persist, :boolean => true) do
98+
desc "Persist the value in the on-disk file ($target)."
99+
newvalues(:true, :false)
100+
defaultto(:true)
101+
end
102+
80103
newparam(:silent, :boolean => true) do
81104
desc "If set, do not report an error if the system key does not exist. This is useful for systems that may need to load a kernel module prior to the sysctl values existing."
82105
newvalues(:true, :false)

0 commit comments

Comments
 (0)