Skip to content

Commit

Permalink
sshd_config: create multiple entries in configuration file when an ar…
Browse files Browse the repository at this point in the history
…ray is

given as the value, e.g.

  value => ['10.0.0.1', '10.0.0.2'],

becomes

  ListenAddress 10.0.0.1
  ListenAddress 10.0.0.2

Fixes issue #13
  • Loading branch information
Dominic Cleal committed Sep 18, 2012
1 parent 19a5ceb commit 3700366
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 43 deletions.
89 changes: 57 additions & 32 deletions lib/puppet/provider/sshd_config/augeas.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,17 @@ def self.path_label(path)
path.split("/")[-1].split("[")[0]
end

def self.get_value(aug, path)
value = Array.new()
if aug.match("#{path}/1").empty?
value.push(aug.get(path))
else
aug.match("#{path}/*").each do |value_path|
value.push(aug.get(value_path))
def self.get_value(aug, pathx)
aug.match(pathx).map do |vp|
# Bug in Augeas lens, counter isn't reset to 1 so check for any int
if aug.match("#{vp}/*[label()=~regexp('[0-9]*')]").empty?
aug.get(vp)
else
aug.match("#{vp}/*").map do |svp|
aug.get(svp)
end
end
end
value
end.flatten
end

def self.set_value(aug, path, value)
Expand All @@ -51,7 +52,21 @@ def self.set_value(aug, path, value)
aug.set("#{path}/#{count}", v)
end
else
aug.set(path, value[0])
# Normal setting: one value per entry
value = value.clone

# Change any existing settings with this name
aug.match(path).each do |sp|
aug.set(sp, value.shift)
end

# Insert new values for the rest
value.each do |v|
unless aug.match("#{path}/../Match").empty?
aug.insert("#{path}/../Match[1]", path_label(path), true)
end
aug.set("#{path}[last()]", v)
end
end
end

Expand All @@ -60,31 +75,41 @@ def self.instances
begin
resources = []
aug = augopen
aug.match("/files#{file}/*").each do |hpath|
name = self.path_label(hpath)
next if name.start_with?("#", "@")

if name =~ /Match(\[\d\*\])?/
conditions = Array.new()
aug.match("#{hpath}/Condition/*").each do |cond_path|
cond_name = self.path_label(cond_path)
cond_value = aug.get(cond_path)
conditions.push("#{cond_name} #{cond_value}")
end
cond_str = conditions.join(" ")
aug.match("#{hpath}/Settings/*").each do |setting_path|
setting_name = self.path_label(setting_path)
value = self.get_value(aug, setting_path)
entry = {:ensure => :present, :name => setting_name,
:value => value, :condition => cond_str}
resources << new(entry) if entry[:value]
end
else
value = self.get_value(aug, hpath)
entry = {:ensure => :present, :name => name, :value => value}

# Ordinary settings outside of match blocks
# Find all unique setting names, then find all instances of it
settings = aug.match("/files#{file}/*[label()!='Match']").map {|spath|
self.path_label(spath)
}.uniq.reject {|name| name.start_with?("#", "@")}

settings.each do |name|
value = self.get_value(aug, "/files#{file}/#{name}")
entry = {:ensure => :present, :name => name, :value => value}
resources << new(entry) if entry[:value]
end

# Settings inside match blocks
aug.match("/files#{file}/Match").each do |mpath|
conditions = []
aug.match("#{mpath}/Condition/*").each do |cond_path|
cond_name = self.path_label(cond_path)
cond_value = aug.get(cond_path)
conditions.push("#{cond_name} #{cond_value}")
end
cond_str = conditions.join(" ")

settings = aug.match("#{mpath}/Settings/*").map {|spath|
self.path_label(spath)
}.uniq.reject {|name| name.start_with?("#", "@")}

settings.each do |name|
value = self.get_value(aug, "#{mpath}/Settings/#{name}")
entry = {:ensure => :present, :name => name,
:value => value, :condition => cond_str}
resources << new(entry) if entry[:value]
end
end

resources
ensure
aug.close if aug
Expand Down
4 changes: 2 additions & 2 deletions spec/fixtures/unit/puppet/sshd_config/full
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@

#Port 22
#AddressFamily any
#ListenAddress 0.0.0.0
#ListenAddress ::
ListenAddress 0.0.0.0
ListenAddress ::

# The default requires explicit activation of protocol 1
#Protocol 2
Expand Down
53 changes: 44 additions & 9 deletions spec/unit/puppet/sshd_config_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,16 @@
}
}

