Skip to content

Commit

Permalink
Add support for comments in all types and providers
Browse files Browse the repository at this point in the history
* ssh_config
* sshd_config
* sshd_config_match
* sshd_config_subsystem

Co-authored-by: Jason Grammenos <jason.grammenos@agilitypr.com>
  • Loading branch information
raphink and jgrammen-agilitypr committed Jul 15, 2020
1 parent 1052668 commit ccfafdd
Show file tree
Hide file tree
Showing 16 changed files with 438 additions and 78 deletions.
157 changes: 94 additions & 63 deletions lib/puppet/provider/ssh_config/augeas.rb
Expand Up @@ -25,77 +25,77 @@ def self.base_path(resource)
"$target/Host[.='#{resource[:host]}']"
end

def self.instances
augopen do |aug,path|
resources = []
aug.match('$target/Host').each do |hpath|
aug.match("#{hpath}/*").each do |kpath|
label = path_label(aug, kpath)
next if label.start_with?("#")

host = aug.get(hpath)
value = self.get_value(aug, kpath)

resources << new({
:ensure => :present,
:name => label,
:key => label,
:value => value,
:host => host
})
def self.instances
augopen do |aug,path|
resources = []
aug.match('$target/Host').each do |hpath|
aug.match("#{hpath}/*").each do |kpath|
label = path_label(aug, kpath)
next if label.start_with?("#")

host = aug.get(hpath)
value = self.get_value(aug, kpath)

resources << new({
:ensure => :present,
:name => label,
:key => label,
:value => value,
:host => host
})
end
end
resources
end
resources
end
end

def self.get_value(aug, pathx)
aug.match(pathx).map do |vp|
# Augeas lens does transparent multi-node (no counte reset) 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)
def self.get_value(aug, pathx)
aug.match(pathx).map do |vp|
# Augeas lens does transparent multi-node (no counte reset) 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
end.flatten
end
end.flatten
end

def self.set_value(aug, base, path, label, value)
if label =~ /Ciphers|SendEnv|MACs|(HostKey|Kex)Algorithms|GlobalKnownHostsFile/i
aug.rm("#{path}/*")
# In case there is more than one entry, keep only the first one
aug.rm("#{path}[position() != 1]")
count = 0
value.each do |v|
count += 1
aug.set("#{path}/#{count}", v)
end
else
# Normal setting: one value per entry
value = value.clone

# Change any existing settings with this name
lastsp = nil
aug.match(path).each do |sp|
val = value.shift
if val.nil?
aug.rm(sp)
else
aug.set(sp, val)
lastsp = sp
def self.set_value(aug, base, path, label, value)
if label =~ /Ciphers|SendEnv|MACs|(HostKey|Kex)Algorithms|GlobalKnownHostsFile/i
aug.rm("#{path}/*")
# In case there is more than one entry, keep only the first one
aug.rm("#{path}[position() != 1]")
count = 0
value.each do |v|
count += 1
aug.set("#{path}/#{count}", v)
end
else
# Normal setting: one value per entry
value = value.clone

# Change any existing settings with this name
lastsp = nil
aug.match(path).each do |sp|
val = value.shift
if val.nil?
aug.rm(sp)
else
aug.set(sp, val)
lastsp = sp
end
end
end

# Insert new values for the rest
value.each do |v|
if lastsp
# After the most recent same setting (lastsp)
aug.insert(lastsp, label, false)
aug.set("#{path}[last()]", v)
else
# Prefer to create the node next to a commented out entry
# Insert new values for the rest
value.each do |v|
if lastsp
# After the most recent same setting (lastsp)
aug.insert(lastsp, label, false)
aug.set("#{path}[last()]", v)
else
# Prefer to create the node next to a commented out entry
commented = aug.match("#{base}/#comment[.=~regexp('#{label}([^a-z\.].*)?')]")
unless commented.empty?
aug.insert(commented.first, label, false)
Expand All @@ -104,6 +104,7 @@ def self.set_value(aug, base, path, label, value)
end
lastsp = aug.match("#{path}[last()]")[0]
end
aug.defvar('resource', path)
end
end

Expand All @@ -114,6 +115,7 @@ def create
# create base_path
aug.set(base_path, resource[:host])
self.class.set_value(aug, base_path, "#{base_path}/#{key}", key, resource[:value])
self.class.set_comment(aug, base_path, resource[:name], resource[:comment]) if resource[:comment]
end
end

