The SALVE Language
What does a SALVE manifest actually look like? Here we describe the basic format of a manifest file.
Example Manifest
We begin with an example, which will be broken down and explained in the sections below.
file {
source "files/bash/bashrc"
target "$HOME/.bashrc"
mode 600
}
directory "$HOME/dircolors" {
source "dirs/dircolors"
action copy
}
file {
source "/etc/passwd"
target "/opt/myprog/passwd-clone"
mode 0440
user "admin"
group "root"
}
manifest "manifests/vim.manifest"
The Grammar
A manifest is a file containing expressions, e, in the following basic grammar. Some liberties have been taken with notation below.
e := Empty String
| block_id optional_primary_attr { attrs } e
block_id := "file"
| "directory"
| "manifest"
optional_primary_attr := Empty String
| value
attrs := Empty String
| name value attrs
name := namechar name
| namechar
namechar := alpha
| digit
| "_"
value := valuechar value
| valuechar
| '"' quotedvalue '"'
| "'" quotedvalue "'"
quotedvalue := quotedchar quotedvalue
| quotedchar
quotedchar := valuechar | " "
valuechar := namechar
| "_" | "-" | "+"
| "=" | "^" | "&"
| "@" | "`" | "/"
| "|" | "~" | "$"
| "(" | ")" | "["
| "]" | "." | ","
| "<" | ">" | "*"
| "?" | "!" | "%"
| "#"
Note that this only defines the grammar of acceptable SALVE expressions for the parser. There are further constraints upon what keywords are valid and carry meaning. Those are defined below.
Variables
SALVE supports the use of environment variables in templates. These values will be pulled out of the executing shell's environment, and used to expand the attribute values of blocks in manifests.
There are a small number of exceptions to this.
SUDO_USER
is inspected, and if set, used in place of USER
.
At present, there is no way to specify the real value of USER
, regardless of 'sudo' invocation.
SALVE_USER_PRIMARY_GROUP
always refers to the primary group of USER
, after SUDO_USER
substitution.
HOME
always refers to the home directory of USER
after SUDO_USER
substitution.
This ensures that HOME
always refers to the invoking user's homedir, even if sudo is set to reset the HOME
environment variable.
Example
Given the block below
file {
source "files/bash/bashrc"
target "$HOME/.bashrc"
mode 600
}
When SALVE is invoked by a user, "user1", with home directory "/home/user1", the value of "target" after expansion is "/home/user1/.bashrc" This holds even when "user1" invokes SALVE with sudo.
Relative Paths
Relative paths are also supported, so that it is not necessary to rely on values like $PWD
.
Relative paths are always interpreted relative to the root manifest's location.
One item on the docket is to make an available override behavior to specify
relative paths with respect to the dirname of the manifest containing the
relative path.
Example
Given the block below
file {
source "files/bash/bashrc"
target "$HOME/.bashrc"
mode 600
}
if SALVE is invoked as salve -m /tmp/myconf/root.manifest
,
then the value of "source" after expansion is "/tmp/myconf/files/bash/bashrc"
Primary Attributes
Primary Attributes are specified immediately after the block type, and are
attribute values, as in manifest "manifests/vim.manifest"
.
They have different semantics depending on the type of block being used.
In the case of file and directory blocks, the primary attribute is the "target"
or file or directory to create or copy over, while in the case of manifest
blocks it is the "source" or manifest whose contents should be read.
Primary Attributes are assigned to the block being parsed as though they were specified explicitly with their matching attribute name. In other words,
manifest "manifests/vim.manifest"
is exactly the same as writing
manifest {
source "manifests/vim.manifest"
}
Definitions
Each attribute of a block has a specific meaning, and many of the values themselves are keywords referring to specific actions.
Knowing these meanings is key to reading and understanding a manifest.
Below are the definitions of each manifest action, given in a subscript notation.
For example, file[action]
specifies the 'action' attribute of 'file' blocks.
file[action]
Specifies what the file block does.
file[action]=copy
-- The copy action copiesfile[source]
tofile[target]
file[action]=create
-- The create action touchesfile[target]
file[mode]
Is the umask (given in the typical octal notation) to be set on the file specified by file[target]
.
file[user], file[group]
These are set via chmod whenever SALVE is invoked as root. Otherwise, they do nothing.
file[user]
-- The owner offile[target]
.file[group]
-- The owning group offile[target]
.
file[source], file[target]
The paths to files specified by the block. Typically the target is a location on the filesystem being configured, and the source is a file versioned in the SALVE repository being used to modify the target.
file[backup_dir], file[backup_log]
The backup_dir holds backups of any files that have destructive operations performed on them by the block. The backup_log records all backups that are performed.
file[backup_dir]
-- The path to the directory in which file backups are storedfile[backup_log]
-- The path to the file to which backup actions are logged (date, hash, full path to file)
manifest[source]
The path to the manifest that is expanded at this location.
directory[action]
directory[action]=create
-- Create the directory atdirectory[target]
, and any required ancestorsdirectory[action]=copy
-- Create the directory atdirectory[target]
, and then recursively copy contents fromdirectory[source]
todirectory[target]
directory[mode]
Is the umask (given in the typical octal notation) to be set on the directory specified by directory[target]
.
directory[user], directory[group]
These are set via chmod whenever SALVE is invoked as root. Otherwise, they do nothing.
directory[user]
-- The owner ofdirectory[target]
.file[group]
-- The owning group ofdirectory[target]
.
directory[source], directory[target]
The paths to directories specified by the block. Typically the target is a location on the filesystem being configured, and the source is a directory versioned in the SALVE repository being used to modify the target. When only one path exists, it is typically the target.
directory[backup_dir], directory[backup_log]
The backup_dir holds backups of any files that have destructive operations performed on them by the block. The backup_log records all backups that are performed.
file[backup_dir]
-- The path to the directory in which file backups are storedfile[backup_log]
-- The path to the file to which backup actions are logged (date, hash, full path to file)