Skip to content

Augeas tool for creating idempotent augtool scripts

License

Notifications You must be signed in to change notification settings

georgehansper/augsuggest.c

Repository files navigation

augsuggest.c

Prerequisites

  • augeas
  • augeas-libs
  • augeas-devel (ie augeas headers)

Building

git clone https://github.com/georgehansper/augsuggest.c.git
cd augsuggest.c
make

Description

This program is an Augeas client (https://augeas.net)

It is strongly recommended to be using Augeas 1.13.0 or later (see Idempotency below).

augsuggest uses the Augeas API to create a script which can be run directly from augtool.

The resulting script is intended to

  • be able to recreate the original file
  • make no changes if applied to the original file
  • use path-expressions in preference to position-numbers

The output script differs from the style of output generated by the augtool print command, in that the print command output always uses an absolute position (number) for repeated nodes or sequential nodes

eg

augtool> print /files/etc/hosts
/files/etc/hosts
/files/etc/hosts/#comment[1] = "default entries"
/files/etc/hosts/1
/files/etc/hosts/1/ipaddr = "127.0.0.1"
/files/etc/hosts/1/canonical = "localhost"
/files/etc/hosts/1/alias[1] = "localhost.localdomain"
/files/etc/hosts/1/alias[2] = "localhost4"
...

augsuggest tries hard to avoid numbered positions, and will generate a path-expression in place of a number in most cases (see Limitations below).

eg

set /files/etc/hosts/seq::*[ipaddr='127.0.0.1']/ipaddr '127.0.0.1'
set /files/etc/hosts/seq::*[ipaddr='127.0.0.1']/canonical 'localhost'
set /files/etc/hosts/seq::*[ipaddr='127.0.0.1']/alias[.='localhost.localdomain'] 'localhost.localdomain'
set /files/etc/hosts/seq::*[ipaddr='127.0.0.1']/alias[.='localhost4'] 'localhost4'
...

The path-expression is based on the values set for each position (number), such that associated paths are kept together In practical terms, this means that if we apply the above augsuggest output to any /etc/hosts file:

a) If there is an existing /etc/hosts entry like the following one, it will leave it unchanged:

    127.0.0.1  localhost localhost.localdomain localhost4

b) If there is no entry for 127.0.0.1 in /etc/hosts, it will create a new entry, appended to the end of the file

c) If there is an existing entry for 127.0.0.1 in /etc/hosts which is different to the above, it will be modified using the values from augsuggest output, regardless of whether or not 127.0.0.1 is the first entry in the file

A normal use for this would be to idempotently add an entry to /etc/hosts, or if an existing entry is found, idempotently modify it to the values given

The nature of the augsuggest paths are that they are position-independent, so that it doesn't require 127.0.0.1 to be the first entry in /etc/hosts - it can be any line in the file

Idempotency

The term "idempotent" is a mathematical term, referring to a function or operation which when subsequently re-applied to the value of the previous result, leaves the result unchanged. eg. multiplying a number by zero or one, or taking the zero-th power of a number.

augsuggest aims to create an augtool script that is "idempotent", in that once it has been applied to a file, re-applying the same script will make no futher changes.

Augeas versions prior to 1.13.0 lack support for the seq::* element in the path-expression, making it difficult to write idempotent augtool scripts

As such, augsuggest should be used with Augeas 1.13.0 or later.

The option --noseq will alter the output of augsuggest to use * in place of seq::*

The resulting script will still be idempotent, and will be compatible with earlier versions of Augeas However, it will not be able to create the paths which are of the form .../1 or .../2 etc Existing paths will still have their values modified to those in the script

For example, given a path like this (from an augtool command match or print):

/files/etc/hosts/1/ipaddr = "127.0.0.1"

The corresponding output from augsuggest --noseq ... would include

set /files/etc/hosts/*[ipaddr='127.0.0.1']/ipaddr '127.0.0.1'

This statement will not create a new entry for 127.0.0.1 if none exists.

Suggested Usage

Augeas is already quite good at being idempotent, but writing path-expressions can be difficult for newcomers, and tedious for experienced users.

The output of augsuggest is intended to automate the generation of Augeas path-expressions as follows:

a) Copy the target file to another location, eg.

    cp /etc/hosts /var/tmp/hosts.new

b) Edit the new file as desired, eg add

    192.0.2.3   defaultdns

c) Run augsuggest as follows

    augsuggest --target=/etc/hosts /var/tmp/hosts.new

d) Identify the path-expressions associated with the changes

    set /files/etc/hosts/seq::*[ipaddr='192.0.2.3']/ipaddr '192.0.2.3'
    set /files/etc/hosts/seq::*[ipaddr='192.0.2.3']/canonical 'defaultdns'

e) Copy the above directly into an augtool script or use them in your chosen augeas client

Regexp output

augsuggest can also produce paths based on regular expressions, as follows:

    augsuggest --target=/etc/hosts --regexp /var/tmp/hosts.new
    set /files/etc/hosts/seq::*[ipaddr=~regexp('192\\.0\\.2\\.3')]/ipaddr '192.0.2.3'
    set /files/etc/hosts/seq::*[ipaddr=~regexp('192\\.0\\.2\\.3')]/canonical 'defaultdns'

Limitations

Append-only

The output is based entirely on set operations. The set operation can only:

a) change an existing value in-situ b) append a new value after the last position in the group

This means that when an entry is re-created, it may not be in the same position as originally intended. ie if the entry for 192.0.2.3 does not already exist, it will be created as the last entry in /etc/hosts

Often, such out-of-sequence entries will not matter to the resulting configuration file. If it does matter, further manual editing of the augtool script will be required.

Repeated Values

augsuggest tries hard to find a path-expression which is unique to a position, and independent of the numerical position However, it is not always successful. If it fails to find a unique expression, it will produce a partial expression followed by a position-number. eg.

For an /etc/hosts section:

    #------
    192.0.2.3   defaultdns
    #------

The output would be:

    set /files/etc/hosts/#comment[.='--------'][1] '--------'
    set /files/etc/hosts/seq::*[ipaddr='192.0.2.3']/ipaddr '192.0.2.3'
    set /files/etc/hosts/seq::*[ipaddr='192.0.2.3']/canonical 'defaultdns'
    set /files/etc/hosts/#comment[.='--------'][2] '--------'

Notice how #comment paths have [1] and [2] appended respectively to the [expr]

augsuggest could not find a position-independent path-expression to describe these comments, because the same comment appears twice in the file.

The resulting output is still idempotent, but the path for the #comment is no longer "independent of position"

Copyright (C) 2022 George Hansper george@hansper.id.au

About

Augeas tool for creating idempotent augtool scripts

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published