Expand All @@ -129,4 +131,33 @@ def value=(value)
self.class.set_value(aug, self.class.base_path(resource), resource_path, key, value)
end
end

def comment
base_path = self.class.base_path(resource)
augopen do |aug|
comment = aug.get("#{base_path}/#comment[following-sibling::*[1][label() =~ regexp('#{resource[:name]}', 'i')]][. =~ regexp('#{resource[:name]}:.*', 'i')]")
comment.sub!(/^#{resource[:name]}:\s*/i, "") if comment
comment || ""
end
end

def comment=(value)
base_path = self.class.base_path(resource)
augopen! do |aug|
self.class.set_comment(aug, base_path, resource[:name], value)
end
end

def self.set_comment(aug, base, name, value)
cmtnode = "#{base}/#comment[following-sibling::*[1][label() =~ regexp('#{name}', 'i')]][. =~ regexp('#{name}:.*', 'i')]"
if value.empty?
aug.rm(cmtnode)
else
if aug.match(cmtnode).empty?
aug.insert('$resource', "#comment", true)
end
aug.set("#{base}/#comment[following-sibling::*[1][label() =~ regexp('#{name}', 'i')]]",
"#{name}: #{value}")
end
end
end
32 changes: 32 additions & 0 deletions lib/puppet/provider/sshd_config/augeas.rb
Expand Up @@ -185,6 +185,7 @@ def create
end

self.class.set_value(aug, base_path, "#{base_path}/#{key}", key, resource[:value])
self.class.set_comment(aug, base_path, key, resource[:comment]) if resource[:comment]
end
end

Expand All @@ -207,4 +208,35 @@ def value=(value)
self.class.set_value(aug, self.class.base_path(resource), resource_path, key, value)
end
end

def comment
base_path = self.class.base_path(resource)
key = resource[:key] ? resource[:key] : resource[:name]
augopen do |aug|
comment = aug.get("#{base_path}/#comment[following-sibling::*[1][label() =~ regexp('#{key}', 'i')]][. =~ regexp('#{key}:.*', 'i')]")
comment.sub!(/^#{key}:\s*/i, "") if comment
comment || ""
end
end

def comment=(value)
base_path = self.class.base_path(resource)
key = resource[:key] ? resource[:key] : resource[:name]
augopen! do |aug|
self.class.set_comment(aug, base_path, key, value)
end
end

def self.set_comment(aug, base, name, value)
cmtnode = "#{base}/#comment[following-sibling::*[1][label() =~ regexp('#{name}', 'i')]][. =~ regexp('#{name}:.*', 'i')]"
if value.empty?
aug.rm(cmtnode)
else
if aug.match(cmtnode).empty?
aug.insert("#{base}/#{name}", "#comment", true)
end
aug.set("#{base}/#comment[following-sibling::*[1][label() =~ regexp('#{name}', 'i')]]",
"#{name}: #{value}")
end
end
end
33 changes: 29 additions & 4 deletions lib/puppet/provider/sshd_config_match/augeas.rb
Expand Up @@ -23,7 +23,8 @@ def self.static_path(resource)
end

def self.path(resource)
path = "$target/*[label()=~regexp('match', 'i') and *[label()=~regexp('condition', 'i') and count(*)=#{resource[:condition].keys.size}]"
path = "$target/*"
path += "[label()=~regexp('match', 'i') and *[label()=~regexp('condition', 'i') and count(*)=#{resource[:condition].keys.size}]"
resource[:condition].each do |c, v|
path += "[*[label()=~regexp('#{c}', 'i')]='#{v}']"
end
Expand Down Expand Up @@ -104,6 +105,7 @@ def self.position!(aug, resource)
def position!
augopen! do |aug|
self.class.position!(aug, resource)
self.comment = resource[:comment]
end
end

Expand All @@ -115,12 +117,35 @@ def create
aug.set("$resource/Condition/#{c}", v)
end
aug.clear("$resource/Settings")
# At least one entry is mandatory (in the lens at least)
aug.set("$resource/Settings/#comment", 'Created by Puppet')

self.class.position!(aug, resource) \
if !self.class.in_position?(aug, resource) and resource[:position]

# At least one entry is mandatory (in the lens at least)
self.comment = resource[:comment]
end
end

def comment
augopen do |aug|
comment = aug.get("$resource/Settings/#comment[1]")
comment.sub!(/^#{resource[:name]}:\s*/i, "") if comment
comment || ""
end
end
end

def comment=(value)
augopen! do |aug|
cmtnode = "$resource/Settings/#comment[1]"

if aug.match(cmtnode).empty?
if aug.match("$resource/Settings/*").any?
# Insert before first entry
aug.insert("$resource/Settings/*[1]", "#comment", true)
end
end

aug.set(cmtnode, "#{resource[:name]}: #{resource[:comment]}")
end
end
end
37 changes: 32 additions & 5 deletions lib/puppet/provider/sshd_config_subsystem/augeas.rb
Expand Up @@ -31,13 +31,16 @@ def self.instances
end
end

define_aug_method!(:create) do |aug, resource|
def create
key = resource[:name]
unless aug.match("$target/Match").empty?
aug.insert("$target/Match[1]", "Subsystem", true)
aug.clear("$target/Subsystem[last()]/#{key}")
augopen! do |aug|
unless aug.match("$target/Match").empty?
aug.insert("$target/Match[1]", "Subsystem", true)
aug.clear("$target/Subsystem[last()]/#{key}")
end
aug.set("$target/Subsystem/#{resource[:name]}", resource[:command])
self.comment = resource[:comment] if resource[:comment]
end
aug.set("$target/Subsystem/#{resource[:name]}", resource[:command])
end

define_aug_method!(:destroy) do |aug, resource|
Expand All @@ -46,4 +49,28 @@ def self.instances
end

attr_aug_accessor(:command, :label => :resource)


def comment
augopen do |aug|
comment = aug.get("$target/#comment[following-sibling::*[1][label() =~ regexp('Subsystem', 'i') and #{resource[:name]}]]")
comment.sub!(/^#{resource[:name]}:\s*/i, "") if comment
comment || ""
end
end

def comment=(value)
augopen! do |aug|
cmtnode = "$target/#comment[following-sibling::*[1][label() =~ regexp('Subsystem', 'i') and #{resource[:name]}]]"

if value.empty?
aug.rm(cmtnode)
else
if aug.match(cmtnode).empty?
aug.insert("$target/*[label()=~regexp('Subsystem', 'i') and #{resource[:name]}]", "#comment", true)
end
aug.set(cmtnode, "#{resource[:name]}: #{resource[:comment]}")
end
end
end
end
4 changes: 4 additions & 0 deletions lib/puppet/type/ssh_config.rb
Expand Up @@ -50,6 +50,10 @@
defaultto { '*' }
end

newproperty(:comment) do
desc "Text to be stored in a comment immediately above the entry. It will be automatically prepended with the name of the variable in order for the provider to know whether it controls the comment or not."
end

autorequire(:file) do
self[:target]
end
Expand Down
4 changes: 4 additions & 0 deletions lib/puppet/type/sshd_config.rb
Expand Up @@ -130,6 +130,10 @@ def should_to_s(new_value)
end
end

newproperty(:comment) do
desc "Text to be stored in a comment immediately above the entry. It will be automatically prepended with the name of the variable in order for the provider to know whether it controls the comment or not."
end

autorequire(:file) do
self[:target]
end
Expand Down
5 changes: 5 additions & 0 deletions lib/puppet/type/sshd_config_match.rb
Expand Up @@ -84,6 +84,11 @@ def self.title_patterns
end
end

newproperty(:comment) do
desc "Text to be stored in a comment immediately above the entry. It will be automatically prepended with the name of the variable in order for the provider to know whether it controls the comment or not."
defaultto { "created by Puppet" }
end

autorequire(:file) do
self[:target]
end
Expand Down
4 changes: 4 additions & 0 deletions lib/puppet/type/sshd_config_subsystem.rb
Expand Up @@ -21,6 +21,10 @@
desc "The file in which to store the settings, defaults to
`/etc/ssh/sshd_config`."
end

newproperty(:comment) do
desc "Text to be stored in a comment immediately above the entry. It will be automatically prepended with the name of the variable in order for the provider to know whether it controls the comment or not."
end

autorequire(:file) do
self[:target]
Expand Down

0 comments on commit ccfafdd

Please sign in to comment.