Puppet Augeas
Version 9 (Andrei Pozolotin, 07/28/2010 03:33 pm)
| 1 | 1 | # Using Puppet with Augeas |
|
|---|---|---|---|
| 2 | 1 | ||
| 3 | 1 | [Augeas](http://augeas.net/index.html) is a lovely tool that treats |
|
| 4 | 1 | config files (well, anything really, but it's mostly about config |
|
| 5 | 1 | files) as trees of values. You then modify the tree as you like, |
|
| 6 | 1 | and write the file back. |
|
| 7 | 1 | ||
| 8 | 1 | This is basically the solution to the problem of dealing with |
|
| 9 | 1 | upstream configuration changes combined with local modifications: |
|
| 10 | 1 | you can allow the upstream changes through and then apply changes |
|
| 11 | 1 | with Augeas to the new version. |
|
| 12 | 1 | ||
| 13 | 1 | Assuming you want to work with Augeas, this is a description of how |
|
| 14 | 1 | to perform Augeas changes using Puppet. You'll need Puppet >= |
|
| 15 | 4 | Sami Haahtinen | 0.24.7 for this. The basic usage is [Type Reference](http://docs.reductivelabs.com/references/latest/type.html#augeas). |
| 16 | 1 | ||
| 17 | 1 | The somewhat more important, and unfortunately complicated, part is |
|
| 18 | 1 | figuring out what the tree for a file looks like so you can |
|
| 19 | 1 | manipulate it properly. The definition that Augeas uses to turn a |
|
| 20 | 1 | file into a tree is called a lens, and understanding the trees is |
|
| 21 | 1 | more difficult than it should be, because many lenses are not |
|
| 22 | 1 | documented sufficiently, or at all. The documentation for those |
|
| 23 | 1 | that are |
|
| 24 | 1 | [has its own surprisingly hard to find page](http://augeas.net/docs/references/lenses/index.html) |
|
| 25 | 1 | on the Augeas site. You can see what lenses are available by |
|
| 26 | 1 | looking in /usr/share/augeas/lenses/ (or |
|
| 27 | 1 | /usr/local/share/augeas/lenses/ , or possibly somewhere else, |
|
| 28 | 1 | depending on your setup). |
|
| 29 | 1 | ||
| 30 | 1 | You can also see which files Augeas has successfully parsed by |
|
| 31 | 1 | entering "ls /files/" in augtool and drilling down from there. If a |
|
| 32 | 1 | file hasn't been properly parsed by Augeas, it simply won't show |
|
| 33 | 1 | up. This could mean that the file has a syntax error, or it could |
|
| 34 | 1 | imply a failure in the lense itself. |
|
| 35 | 1 | ||
| 36 | 1 | Here's an example of how to determine the tree structure of a file, |
|
| 37 | 1 | in this case /etc/exports. |
|
| 38 | 1 | ||
| 39 | 1 | The easiest thing to do is to set up the file with some examples (I |
|
| 40 | 1 | pulled examples from the bottom of "man 5 exports") and see what |
|
| 41 | 1 | they look like: |
|
| 42 | 1 | ||
| 43 | 1 | $ augtool |
|
| 44 | 1 | augtool> ls /files/etc/exports/ |
|
| 45 | 1 | comment[1] = /etc/exports: the access control list for filesystems which may be exported |
|
| 46 | 1 | comment[2] = to NFS clients. See exports(5). |
|
| 47 | 1 | comment[3] = sample /etc/exports file |
|
| 48 | 1 | dir[1]/ = / |
|
| 49 | 1 | dir[2]/ = /projects |
|
| 50 | 1 | dir[3]/ = /usr |
|
| 51 | 1 | dir[4]/ = /home/joe |
|
| 52 | 1 | ||
| 53 | 1 | From here you can investigate the structure, like so: |
|
| 54 | 1 | ||
| 55 | 1 | augtool> ls /files/etc/exports/dir[1] |
|
| 56 | 1 | client[1]/ = master |
|
| 57 | 1 | client[2]/ = trusty |
|
| 58 | 1 | ||
| 59 | 1 | The corresponding line in the file is: |
|
| 60 | 1 | ||
| 61 | 1 | / master(rw) trusty(rw,no_root_squash) |
|
| 62 | 1 | ||
| 63 | 1 | Digging further: |
|
| 64 | 1 | ||
| 65 | 1 | augtool> ls /files/etc/exports/dir[1]/client[1] |
|
| 66 | 1 | option = rw |
|
| 67 | 1 | ||
| 68 | 1 | So, if you want to add a new entry, you'd do something like this: |
|
| 69 | 1 | ||
| 70 | 1 | augtool> set /files/etc/exports/dir[last()+1] /foo |
|
| 71 | 1 | augtool> set /files/etc/exports/dir[last()]/client weeble |
|
| 72 | 1 | augtool> set /files/etc/exports/dir[last()]/client/option[1] ro |
|
| 73 | 1 | augtool> set /files/etc/exports/dir[last()]/client/option[2] all_squash |
|
| 74 | 1 | augtool> save |
|
| 75 | 1 | Saved 1 file(s) |
|
| 76 | 1 | ||
| 77 | 1 | Which creates the line: |
|
| 78 | 1 | ||
| 79 | 1 | /foo weeble(ro,all_squash) |
|
| 80 | 1 | ||
| 81 | 1 | Now that you've played around in augtool, you can make changes |
|
| 82 | 1 | using Puppet: |
|
| 83 | 1 | ||
| 84 | 1 | augeas{ "export foo" : |
|
| 85 | 1 | context => "/files/etc/exports", |
|
| 86 | 1 | changes => [ |
|
| 87 | 1 | "set dir[last()+1] /foo", |
|
| 88 | 1 | "set dir[last()]/client weeble", |
|
| 89 | 1 | "set dir[last()]/client/option[1] ro", |
|
| 90 | 1 | "set dir[last()]/client/option[2] all_squash", |
|
| 91 | 1 | ], |
|
| 92 | 1 | } |
|
| 93 | 1 | ||
| 94 | 1 | This adds the line described above. |
|
| 95 | 5 | Patrick Mohr | |
| 96 | 5 | Patrick Mohr | |
| 97 | 5 | Patrick Mohr | **For information on quotes and spaces, see** http://groups.google.com/group/puppet-users/browse_thread/thread/b4730f74589433e5 |
| 98 | 6 | Andrei Pozolotin | |
| 99 | 6 | Andrei Pozolotin | |
| 100 | 6 | Andrei Pozolotin | # Working Examples |
| 101 | 6 | Andrei Pozolotin | |
| 102 | 9 | Andrei Pozolotin | test it like this: |
| 103 | 9 | Andrei Pozolotin | |
| 104 | 9 | Andrei Pozolotin | sudo puppet apply --verbose --debug --trace --summarize test.pp |
| 105 | 9 | Andrei Pozolotin | |
| 106 | 7 | Andrei Pozolotin | ## /etc/sysctl.conf |
| 107 | 6 | Andrei Pozolotin | |
| 108 | 7 | Andrei Pozolotin | works on puppet 2.6.1; fedora 12; ubuntu 10.04 |
| 109 | 6 | Andrei Pozolotin | |
| 110 | 6 | Andrei Pozolotin | class sysctl { |
| 111 | 6 | Andrei Pozolotin | |
| 112 | 6 | Andrei Pozolotin | # nested class/define |
| 113 | 6 | Andrei Pozolotin | define conf ( $value ) { |
| 114 | 6 | Andrei Pozolotin | |
| 115 | 6 | Andrei Pozolotin | # $name is provided by define invocation |
| 116 | 6 | Andrei Pozolotin | |
| 117 | 6 | Andrei Pozolotin | # guid of this entry |
| 118 | 6 | Andrei Pozolotin | $key = $name |
| 119 | 6 | Andrei Pozolotin | |
| 120 | 6 | Andrei Pozolotin | $context = "/files/etc/sysctl.conf" |
| 121 | 6 | Andrei Pozolotin | |
| 122 | 6 | Andrei Pozolotin | augeas { "sysctl_conf/$key": |
| 123 | 6 | Andrei Pozolotin | context => "$context", |
| 124 | 6 | Andrei Pozolotin | onlyif => "get $key != $value", |
| 125 | 6 | Andrei Pozolotin | changes => "set $key $value", |
| 126 | 6 | Andrei Pozolotin | notify => Exec["sysctl"], |
| 127 | 6 | Andrei Pozolotin | } |
| 128 | 6 | Andrei Pozolotin | |
| 129 | 6 | Andrei Pozolotin | } |
| 130 | 6 | Andrei Pozolotin | |
| 131 | 6 | Andrei Pozolotin | file { "sysctl_conf": |
| 132 | 6 | Andrei Pozolotin | name => $operatingsystem ? { |
| 133 | 6 | Andrei Pozolotin | default => "/etc/sysctl.conf", |
| 134 | 6 | Andrei Pozolotin | }, |
| 135 | 6 | Andrei Pozolotin | } |
| 136 | 6 | Andrei Pozolotin | |
| 137 | 6 | Andrei Pozolotin | exec { "sysctl -p": |
| 138 | 6 | Andrei Pozolotin | alias => "sysctl", |
| 139 | 6 | Andrei Pozolotin | refreshonly => true, |
| 140 | 6 | Andrei Pozolotin | subscribe => File["sysctl_conf"], |
| 141 | 6 | Andrei Pozolotin | } |
| 142 | 6 | Andrei Pozolotin | |
| 143 | 6 | Andrei Pozolotin | } |
| 144 | 6 | Andrei Pozolotin | |
| 145 | 8 | Andrei Pozolotin | use case: |
| 146 | 7 | Andrei Pozolotin | |
| 147 | 8 | Andrei Pozolotin | include sysctl |
| 148 | 8 | Andrei Pozolotin | |
| 149 | 8 | Andrei Pozolotin | sysctl::conf { |
| 150 | 8 | Andrei Pozolotin | |
| 151 | 8 | Andrei Pozolotin | # prevent java heap swap |
| 152 | 8 | Andrei Pozolotin | "vm.swappiness": value => 0; |
| 153 | 8 | Andrei Pozolotin | |
| 154 | 8 | Andrei Pozolotin | # increase max read/write buffer size that can be applied via setsockopt() |
| 155 | 8 | Andrei Pozolotin | "net.core.rmem_max": value => 16777216; |
| 156 | 8 | Andrei Pozolotin | "net.core.wmem_max": value => 16777216; |
| 157 | 8 | Andrei Pozolotin | |
| 158 | 8 | Andrei Pozolotin | } |
| 159 | 8 | Andrei Pozolotin | |
| 160 | 8 | Andrei Pozolotin | |
| 161 | 7 | Andrei Pozolotin | ## /etc/security/limits.conf |
| 162 | 7 | Andrei Pozolotin | |
| 163 | 7 | Andrei Pozolotin | works on puppet 2.6.1; fedora 12; ubuntu 10.04 |
| 164 | 7 | Andrei Pozolotin | |
| 165 | 7 | Andrei Pozolotin | class limits { |
| 166 | 7 | Andrei Pozolotin | |
| 167 | 7 | Andrei Pozolotin | # nested class/define |
| 168 | 7 | Andrei Pozolotin | define conf ( |
| 169 | 7 | Andrei Pozolotin | $domain = "root", |
| 170 | 7 | Andrei Pozolotin | $type = "soft", |
| 171 | 7 | Andrei Pozolotin | $item = "nofile", |
| 172 | 7 | Andrei Pozolotin | $value = "10000" |
| 173 | 7 | Andrei Pozolotin | ) { |
| 174 | 7 | Andrei Pozolotin | |
| 175 | 7 | Andrei Pozolotin | # guid of this entry |
| 176 | 7 | Andrei Pozolotin | $key = "$domain/$type/$item" |
| 177 | 7 | Andrei Pozolotin | |
| 178 | 7 | Andrei Pozolotin | # augtool> match /files/etc/security/limits.conf/domain[.="root"][./type="hard" and ./item="nofile" and ./value="10000"] |
| 179 | 7 | Andrei Pozolotin | |
| 180 | 7 | Andrei Pozolotin | $context = "/files/etc/security/limits.conf" |
| 181 | 7 | Andrei Pozolotin | |
| 182 | 7 | Andrei Pozolotin | $path_list = "domain[.=\"$domain\"][./type=\"$type\" and ./item=\"$item\"]" |
| 183 | 7 | Andrei Pozolotin | $path_exact = "domain[.=\"$domain\"][./type=\"$type\" and ./item=\"$item\" and ./value=\"$value\"]" |
| 184 | 7 | Andrei Pozolotin | |
| 185 | 7 | Andrei Pozolotin | # TODO add duplicate entry cleanup |
| 186 | 7 | Andrei Pozolotin | |
| 187 | 7 | Andrei Pozolotin | augeas { "limits_conf/$key": |
| 188 | 7 | Andrei Pozolotin | context => "$context", |
| 189 | 7 | Andrei Pozolotin | onlyif => "match $path_exact size==0", |
| 190 | 7 | Andrei Pozolotin | changes => [ |
| 191 | 7 | Andrei Pozolotin | # remove all matching to the $domain, $type, $item, for any $value |
| 192 | 7 | Andrei Pozolotin | "rm $path_list", |
| 193 | 7 | Andrei Pozolotin | # insert new node at the end of tree |
| 194 | 7 | Andrei Pozolotin | "set domain[last()+1] $domain", |
| 195 | 7 | Andrei Pozolotin | # assign values to the new node |
| 196 | 7 | Andrei Pozolotin | "set domain[last()]/type $type", |
| 197 | 7 | Andrei Pozolotin | "set domain[last()]/item $item", |
| 198 | 7 | Andrei Pozolotin | "set domain[last()]/value $value", |
| 199 | 7 | Andrei Pozolotin | ], |
| 200 | 7 | Andrei Pozolotin | } |
| 201 | 7 | Andrei Pozolotin | |
| 202 | 7 | Andrei Pozolotin | } |
| 203 | 7 | Andrei Pozolotin | |
| 204 | 7 | Andrei Pozolotin | } |
| 205 | 8 | Andrei Pozolotin | |
| 206 | 8 | Andrei Pozolotin | use case: |
| 207 | 8 | Andrei Pozolotin | |
| 208 | 8 | Andrei Pozolotin | include limits |
| 209 | 8 | Andrei Pozolotin | |
| 210 | 8 | Andrei Pozolotin | limits::conf { |
| 211 | 8 | Andrei Pozolotin | |
| 212 | 8 | Andrei Pozolotin | # maximum number of open files/sockets for root |
| 213 | 8 | Andrei Pozolotin | "root-soft": domain => root, type => soft, item => nofile, value => 9999; |
| 214 | 8 | Andrei Pozolotin | "root-hard": domain => root, type => hard, item => nofile, value => 9999; |
| 215 | 8 | Andrei Pozolotin | |
| 216 | 8 | Andrei Pozolotin | } |
| 217 | 8 | Andrei Pozolotin | |
| 218 | 8 | Andrei Pozolotin | |
| 219 | 6 | Andrei Pozolotin |