SlideShare ist ein Scribd-Unternehmen logo
1 von 38
Downloaden Sie, um offline zu lesen
Configuration surgery with Augeas
                         Raphaël Pinson

                            @raphink
                     LSM 2012, Geneva
                          2012-07-11
https://github.com/raphink/augeas-talks/
Tired of ugly sed and awk one liners?




  or of using tons of different parsing libraries or
               common::line tricks?




           www.camptocamp.com /                        2/38
Become a configuration surgeon with




                        Augeas


        www.camptocamp.com /          3/38
What is the need?




●   A lot of different syntaxes
●   Securely editing configuration files with a
    unified API




            www.camptocamp.com /                  4/38
A tree




Augeas turns configuration files into a tree
structure:
/etc/hosts -> /files/etc/hosts




             www.camptocamp.com /              5/38
Its branches and leaves



... and their parameters into branches and leaves:
augtool> print /files/etc/hosts
  /files/etc/hosts
  /files/etc/hosts/1
  /files/etc/hosts/1/ipaddr = "127.0.0.1"
  /files/etc/hosts/1/canonical = "localhost"




             www.camptocamp.com /               6/38
Augeas provides many stock parsers

They are called lenses:
Access             Cron                Host_Conf
Aliases            Crypttab            Hostname
Anacron            debctrl             Hosts_Access
Approx             Desktop             IniFile
AptConf            Dhcpd               Inputrc
Automaster         Dpkg                Iptables
Automounter        Exports             Kdump
BackupPCHosts      FAI_DiskConfig      Keepalived
cgconfig           Fonts               Keepalived
cgrules            Fuse                Login_defs
Channels           Grub                Mke2fs
...




                www.camptocamp.com /                  7/38
... as well as generic lenses




available to build new parsers:
Build        Sep                  Simplelines
IniFile      Shellvars            Simplevars
Rx           Shellvars_list       Util




           www.camptocamp.com /                 8/38
augtool lets you inspect the tree
$ augtool

augtool> ls /
 augeas/ = (none)
 files/ = (none)

augtool> print /files/etc/passwd/root/
 /files/etc/passwd/root
 /files/etc/passwd/root/password = "x"
 /files/etc/passwd/root/uid = "0"
 /files/etc/passwd/root/gid = "0"
 /files/etc/passwd/root/name = "root"
 /files/etc/passwd/root/home = "/root"
 /files/etc/passwd/root/shell = "/bin/bash"




             www.camptocamp.com /             9/38
The tree can be queried using XPath