inst.size.should == 18
inst[0].should == {:name=>"SyslogFacility", :ensure=>:present, :value=>["AUTHPRIV"], :condition=>:absent}
inst[1].should == {:name=>"AllowGroups", :ensure=>:present, :value=>["sshusers", "admins"], :condition=>:absent}
inst[2].should == {:name=>"PermitRootLogin", :ensure=>:present, :value=>["without-password"], :condition=>:absent}
inst[3].should == {:name=>"PasswordAuthentication", :ensure=>:present, :value=>["yes"], :condition=>:absent}
inst[7].should == {:name=>"UsePAM", :ensure=>:present, :value=>["yes"], :condition=>:absent}
inst[8].should == {:name=>"AcceptEnv", :ensure=>:present, :value=>["LANG", "LC_CTYPE", "LC_NUMERIC", "LC_TIME", "LC_COLLATE", "LC_MONETARY", "LC_MESSAGES"], :condition=>:absent}
inst[14].should == {:name=>"X11Forwarding", :ensure=>:present, :value=>["no"], :condition=> "User anoncvs"}
inst[17].should == {:name=>"AllowAgentForwarding", :ensure=>:present, :value=>["no"], :condition=> "Host *.example.net User *"}
inst.size.should == 16
inst[0].should == {:name=>"ListenAddress", :ensure=>:present, :value=>["0.0.0.0", "::"], :condition=>:absent}
inst[1].should == {:name=>"SyslogFacility", :ensure=>:present, :value=>["AUTHPRIV"], :condition=>:absent}
inst[2].should == {:name=>"AllowGroups", :ensure=>:present, :value=>["sshusers", "admins"], :condition=>:absent}
inst[3].should == {:name=>"PermitRootLogin", :ensure=>:present, :value=>["without-password"], :condition=>:absent}
inst[4].should == {:name=>"PasswordAuthentication", :ensure=>:present, :value=>["yes"], :condition=>:absent}
inst[8].should == {:name=>"UsePAM", :ensure=>:present, :value=>["yes"], :condition=>:absent}
inst[9].should == {:name=>"AcceptEnv", :ensure=>:present, :value=>["LANG", "LC_CTYPE", "LC_NUMERIC", "LC_TIME", "LC_COLLATE", "LC_MONETARY", "LC_MESSAGES", "LC_PAPER", "LC_NAME", "LC_ADDRESS", "LC_TELEPHONE", "LC_MEASUREMENT", "LC_IDENTIFICATION", "LC_ALL", "LANGUAGE", "XMODIFIERS"], :condition=>:absent}
inst[12].should == {:name=>"X11Forwarding", :ensure=>:present, :value=>["no"], :condition=> "User anoncvs"}
inst[15].should == {:name=>"AllowAgentForwarding", :ensure=>:present, :value=>["no"], :condition=> "Host *.example.net User *"}
end

describe "when creating settings" do
Expand Down Expand Up @@ -121,6 +122,22 @@
aug.get("AcceptEnv/2").should == "LC_FOO"
end
end

it "should replace multiple single-value settings" do
apply!(Puppet::Type.type(:sshd_config).new(
:name => "ListenAddress",
:value => ["192.168.1.1", "192.168.2.1", "192.168.3.1"],
:target => target,
:provider => "augeas"
))

aug_open(target, "Sshd.lns") do |aug|
aug.match("ListenAddress").size.should == 3
aug.get("ListenAddress[1]").should == "192.168.1.1"
aug.get("ListenAddress[2]").should == "192.168.2.1"
aug.get("ListenAddress[3]").should == "192.168.3.1"
end
end
end

describe "when deleting settings" do
Expand All @@ -142,6 +159,24 @@
end
end

it "should delete all instances of a setting" do
expr = "ListenAddress"
aug_open(target, "Sshd.lns") do |aug|
aug.match(expr).should_not == []
end

apply!(Puppet::Type.type(:sshd_config).new(
:name => "ListenAddress",
:ensure => "absent",
:target => target,
:provider => "augeas"
))

aug_open(target, "Sshd.lns") do |aug|
aug.match(expr).should == []
end
end

it "should delete from a Match block" do
expr = "Match[*]/Settings/AllowAgentForwarding"
aug_open(target, "Sshd.lns") do |aug|
Expand Down

2 comments on commit 3700366

@domcleal
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Alexander,

Oops, thanks for finding that bug. The issue lies in the fact the code handles differently if there's a Match block in the config file, which the test's sample file does. I'm going to build up a few more tests before pushing the fix, to make sure nothing else is broken.

@alexanderdavidsen
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great Dominic! :)

Please sign in to comment.