augtool> print /files/etc/passwd/*[uid='0'][1]
 /files/etc/passwd/root
 /files/etc/passwd/root/password = "x"
 /files/etc/passwd/root/uid = "0"
 /files/etc/passwd/root/gid = "0"
 /files/etc/passwd/root/name = "root"
 /files/etc/passwd/root/home = "/root"
 /files/etc/passwd/root/shell = "/bin/bash"




             www.camptocamp.com /                10/38
But also modified
$ getent passwd root
root:x:0:0:root:/root:/bin/bash

$ augtool

augtool> set /files/etc/passwd/*[uid='0']/shell /bin/sh
augtool> match /files/etc/passwd/*[uid='0']/shell
/files/etc/passwd/root/shell = "/bin/sh"
augtool> save
Saved 1 file(s)
augtool> exit

$ getent passwd root
root:x:0:0:root:/root:/bin/sh




             www.camptocamp.com /                         11/38
Puppet has a native provider


augeas {'export foo':
    context => '/files/etc/exports',
    changes => [
        "set dir[. = '/foo'] /foo",
        "set dir[. = '/foo']/client weeble",
        "set dir[. = '/foo']/client/option[1] ro",
        "set dir[. = '/foo']/client/option[2] all_squash",
    ],
}




             www.camptocamp.com /                            12/38
It is better to wrap things up

define kmod::generic(
  $type, $module, $ensure=present,
  $command='', $file='/etc/modprobe.d/modprobe.conf'
) {
  augeas {"${type} module ${module}":
    context => "/files${file}",
    changes => [
       "set ${type}[. = '${module}'] ${module}",
       "set ${type}[. = '${module}']/command '${command}'",
    ],
  }
}




              www.camptocamp.com /                            13/38
mcollective has an agent

$ mco augeas match /files/etc/passwd/rpinson/shell

 * [ ======================================> ] 196 / 196

...
wrk1
saja-map-dev
     /files/etc/passwd/rpinson/shell = /bin/bash
wrk3
wrk4
     /files/etc/passwd/rpinson/shell = /bin/bash
...




              www.camptocamp.com /                         14/38
... and uses it for discovery




$ mco find -S "augeas_match(/files/etc/passwd/rip).size = 0"




             www.camptocamp.com /                              15/38
Bindings include Perl, Python, Java,
       PHP, Haskell, Ruby...

require 'augeas'
aug = Augeas.open
if aug.match('/augeas/load'+lens).length > 0
    aug.set('/augeas/load/'+lens+'incl[last()+1]', path)
else
    aug.set('/augeas/load/'+lens+'/lens', lens+'.lns')
end
                              (From the mcollective agent)




              www.camptocamp.com /                           16/38
The Ruby bindings can be used in Facter
Facter.add(:augeasversion) do
  setcode do
    begin
      require 'augeas'
      aug = Augeas::open('/', nil, Augeas::NO_MODL_AUTOLOAD)
      ver = aug.get('/augeas/version')
      aug.close
      ver
    rescue Exception
      Facter.debug('ruby-augeas not available')
    end
  end
end
                            (From the augeasversion fact)




             www.camptocamp.com /                              17/38
Or to write native types

def ip
    aug = nil
    path = "/files#{self.class.file(resource)}"
    begin
       aug = self.class.augopen(resource)
       aug.get("#{path}/*[canonical =
          '#{resource[:name]}']/ipaddr")
    ensure
       aug.close if aug
    end
end
              (See https://github.com/domcleal/augeasproviders)




             www.camptocamp.com /                                 18/38
The case of sshd_config
Custom type:
define ssh::config::sshd ($ensure='present', $value='') {

    case $ensure {
      'present': { $changes = "set ${name} ${value}" }

        'absent': { $changes = "rm ${name}" }

        'default': { fail("Wrong value for ensure: ${ensure}") }
    }

    augeas {"Set ${name} in /etc/ssh/sshd_config":
      context => '/files/etc/ssh/sshd_config',
      changes => $changes,
    }
}



                 www.camptocamp.com /                              19/38
Using the custom type for sshd_config




ssh::config::sshd {'PasswordAuthenticator':
  value => 'yes',
}




             www.camptocamp.com /             20/38
The problem with sshd_config


Match groups:
Match Host example.com
  PermitRootLogin no

=> Not possible with ssh::config::sshd, requires
insertions and looping through the configuration
parameters.




             www.camptocamp.com /             21/38
A native provider for sshd_config (1)
The type:
Puppet::Type.newtype(:sshd_config) do
  ensurable

  newparam(:name) do
    desc "The name of the entry."
    isnamevar
  end

  newproperty(:value) do
    desc "Entry value."
  end

  newproperty(:target) do
    desc "File target."
  end

  newparam(:condition) do
    desc "Match group condition for the entry."
  end
end


                 www.camptocamp.com /             22/38
A native provider for sshd_config (2)

The provider:
require 'augeas' if Puppet.features.augeas?

Puppet::Type.type(:sshd_config).provide(:augeas) do
  desc "Uses Augeas API to update an sshd_config parameter"

  def self.file(resource = nil)
    file = "/etc/ssh/sshd_config"
    file = resource[:target] if resource and resource[:target]
    file.chomp("/")
  end

  confine :true   => Puppet.features.augeas?
  confine :exists => file




                 www.camptocamp.com /                            23/38
A native provider for sshd_config (3)
def self.augopen(resource = nil)
 aug = nil
 file = file(resource)
 begin
   aug = Augeas.open(nil, nil, Augeas::NO_MODL_AUTOLOAD)
   aug.transform(
     :lens => "Sshd.lns",
     :name => "Sshd",
     :incl => file
   )
   aug.load!

    if aug.match("/files#{file}").empty?
      message = aug.get("/augeas/files#{file}/error/message")
      fail("Augeas didn't load #{file}: #{message}")
    end
  rescue
    aug.close if aug
    raise
  end
  aug
end


                 www.camptocamp.com /                           24/38
A native provider for sshd_config (4)
def self.instances
  aug = nil
  path = "/files#{file}"
  entry_path = self.class.entry_path(resource)
  begin
    resources = []
    aug = augopen
    aug.match(entry_path).each do |hpath|
      entry = {}
      entry[:name] = resource[:name]
      entry[:conditions] = Hash[*resource[:condition].split(' ').flatten(1)]
      entry[:value] = aug.get(hpath)

      resources << new(entry)
    end
    resources
  ensure
    aug.close if aug
  end
end



                 www.camptocamp.com /                                      25/38
A native provider for sshd_config (5)
def self.match_conditions(resource=nil)
  if resource[:condition]
    conditions = Hash[*resource[:condition].split(' ').flatten(1)]
    cond_keys = conditions.keys.length
    cond_str = "[count(Condition/*)=#{cond_keys}]"
    conditions.each { |k,v| cond_str += "[Condition/#{k}="#{v}"]" }
    cond_str
  else
    ""
  end
end

def self.entry_path(resource=nil)
  path = "/files#{self.file(resource)}"
  if resource[:condition]
    cond_str = self.match_conditions(resource)
    "#{path}/Match#{cond_str}/Settings/#{resource[:name]}"
  else
    "#{path}/#{resource[:name]}"
  end
end



                 www.camptocamp.com /                                   26/38
A native provider for sshd_config (6)

def self.match_exists?(resource=nil)
  aug = nil
  path = "/files#{self.file(resource)}"
  begin
    aug = self.augopen(resource)
    if resource[:condition]
      cond_str = self.match_conditions(resource)
    else
      false
    end
    not aug.match("#{path}/Match#{cond_str}").empty?
  ensure
    aug.close if aug
  end
end




                 www.camptocamp.com /                  27/38
A native provider for sshd_config (7)
def exists?
  aug = nil
  entry_path = self.class.entry_path(resource)
  begin
    aug = self.class.augopen(resource)
    not aug.match(entry_path).empty?
  ensure
    aug.close if aug
  end
end

def self.create_match(resource=nil, aug=nil)
  path = "/files#{self.file(resource)}"
  begin
    aug.insert("#{path}/*[last()]", "Match", false)
    conditions = Hash[*resource[:condition].split(' ').flatten(1)]
    conditions.each do |k,v|
      aug.set("#{path}/Match[last()]/Condition/#{k}", v)
    end
    aug
  end
end


                 www.camptocamp.com /                                28/38
A native provider for sshd_config (8)
def create
  aug = nil
  path = "/files#{self.class.file(resource)}"
  entry_path = self.class.entry_path(resource)
  begin
    aug = self.class.augopen(resource)
    if resource[:condition]
      unless self.class.match_exists?(resource)
         aug = self.class.create_match(resource, aug)
      end
    else
      unless aug.match("#{path}/Match").empty?
         aug.insert("#{path}/Match[1]", resource[:name], true)
      end
    end
    aug.set(entry_path, resource[:value])
    aug.save!
  ensure
    aug.close if aug
  end
end



                 www.camptocamp.com /                            29/38
A native provider for sshd_config (9)
def destroy
  aug = nil
  path = "/files#{self.class.file(resource)}"
  begin
    aug = self.class.augopen(resource)
    entry_path = self.class.entry_path(resource)
    aug.rm(entry_path)
    aug.rm("#{path}/Match[count(Settings/*)=0]")
    aug.save!
  ensure
    aug.close if aug
  end
end

def target
  self.class.file(resource)
end




                 www.camptocamp.com /              30/38
A native provider for sshd_config (10)


def value
  aug = nil
  path = "/files#{self.class.file(resource)}"
  begin
    aug = self.class.augopen(resource)
    entry_path = self.class.entry_path(resource)
    aug.get(entry_path)
  ensure
    aug.close if aug
  end
end




                 www.camptocamp.com /              31/38
A native provider for sshd_config (11)


def value=(thevalue)
  aug = nil
  path = "/files#{self.class.file(resource)}"
  begin
    aug = self.class.augopen(resource)
    entry_path = self.class.entry_path(resource)
    aug.set(entry_path, thevalue)
    aug.save!
  ensure
    aug.close if aug
  end
end




                 www.camptocamp.com /              32/38
Using the native provider for
        sshd_config


sshd_config   {'PermitRootLogin':
  ensure      => present,
  condition   => 'Host example.com',
  value       => 'yes',
}




               www.camptocamp.com /    33/38
Errors are reported in the /augeas tree


augtool> print /augeas//error
 /augeas/files/etc/mke2fs.conf/error = "parse_failed"
 /augeas/files/etc/mke2fs.conf/error/pos = "82"
 /augeas/files/etc/mke2fs.conf/error/line = "3"
 /augeas/files/etc/mke2fs.conf/error/char = "0"
 /augeas/files/etc/mke2fs.conf/error/lens = 
    "/usr/share/augeas/lenses/dist/mke2fs.aug:132.10-.49:"
 /augeas/files/etc/mke2fs.conf/error/message = 
    "Get did not match entire input"




             www.camptocamp.com /                            34/38
Other projects using Augeas


●   libvirt
●   rpm
●   Nut
●   guestfs
●   ZYpp
●   Config::Model
●   Augeas::Validator



            www.camptocamp.com /   35/38
Future projects
●   more API calls
●   improved XPath syntax
●   more lenses
●   more native providers
●   DBUS provider
●   content validation in Puppet (validator)
●   integration in package managers
●   finish the Augeas book
●   ...
●   your idea/project here...

            www.camptocamp.com /               36/38
Questions?




              http://augeas.net
         augeas-devel@redhat.com
            freenode: #augeas




       www.camptocamp.com /        37/38
Augeas @RMLL 2012

Weitere ähnliche Inhalte

Was ist angesagt?

Auto-loading of Drupal CCK Nodes
Auto-loading of Drupal CCK NodesAuto-loading of Drupal CCK Nodes
Auto-loading of Drupal CCK Nodes
nihiliad
 
AST - the only true tool for building JavaScript
AST - the only true tool for building JavaScriptAST - the only true tool for building JavaScript
AST - the only true tool for building JavaScript
Ingvar Stepanyan
 

Was ist angesagt? (20)

Groovy on the Shell
Groovy on the ShellGroovy on the Shell
Groovy on the Shell
 
Puppet @ Seat
Puppet @ SeatPuppet @ Seat
Puppet @ Seat
 
Spring data iii
Spring data iiiSpring data iii
Spring data iii
 
Stanford Hackathon - Puppet Modules
Stanford Hackathon - Puppet ModulesStanford Hackathon - Puppet Modules
Stanford Hackathon - Puppet Modules
 
C99[2]
C99[2]C99[2]
C99[2]
 
PL/Perl - New Features in PostgreSQL 9.0
PL/Perl - New Features in PostgreSQL 9.0PL/Perl - New Features in PostgreSQL 9.0
PL/Perl - New Features in PostgreSQL 9.0
 
dotCloud and go
dotCloud and godotCloud and go
dotCloud and go
 
Memory Manglement in Raku
Memory Manglement in RakuMemory Manglement in Raku
Memory Manglement in Raku
 
Auto-loading of Drupal CCK Nodes
Auto-loading of Drupal CCK NodesAuto-loading of Drupal CCK Nodes
Auto-loading of Drupal CCK Nodes
 
Nubilus Perl
Nubilus PerlNubilus Perl
Nubilus Perl
 
BSDM with BASH: Command Interpolation
BSDM with BASH: Command InterpolationBSDM with BASH: Command Interpolation
BSDM with BASH: Command Interpolation
 
PuppetCamp Ghent - What Not to Do with Puppet
PuppetCamp Ghent - What Not to Do with PuppetPuppetCamp Ghent - What Not to Do with Puppet
PuppetCamp Ghent - What Not to Do with Puppet
 
Puppet: What _not_ to do
Puppet: What _not_ to doPuppet: What _not_ to do
Puppet: What _not_ to do
 
Codeigniter4の比較と検証
Codeigniter4の比較と検証Codeigniter4の比較と検証
Codeigniter4の比較と検証
 
AST Rewriting Using recast and esprima
AST Rewriting Using recast and esprimaAST Rewriting Using recast and esprima
AST Rewriting Using recast and esprima
 
Perl at SkyCon'12
Perl at SkyCon'12Perl at SkyCon'12
Perl at SkyCon'12
 
Puppet Camp Chicago 2014: Smoothing Troubles With Custom Types and Providers ...
Puppet Camp Chicago 2014: Smoothing Troubles With Custom Types and Providers ...Puppet Camp Chicago 2014: Smoothing Troubles With Custom Types and Providers ...
Puppet Camp Chicago 2014: Smoothing Troubles With Custom Types and Providers ...
 
Perl Web Client
Perl Web ClientPerl Web Client
Perl Web Client
 
BASH Variables Part 1: Basic Interpolation
BASH Variables Part 1: Basic InterpolationBASH Variables Part 1: Basic Interpolation
BASH Variables Part 1: Basic Interpolation
 
AST - the only true tool for building JavaScript
AST - the only true tool for building JavaScriptAST - the only true tool for building JavaScript
AST - the only true tool for building JavaScript
 

Ähnlich wie Augeas @RMLL 2012

On secure application of PHP wrappers
On secure application  of PHP wrappersOn secure application  of PHP wrappers
On secure application of PHP wrappers
Positive Hack Days
 
4069180 Caching Performance Lessons From Facebook
4069180 Caching Performance Lessons From Facebook4069180 Caching Performance Lessons From Facebook
4069180 Caching Performance Lessons From Facebook
guoqing75
 

Ähnlich wie Augeas @RMLL 2012 (20)

On secure application of PHP wrappers
On secure application  of PHP wrappersOn secure application  of PHP wrappers
On secure application of PHP wrappers
 
EC2
EC2EC2
EC2
 
Writing and Publishing Puppet Modules - PuppetConf 2014
Writing and Publishing Puppet Modules - PuppetConf 2014Writing and Publishing Puppet Modules - PuppetConf 2014
Writing and Publishing Puppet Modules - PuppetConf 2014
 
ELK: a log management framework
ELK: a log management frameworkELK: a log management framework
ELK: a log management framework
 
Vagrant for real
Vagrant for realVagrant for real
Vagrant for real
 
All I Need to Know I Learned by Writing My Own Web Framework
All I Need to Know I Learned by Writing My Own Web FrameworkAll I Need to Know I Learned by Writing My Own Web Framework
All I Need to Know I Learned by Writing My Own Web Framework
 
Does your configuration code smell?
Does your configuration code smell?Does your configuration code smell?
Does your configuration code smell?
 
KubeCon EU 2016: Custom Volume Plugins
KubeCon EU 2016: Custom Volume PluginsKubeCon EU 2016: Custom Volume Plugins
KubeCon EU 2016: Custom Volume Plugins
 
Golang Project Layout and Practice
Golang Project Layout and PracticeGolang Project Layout and Practice
Golang Project Layout and Practice
 
Vagrant for real codemotion (moar tips! ;-))
Vagrant for real codemotion (moar tips! ;-))Vagrant for real codemotion (moar tips! ;-))
Vagrant for real codemotion (moar tips! ;-))
 
Terraform in deployment pipeline
Terraform in deployment pipelineTerraform in deployment pipeline
Terraform in deployment pipeline
 
Augeas
AugeasAugeas
Augeas
 
Puppet: Eclipsecon ALM 2013
Puppet: Eclipsecon ALM 2013Puppet: Eclipsecon ALM 2013
Puppet: Eclipsecon ALM 2013
 
Vagrant for real
Vagrant for realVagrant for real
Vagrant for real
 
Vagrant for real (codemotion rome 2016)
Vagrant for real (codemotion rome 2016)Vagrant for real (codemotion rome 2016)
Vagrant for real (codemotion rome 2016)
 
Puppet and the HashiStack
Puppet and the HashiStackPuppet and the HashiStack
Puppet and the HashiStack
 
PuppetConf 2016: The Challenges with Container Configuration – David Lutterko...
PuppetConf 2016: The Challenges with Container Configuration – David Lutterko...PuppetConf 2016: The Challenges with Container Configuration – David Lutterko...
PuppetConf 2016: The Challenges with Container Configuration – David Lutterko...
 
Challenges of container configuration
Challenges of container configurationChallenges of container configuration
Challenges of container configuration
 
eZ Publish Cluster Unleashed
eZ Publish Cluster UnleashedeZ Publish Cluster Unleashed
eZ Publish Cluster Unleashed
 
4069180 Caching Performance Lessons From Facebook
4069180 Caching Performance Lessons From Facebook4069180 Caching Performance Lessons From Facebook
4069180 Caching Performance Lessons From Facebook
 

Mehr von Raphaël PINSON

Cloud Native Bern 05.2023 — Zero Trust Visibility
Cloud Native Bern 05.2023 — Zero Trust VisibilityCloud Native Bern 05.2023 — Zero Trust Visibility
Cloud Native Bern 05.2023 — Zero Trust Visibility
Raphaël PINSON
 

Mehr von Raphaël PINSON (20)

Explore the World of Cilium, Tetragon & eBPF
Explore the World of Cilium, Tetragon & eBPFExplore the World of Cilium, Tetragon & eBPF
Explore the World of Cilium, Tetragon & eBPF
 
Cfgmgmtcamp 2024 — eBPF-based Security Observability & Runtime Enforcement wi...
Cfgmgmtcamp 2024 — eBPF-based Security Observability & Runtime Enforcement wi...Cfgmgmtcamp 2024 — eBPF-based Security Observability & Runtime Enforcement wi...
Cfgmgmtcamp 2024 — eBPF-based Security Observability & Runtime Enforcement wi...
 
ContainerDays Hamburg 2023 — Cilium Workshop.pdf
ContainerDays Hamburg 2023 — Cilium Workshop.pdfContainerDays Hamburg 2023 — Cilium Workshop.pdf
ContainerDays Hamburg 2023 — Cilium Workshop.pdf
 
KCD Zurich 2023 — Bridge Dev & Ops with eBPF.pdf
KCD Zurich 2023 — Bridge Dev & Ops with eBPF.pdfKCD Zurich 2023 — Bridge Dev & Ops with eBPF.pdf
KCD Zurich 2023 — Bridge Dev & Ops with eBPF.pdf
 
Cloud Native Bern 05.2023 — Zero Trust Visibility
Cloud Native Bern 05.2023 — Zero Trust VisibilityCloud Native Bern 05.2023 — Zero Trust Visibility
Cloud Native Bern 05.2023 — Zero Trust Visibility
 
DevOpsDays Zurich 2023 — Bridging Dev and Ops with eBPF: Extending Observabil...
DevOpsDays Zurich 2023 — Bridging Dev and Ops with eBPF: Extending Observabil...DevOpsDays Zurich 2023 — Bridging Dev and Ops with eBPF: Extending Observabil...
DevOpsDays Zurich 2023 — Bridging Dev and Ops with eBPF: Extending Observabil...
 
Révolution eBPF - un noyau dynamique
Révolution eBPF - un noyau dynamiqueRévolution eBPF - un noyau dynamique
Révolution eBPF - un noyau dynamique
 
Cfgmgmtcamp 2023 — eBPF Superpowers
Cfgmgmtcamp 2023 — eBPF SuperpowersCfgmgmtcamp 2023 — eBPF Superpowers
Cfgmgmtcamp 2023 — eBPF Superpowers
 
Cloud Native Networking & Security with Cilium & eBPF
Cloud Native Networking & Security with Cilium & eBPFCloud Native Networking & Security with Cilium & eBPF
Cloud Native Networking & Security with Cilium & eBPF
 
2022 DevOpsDays Geneva — The Hare and the Tortoise.pdf
2022 DevOpsDays Geneva — The Hare and the Tortoise.pdf2022 DevOpsDays Geneva — The Hare and the Tortoise.pdf
2022 DevOpsDays Geneva — The Hare and the Tortoise.pdf
 
SKS in git ops mode
SKS in git ops modeSKS in git ops mode
SKS in git ops mode
 
The Hare and the Tortoise: Open Source, Standards & Technological Debt
The Hare and the Tortoise: Open Source, Standards & Technological DebtThe Hare and the Tortoise: Open Source, Standards & Technological Debt
The Hare and the Tortoise: Open Source, Standards & Technological Debt
 
Devops stack
Devops stackDevops stack
Devops stack
 
YAML Engineering: why we need a new paradigm
YAML Engineering: why we need a new paradigmYAML Engineering: why we need a new paradigm
YAML Engineering: why we need a new paradigm
 
Container Security: a toolchain for automatic image rebuilds
Container Security: a toolchain for automatic image rebuildsContainer Security: a toolchain for automatic image rebuilds
Container Security: a toolchain for automatic image rebuilds
 
K9s - Kubernetes CLI To Manage Your Clusters In Style
K9s - Kubernetes CLI To Manage Your Clusters In StyleK9s - Kubernetes CLI To Manage Your Clusters In Style
K9s - Kubernetes CLI To Manage Your Clusters In Style
 
Argocd up and running
Argocd up and runningArgocd up and running
Argocd up and running
 
Bivac - Container Volumes Backup
Bivac - Container Volumes BackupBivac - Container Volumes Backup
Bivac - Container Volumes Backup
 
Automating Puppet Certificates Renewal
Automating Puppet Certificates RenewalAutomating Puppet Certificates Renewal
Automating Puppet Certificates Renewal
 
Running the Puppet Stack in Containers
Running the Puppet Stack in ContainersRunning the Puppet Stack in Containers
Running the Puppet Stack in Containers
 

Kürzlich hochgeladen

Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
vu2urc
 

Kürzlich hochgeladen (20)

Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
Developing An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilDeveloping An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of Brazil
 
Advantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessAdvantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your Business
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
HTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesHTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation Strategies
 
Tech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdfTech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdf
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 

Augeas @RMLL 2012

  • 1. Configuration surgery with Augeas Raphaël Pinson @raphink LSM 2012, Geneva 2012-07-11 https://github.com/raphink/augeas-talks/
  • 2. Tired of ugly sed and awk one liners? or of using tons of different parsing libraries or common::line tricks? www.camptocamp.com / 2/38
  • 3. Become a configuration surgeon with Augeas www.camptocamp.com / 3/38
  • 4. What is the need? ● A lot of different syntaxes ● Securely editing configuration files with a unified API www.camptocamp.com / 4/38
  • 5. A tree Augeas turns configuration files into a tree structure: /etc/hosts -> /files/etc/hosts www.camptocamp.com / 5/38
  • 6. Its branches and leaves ... and their parameters into branches and leaves: augtool> print /files/etc/hosts /files/etc/hosts /files/etc/hosts/1 /files/etc/hosts/1/ipaddr = "127.0.0.1" /files/etc/hosts/1/canonical = "localhost" www.camptocamp.com / 6/38
  • 7. Augeas provides many stock parsers They are called lenses: Access Cron Host_Conf Aliases Crypttab Hostname Anacron debctrl Hosts_Access Approx Desktop IniFile AptConf Dhcpd Inputrc Automaster Dpkg Iptables Automounter Exports Kdump BackupPCHosts FAI_DiskConfig Keepalived cgconfig Fonts Keepalived cgrules Fuse Login_defs Channels Grub Mke2fs ... www.camptocamp.com / 7/38
  • 8. ... as well as generic lenses available to build new parsers: Build Sep Simplelines IniFile Shellvars Simplevars Rx Shellvars_list Util www.camptocamp.com / 8/38
  • 9. augtool lets you inspect the tree $ augtool augtool> ls / augeas/ = (none) files/ = (none) augtool> print /files/etc/passwd/root/ /files/etc/passwd/root /files/etc/passwd/root/password = "x" /files/etc/passwd/root/uid = "0" /files/etc/passwd/root/gid = "0" /files/etc/passwd/root/name = "root" /files/etc/passwd/root/home = "/root" /files/etc/passwd/root/shell = "/bin/bash" www.camptocamp.com / 9/38
  • 10. The tree can be queried using XPath augtool> print /files/etc/passwd/*[uid='0'][1] /files/etc/passwd/root /files/etc/passwd/root/password = "x" /files/etc/passwd/root/uid = "0" /files/etc/passwd/root/gid = "0" /files/etc/passwd/root/name = "root" /files/etc/passwd/root/home = "/root" /files/etc/passwd/root/shell = "/bin/bash" www.camptocamp.com / 10/38
  • 11. But also modified $ getent passwd root root:x:0:0:root:/root:/bin/bash $ augtool augtool> set /files/etc/passwd/*[uid='0']/shell /bin/sh augtool> match /files/etc/passwd/*[uid='0']/shell /files/etc/passwd/root/shell = "/bin/sh" augtool> save Saved 1 file(s) augtool> exit $ getent passwd root root:x:0:0:root:/root:/bin/sh www.camptocamp.com / 11/38
  • 12. Puppet has a native provider augeas {'export foo': context => '/files/etc/exports', changes => [ "set dir[. = '/foo'] /foo", "set dir[. = '/foo']/client weeble", "set dir[. = '/foo']/client/option[1] ro", "set dir[. = '/foo']/client/option[2] all_squash", ], } www.camptocamp.com / 12/38
  • 13. It is better to wrap things up define kmod::generic( $type, $module, $ensure=present, $command='', $file='/etc/modprobe.d/modprobe.conf' ) { augeas {"${type} module ${module}": context => "/files${file}", changes => [ "set ${type}[. = '${module}'] ${module}", "set ${type}[. = '${module}']/command '${command}'", ], } } www.camptocamp.com / 13/38
  • 14. mcollective has an agent $ mco augeas match /files/etc/passwd/rpinson/shell * [ ======================================> ] 196 / 196 ... wrk1 saja-map-dev /files/etc/passwd/rpinson/shell = /bin/bash wrk3 wrk4 /files/etc/passwd/rpinson/shell = /bin/bash ... www.camptocamp.com / 14/38
  • 15. ... and uses it for discovery $ mco find -S "augeas_match(/files/etc/passwd/rip).size = 0" www.camptocamp.com / 15/38
  • 16. Bindings include Perl, Python, Java, PHP, Haskell, Ruby... require 'augeas' aug = Augeas.open if aug.match('/augeas/load'+lens).length > 0 aug.set('/augeas/load/'+lens+'incl[last()+1]', path) else aug.set('/augeas/load/'+lens+'/lens', lens+'.lns') end (From the mcollective agent) www.camptocamp.com / 16/38
  • 17. The Ruby bindings can be used in Facter Facter.add(:augeasversion) do setcode do begin require 'augeas' aug = Augeas::open('/', nil, Augeas::NO_MODL_AUTOLOAD) ver = aug.get('/augeas/version') aug.close ver rescue Exception Facter.debug('ruby-augeas not available') end end end (From the augeasversion fact) www.camptocamp.com / 17/38
  • 18. Or to write native types def ip aug = nil path = "/files#{self.class.file(resource)}" begin aug = self.class.augopen(resource) aug.get("#{path}/*[canonical = '#{resource[:name]}']/ipaddr") ensure aug.close if aug end end (See https://github.com/domcleal/augeasproviders) www.camptocamp.com / 18/38
  • 19. The case of sshd_config Custom type: define ssh::config::sshd ($ensure='present', $value='') { case $ensure { 'present': { $changes = "set ${name} ${value}" } 'absent': { $changes = "rm ${name}" } 'default': { fail("Wrong value for ensure: ${ensure}") } } augeas {"Set ${name} in /etc/ssh/sshd_config": context => '/files/etc/ssh/sshd_config', changes => $changes, } } www.camptocamp.com / 19/38
  • 20. Using the custom type for sshd_config ssh::config::sshd {'PasswordAuthenticator': value => 'yes', } www.camptocamp.com / 20/38
  • 21. The problem with sshd_config Match groups: Match Host example.com PermitRootLogin no => Not possible with ssh::config::sshd, requires insertions and looping through the configuration parameters. www.camptocamp.com / 21/38
  • 22. A native provider for sshd_config (1) The type: Puppet::Type.newtype(:sshd_config) do ensurable newparam(:name) do desc "The name of the entry." isnamevar end newproperty(:value) do desc "Entry value." end newproperty(:target) do desc "File target." end newparam(:condition) do desc "Match group condition for the entry." end end www.camptocamp.com / 22/38
  • 23. A native provider for sshd_config (2) The provider: require 'augeas' if Puppet.features.augeas? Puppet::Type.type(:sshd_config).provide(:augeas) do desc "Uses Augeas API to update an sshd_config parameter" def self.file(resource = nil) file = "/etc/ssh/sshd_config" file = resource[:target] if resource and resource[:target] file.chomp("/") end confine :true => Puppet.features.augeas? confine :exists => file www.camptocamp.com / 23/38
  • 24. A native provider for sshd_config (3) def self.augopen(resource = nil) aug = nil file = file(resource) begin aug = Augeas.open(nil, nil, Augeas::NO_MODL_AUTOLOAD) aug.transform( :lens => "Sshd.lns", :name => "Sshd", :incl => file ) aug.load! if aug.match("/files#{file}").empty? message = aug.get("/augeas/files#{file}/error/message") fail("Augeas didn't load #{file}: #{message}") end rescue aug.close if aug raise end aug end www.camptocamp.com / 24/38
  • 25. A native provider for sshd_config (4) def self.instances aug = nil path = "/files#{file}" entry_path = self.class.entry_path(resource) begin resources = [] aug = augopen aug.match(entry_path).each do |hpath| entry = {} entry[:name] = resource[:name] entry[:conditions] = Hash[*resource[:condition].split(' ').flatten(1)] entry[:value] = aug.get(hpath) resources << new(entry) end resources ensure aug.close if aug end end www.camptocamp.com / 25/38
  • 26. A native provider for sshd_config (5) def self.match_conditions(resource=nil) if resource[:condition] conditions = Hash[*resource[:condition].split(' ').flatten(1)] cond_keys = conditions.keys.length cond_str = "[count(Condition/*)=#{cond_keys}]" conditions.each { |k,v| cond_str += "[Condition/#{k}="#{v}"]" } cond_str else "" end end def self.entry_path(resource=nil) path = "/files#{self.file(resource)}" if resource[:condition] cond_str = self.match_conditions(resource) "#{path}/Match#{cond_str}/Settings/#{resource[:name]}" else "#{path}/#{resource[:name]}" end end www.camptocamp.com / 26/38
  • 27. A native provider for sshd_config (6) def self.match_exists?(resource=nil) aug = nil path = "/files#{self.file(resource)}" begin aug = self.augopen(resource) if resource[:condition] cond_str = self.match_conditions(resource) else false end not aug.match("#{path}/Match#{cond_str}").empty? ensure aug.close if aug end end www.camptocamp.com / 27/38
  • 28. A native provider for sshd_config (7) def exists? aug = nil entry_path = self.class.entry_path(resource) begin aug = self.class.augopen(resource) not aug.match(entry_path).empty? ensure aug.close if aug end end def self.create_match(resource=nil, aug=nil) path = "/files#{self.file(resource)}" begin aug.insert("#{path}/*[last()]", "Match", false) conditions = Hash[*resource[:condition].split(' ').flatten(1)] conditions.each do |k,v| aug.set("#{path}/Match[last()]/Condition/#{k}", v) end aug end end www.camptocamp.com / 28/38
  • 29. A native provider for sshd_config (8) def create aug = nil path = "/files#{self.class.file(resource)}" entry_path = self.class.entry_path(resource) begin aug = self.class.augopen(resource) if resource[:condition] unless self.class.match_exists?(resource) aug = self.class.create_match(resource, aug) end else unless aug.match("#{path}/Match").empty? aug.insert("#{path}/Match[1]", resource[:name], true) end end aug.set(entry_path, resource[:value]) aug.save! ensure aug.close if aug end end www.camptocamp.com / 29/38
  • 30. A native provider for sshd_config (9) def destroy aug = nil path = "/files#{self.class.file(resource)}" begin aug = self.class.augopen(resource) entry_path = self.class.entry_path(resource) aug.rm(entry_path) aug.rm("#{path}/Match[count(Settings/*)=0]") aug.save! ensure aug.close if aug end end def target self.class.file(resource) end www.camptocamp.com / 30/38
  • 31. A native provider for sshd_config (10) def value aug = nil path = "/files#{self.class.file(resource)}" begin aug = self.class.augopen(resource) entry_path = self.class.entry_path(resource) aug.get(entry_path) ensure aug.close if aug end end www.camptocamp.com / 31/38
  • 32. A native provider for sshd_config (11) def value=(thevalue) aug = nil path = "/files#{self.class.file(resource)}" begin aug = self.class.augopen(resource) entry_path = self.class.entry_path(resource) aug.set(entry_path, thevalue) aug.save! ensure aug.close if aug end end www.camptocamp.com / 32/38
  • 33. Using the native provider for sshd_config sshd_config {'PermitRootLogin': ensure => present, condition => 'Host example.com', value => 'yes', } www.camptocamp.com / 33/38
  • 34. Errors are reported in the /augeas tree augtool> print /augeas//error /augeas/files/etc/mke2fs.conf/error = "parse_failed" /augeas/files/etc/mke2fs.conf/error/pos = "82" /augeas/files/etc/mke2fs.conf/error/line = "3" /augeas/files/etc/mke2fs.conf/error/char = "0" /augeas/files/etc/mke2fs.conf/error/lens = "/usr/share/augeas/lenses/dist/mke2fs.aug:132.10-.49:" /augeas/files/etc/mke2fs.conf/error/message = "Get did not match entire input" www.camptocamp.com / 34/38
  • 35. Other projects using Augeas ● libvirt ● rpm ● Nut ● guestfs ● ZYpp ● Config::Model ● Augeas::Validator www.camptocamp.com / 35/38
  • 36. Future projects ● more API calls ● improved XPath syntax ● more lenses ● more native providers ● DBUS provider ● content validation in Puppet (validator) ● integration in package managers ● finish the Augeas book ● ... ● your idea/project here... www.camptocamp.com / 36/38
  • 37. Questions? http://augeas.net augeas-devel@redhat.com freenode: #augeas www.camptocamp.com / 37/38