neulab/tldr huggingface dataset:
Client interfaces Salt's client interfaces expose executing functions by crafting a dictionary of values that are mapped to function arguments. This allows calling functions simply by creating a data structure. (And this is exactly how much of Salt's own internals work!)
class salt.netapi.NetapiClient(opts) Provide a uniform method of accessing the various client interfaces in Salt in the form of low-data data structures. For example:
>>> client = NetapiClient(__opts__) >>> lowstate = {'client': 'local', 'tgt': '*', 'fun': 'test.ping', 'arg': ''} >>> client.run(lowstate)
local(*args, **kwargs) Run execution modules synchronously
See salt.client.LocalClient.cmd() for all available parameters.
Sends a command from the master to the targeted minions. This is the same interface that Salt's own CLI uses. Note the arg and kwarg parameters are sent down to the minion(s) and the given function, fun, is called with those parameters.
Returns Returns the result from the execution module
local_async(*args, **kwargs) Run execution modules asynchronously
Wraps salt.client.LocalClient.run_job().
Returns job ID
local_subset(*args, **kwargs) Run execution modules against subsets of minions
Wraps salt.client.LocalClient.cmd_subset()
runner(fun, timeout=None, full_return=False, **kwargs) Run runner modules <all-salt.runners> synchronously
Wraps salt.runner.RunnerClient.cmd_sync().
Note that runner functions must be called using keyword arguments.  Positional arguments are not supported.
Returns Returns the result from the runner module
runner_async(fun, **kwargs) Run runner modules <all-salt.runners> asynchronously
Wraps salt.runner.RunnerClient.cmd_async().
Returns event data and a job ID for the executed function.
ssh(*args, **kwargs) Run salt-ssh commands synchronously
Wraps salt.client.ssh.client.SSHClient.cmd_sync().
Returns Returns the result from the salt-ssh command
wheel(fun, **kwargs) Run wheel modules synchronously
Wraps salt.wheel.WheelClient.master_call().
Note that wheel functions must be called using keyword arguments.  Positional arguments are not supported.
Returns Returns the result from the wheel module
wheel_async(fun, **kwargs) Run wheel modules asynchronously
Writing netapi modules netapi modules, put simply, bind a port and start a service.  They are purposefully open-ended and can be used to present a variety of external interfaces to Salt, and even present multiple interfaces at once.
Configuration All netapi configuration is done in the Salt master config and takes a form similar to the following:
rest_cherrypy: port: 8000 debug: True ssl_crt: /etc/pki/tls/certs/localhost.crt ssl_key: /etc/pki/tls/certs/localhost.key
The __virtual__ function Like all module types in Salt, netapi modules go through Salt's loader interface to determine if they should be loaded into memory and then executed.
The __virtual__ function in the module makes this determination and should return False or a string that will serve as the name of the module. If the module raises an ImportError or any other errors, it will not be loaded.
The start function The start() function will be called for each netapi module that is loaded. This function should contain the server loop that actually starts the service. This is started in a multiprocess.
Multiple instances New in version 2016.11.0.
rest_cherrypy and rest_tornado support running multiple instances by copying and renaming entire directory of those. To start the copied multiple netapi modules, add configuration blocks for the copied netapi modules in the Salt Master config. The name of each added configuration block must match with the name of each directory of the copied netapi module.
Inline documentation As with the rest of Salt, it is a best-practice to include liberal inline documentation in the form of a module docstring and docstrings on any classes, methods, and functions in your netapi module.
Loader “magic” methods The loader makes the __opts__ data structure available to any function in a netapi module.
If you are used to configuration management tools that require you to plan down to the last detail before you install anything, you are probably wondering why this section doesn't appear before the installation instructions. With Salt, you can switch to a high availability architecture at any time, and add additional components to scale your deployment as you go.
Since a single Salt master can manage thousands of systems, we usually recommend that you start by deploying a single Salt master, and then modifying your deployment as needed for redundancy, geographical distribution, and scale.
High Availability Features in Salt Salt supports several features for high availability and fault tolerance. Brief documentation for these features is listed alongside their configuration parameters in Configuration file examples.
Multimaster Salt minions can connect to multiple masters at one time by configuring the master configuration parameter as a YAML list of all the available masters.  By default, all masters are "hot", meaning that any master can direct commands to the Salt infrastructure.
In a multimaster configuration, each master must have the same cryptographic keys, and minion keys must be accepted on all masters separately.  The contents of file_roots and pillar_roots need to be kept in sync with processes external to Salt as well
A tutorial on setting up multimaster with "hot" masters is here:
Multimaster Tutorial
Multimaster with Failover Changing the master_type parameter from str to failover will cause minions to connect to the first responding master in the list of masters. Every master_alive_interval seconds the minions will check to make sure the current master is still responding.  If the master does not respond, the minion will attempt to connect to the next master in the list.  If the minion runs out of masters, the list will be recycled in case dead masters have been restored.  Note that master_alive_interval must be present in the minion configuration, or else the recurring job to check master status will not get scheduled.
Failover can be combined with PKI-style encrypted keys, but PKI is NOT REQUIRED to use failover.
Multimaster with PKI and Failover is discussed in this tutorial
master_type: failover can be combined with master_shuffle: True to spread minion connections across all masters (one master per minion, not each minion connecting to all masters).  Adding Salt Syndics into the mix makes it possible to create a load-balanced Salt infrastructure.  If a master fails, minions will notice and select another master from the available list.
Syndic Salt's Syndic feature is a way to create differing infrastructure topologies.  It is not strictly an HA feature, but can be treated as such.
With the syndic, a Salt infrastructure can be partitioned in such a way that certain masters control certain segments of the infrastructure, and "Master of Masters" nodes can control multiple segments underneath them.
Syndics are covered in depth in Salt Syndic.
Syndic with Multimaster New in version 2015.5.0.
Syndic with Multimaster lets you connect a syndic to multiple masters to provide an additional layer of redundancy in a syndic configuration.
Salt Syndic The most basic or typical Salt topology consists of a single Master node controlling a group of Minion nodes.  An intermediate node type, called Syndic, when used offers greater structural flexibility and scalability in the construction of Salt topologies than topologies constructed only out of Master and Minion node types.
A Syndic node can be thought of as a special passthrough Minion node.  A Syndic node consists of a salt-syndic daemon and a salt-master daemon running on the same system.  The salt-master daemon running on the Syndic node controls a group of lower level Minion nodes and the salt-syndic daemon connects higher level Master node, sometimes called a Master of Masters.
The salt-syndic daemon relays publications and events between the Master node and the local salt-master daemon.  This gives the Master node control over the Minion nodes attached to the salt-master daemon running on the Syndic node.
Configuring the Syndic To setup a Salt Syndic you need to tell the Syndic node and its Master node about each other.  If your Master node is located at 10.10.0.1, then your configurations would be:
On the Syndic node:
# /etc/salt/master syndic_master: 10.10.0.1  # may be either an IP address or a hostname
# /etc/salt/minion
# id is shared by the salt-syndic daemon and a possible salt-minion daemon # on the Syndic node id: my_syndic
On the Master node:
# /etc/salt/master order_masters: True
The syndic_master option tells the Syndic node where to find the Master node in the same way that the master option tells a Minion node where to find a Master node.
The id option is used by the salt-syndic daemon to identify with the Master node and if unset will default to the hostname or IP address of the Syndic just as with a Minion.
The order_masters option configures the Master node to send extra information with its publications that is needed by Syndic nodes connected directly to it.
NOTE: Each Syndic must provide its own file_roots directory. Files will not be automatically transferred from the Master node.
Configuring the Syndic with Multimaster New in version 2015.5.0.
Higher level masters should first be configured in a multimaster configuration.  See Multimaster Tutorial.
On the syndic, the syndic_master option is populated with a list of the higher level masters.
Since each syndic is connected to each master, jobs sent from any master are forwarded to minions that are connected to each syndic. If the master_id value is set in the master config on the higher level masters, job results are returned to the master that originated the request in a best effort fashion. Events/jobs without a master_id are returned to any available master.
Running the Syndic The salt-syndic daemon is a separate process that needs to be started in addition to the salt-master daemon running on the Syndic node.  Starting the salt-syndic daemon is the same as starting the other Salt daemons.
The Master node in many ways sees the Syndic as an ordinary Minion node. In particular, the Master will need to accept the Syndic's Minion key as it would for any other Minion.
# salt-syndic or # service salt-syndic start
# salt-key -a my_syndic
The Master node will now be able to control the Minion nodes connected to the Syndic.  Only the Syndic key will be listed in the Master node's key registry but this also means that key activity between the Syndic's Minions and the Syndic does not encumber the Master node.  In this way, the Syndic's key on the Master node can be thought of as a placeholder for the keys of all the Minion and Syndic nodes beneath it, giving the Master node a clear, high level structural view on the Salt cluster.
# salt-key -L Accepted Keys: my_syndic Denied Keys: Unaccepted Keys: Rejected Keys:
# salt '*' test.version minion_1: 2018.3.4 minion_2: 2018.3.4 minion_4: 2018.3.4 minion_3: 2018.3.4
Topology A Master node (a node which is itself not a Syndic to another higher level Master node) must run a salt-master daemon and optionally a salt-minion daemon.
A Syndic node must run salt-syndic and salt-master daemons and optionally a salt-minion daemon.
A Minion node must run a salt-minion daemon.
When a salt-master daemon issues a command, it will be received by the Syndic and Minion nodes directly connected to it.  A Minion node will process the command in the way it ordinarily would.  On a Syndic node, the salt-syndic daemon will relay the command to the salt-master daemon running on the Syndic node, which then propagates the command to the Minions and Syndics connected to it.
When events and job return data are generated by salt-minion daemons, they are aggregated by the salt-master daemon they are connected to, which salt-master daemon then relays the data back through its salt-syndic daemon until the data reaches the Master or Syndic node that issued the command.
Syndic wait syndic_wait is a master configuration file setting that specifies the number of seconds the Salt client should wait for additional syndics to check in with their lists of expected minions before giving up. This value defaults to 5 seconds.
The syndic_wait setting is necessary because the higher-level master does not have a way of knowing which minions are below the syndics. The higher-level master has its own list of expected minions and the masters below them have their own lists as well, so the Salt client does not know how long to wait for all returns. The syndic_wait option allows time for all minions to return to the Salt client.
NOTE: To reduce the amount of time the CLI waits for Minions to respond, install a Minion on the Syndic or tune the value of the syndic_wait configuration.
While it is possible to run a Syndic without a Minion installed on the same system, it is recommended, for a faster CLI response time, to do so. Without a Minion installed on the Syndic node, the timeout value of syndic_wait increases significantly - about three-fold. With a Minion installed on the Syndic, the CLI timeout resides at the value defined in syndic_wait.
NOTE: If you have a very large infrastructure or many layers of Syndics, you may find that the CLI doesn't wait long enough for the Syndics to return their events.  If you think this is the case, you can set the syndic_wait value in the Master configs on the Master or Syndic nodes from which commands are executed.  The default value is 5, and should work for the majority of deployments.
In order for a Master or Syndic node to return information from Minions that are below their Syndics, the CLI requires a short wait time in order to allow the Syndics to gather responses from their Minions. This value is defined in the syndic_wait config option and has a default of five seconds.
Syndic config options These are the options that can be used to configure a Syndic node.  Note that other than id, Syndic config options are placed in the Master config on the Syndic node.
• id: Syndic id (shared by the salt-syndic daemon with a potential salt-minion daemon on the same system)
• syndic_master: Master node IP address or hostname
• syndic_master_port: Master node ret_port
• syndic_log_file: path to the logfile (absolute or not)
• syndic_pidfile: path to the pidfile (absolute or not)
• syndic_wait: time in seconds to wait on returns from this syndic
Minion Data Cache Beginning with Salt 2016.11.0, the Pluggable Minion Data Cache was introduced. The minion data cache contains the Salt Mine data, minion grains, and minion pillar information cached on the Salt Master. By default, Salt uses the localfs cache module, but other external data stores can be used instead.
The Minion data cache contains the Salt Mine data, minion grains and minion pillar information cached on the Salt Master. By default, Salt uses the localfs cache module to save the data in a msgpack file on the Salt Master.
Pluggable Data Cache While the default Minion data cache is the localfs cache, other external data stores can also be used to store this data such as the consul module.  To configure a Salt Master to use a different data store, the cache setting needs to be established:
The pluggable data cache streamlines using various Salt topologies such as a Multi-Master or Salt Syndics configuration by allowing the data stored on the Salt Master about a Salt Minion to be available to other Salt Syndics or Salt Masters that a Salt Minion is connected to.
Additional minion data cache modules can be easily created by modeling the custom data store after one of the existing cache modules.
See cache modules for a current list.
Configuring the Minion Data Cache The default localfs Minion data cache module doesn't require any configuration.  External data cache modules with external data stores such as Consul require a configuration setting in the master config.
Here's an example config for Consul:
NOTE: This functionality is under development and could be changed in the future releases
Many times it is useful to store the results of a command during the course of an execution. Salt Slots are designed to allow you to store this information and use it later during the highstate or other job execution.
Slots extend the state syntax and allows you to do things right before the state function is executed. So you can make a decision in the last moment right before a state is executed.
Execution functions NOTE: Using execution modules return data as a state values is a first step of Slots development. Other functionality is under development.
Slots allow you to use the return from a remote-execution function as an argument value in states.
Slot syntax looks close to the simple python function call.
__slot__:salt:<module>.<function>(<args>, ..., <kwargs...>, ...)
For the 3000 release, this syntax has been updated to support parsing functions which return dictionaries and for appending text to the slot result.
__slot__:salt:<module>.<function>(<args>..., <kwargs...>, ...).dictionary ~ append
There are some specifics in the syntax coming from the execution functions nature and a desire to simplify the user experience. First one is that you don't need to quote the strings passed to the slots functions. The second one is that all arguments handled as strings.
Here is a simple example:
copy-some-file: file.copy: - name: __slot__:salt:test.echo(text=/tmp/some_file) - source: __slot__:salt:test.echo(/etc/hosts)
This will execute the test.echo execution functions right before calling the state. The functions in the example will return /tmp/some_file and /etc/hosts strings that will be used as a target and source arguments in the state function file.copy.
Here is an example of result parsing and appending:
file-in-user-home: file.copy: - name: __slot__:salt:user.info(someuser).home ~ /subdirectory - source: salt://somefile
This section contains details on the Windows Package Manager, and specific information you need to use Salt on Windows.
Windows Package Manager Introduction The Windows Package Manager provides a software repository and a package manager similar to what is provided by yum and apt on Linux. This tool enables the installation of software on remote Windows systems.
The repository contains a collection of software definition files. A software definition file is a YAML/JINJA file with an .sls file extension. It contains all the information Salt needs to install a software package on a Windows system, including the download location of the installer, required command-line switches for silent install, etc.
Software definition files can be hosted in one or more Git repositories. The default repository is hosted on GitHub by SaltStack. It is maintained by SaltStack and the Salt community and contains software definition files for many common Windows packages.  Anyone is welcome to submit a pull request to this repo to add new software definitions. The default github repository is:
• salt-winrepo-ng
The Windows Package Manager is used the same way as other package managers Salt is aware of. For example:
• the pkg.installed and similar states work on Windows.
• the pkg.install and similar module functions work on Windows.
High level differences to yum and apt are:
• The repository metadata (SLS files) can be managed through either Salt or git
• Packages can be downloaded from within the Salt repository, a git repository or from HTTP(S) or FTP URLs
• No dependencies are managed. Dependencies between packages need to be managed manually
Requirements If using the a software definition files hosted on a Git repo, the following libraries are required:
• GitPython 0.3 or later
• pygit2 0.20.3 with libgit 0.20.0 or later
Quick Start You can get up and running with winrepo pretty quickly just using the defaults.  Assuming no changes to the default configuration (ie, file_roots) run the following commands on the master:
salt-run winrepo.update_git_repos salt * pkg.refresh_db salt * pkg.install firefox_x64
On a masterless minion run the following:
salt-call --local winrepo.update_git_repos salt-call --local pkg.refresh_db salt-call --local pkg.install firefox_x64
These commands clone the default winrepo from github, update the winrepo database on the minion, and install the latest version of Firefox.
Configuration The Github repository (winrepo) is synced to the file_roots in a location specified by the winrepo_dir_ng setting in the config. The default value of winrepo_dir_ng is as follows:
• Linux master: /srv/salt/win/repo-ng (salt://win/repo-ng)
• Masterless minion: C:\salt\srv\salt\win\repo-ng (salt://win/repo-ng)
Master Configuration The following are settings are available for configuring the winrepo on the master:
• winrepo_dir
• winrepo_dir_ng
• winrepo_remotes
• winrepo_remotes_ng
• winrepo_branch
• winrepo_provider
• winrepo_ssl_verify
See here for detailed information on all master config options for winrepo.
winrepo_dir winrepo_dir (str)
This setting is maintained for backwards compatibility with legacy minions. It points to the location in the file_roots where the winrepo files are kept.  The default is: /srv/salt/win/repo
winrepo_dir_ng winrepo_dir_ng (str)
The location in the file_roots where the winrepo files are kept. The default is /srv/salt/win/repo-ng.
WARNING: You can change the location of the winrepo directory. However, it must always be set to a path that is inside the file_roots.  Otherwise the software definition files will be unreachable by the minion.
IMPORTANT: A common mistake is to change the file_roots setting and fail to update the winrepo_dir_ng and winrepo_dir settings so that they are inside the file_roots
winrepo_remotes winrepo_remotes (list)
This setting is maintained for backwards compatibility with legacy minions. It points to the legacy git repo. The default is a list containing a single URL:
https://github.com/saltstack/salt-winrepo
The legacy repo can be disabled by setting it to an empty list in the master config.
winrepo_remotes: []
winrepo_remotes_ng winrepo_remotes_ng (list)
This setting tells the winrepo.upgate_git_repos command where the next generation winrepo is hosted. This a list of URLs to multiple git repos. The default is a list containing a single URL:
https://github.com/saltstack/salt-winrepo-ng
winrepo_refspecs winrepo_refspecs (list)
Specify what references to fetch from remote repositories. The default is ['+refs/heads/*:refs/remotes/origin/*', '+refs/tags/*:refs/tags/*']
winrepo_branch winrepo_branch (str)
The branch of the git repo to checkout. The default is master
winrepo_provider winrepo_provider (str)
The provider to be used for winrepo. Default is pygit2. Falls back to gitpython when pygit2 is not available
winrepo_ssl_verify winrepo_ssl_verify (bool)
Ignore SSL certificate errors when contacting remote repository. Default is False
Master Configuration (pygit2) The following configuration options only apply when the winrepo_provider option is set to pygit2.
• winrepo_insecure_auth
• winrepo_passphrase
• winrepo_password
• winrepo_privkey
• winrepo_pubkey
• winrepo_user
winrepo_insecure_auth winrepo_insecure_auth (bool)
Used only with pygit2 provider. Whether or not to allow insecure auth. Default is False
winrepo_passphrase winrepo_passphrase (str)
Used only with pygit2 provider. Used when the SSH key being used to authenticate is protected by a passphrase. Default is ''
winrepo_privkey winrepo_privkey (str)
Used only with pygit2 provider. Used with winrepo_pubkey to authenticate to SSH remotes. Default is ''
winrepo_pubkey winrepo_pubkey (str)
Used only with pygit2 provider. Used with winrepo_privkey to authenticate to SSH remotes. Default is ''
winrepo_user winrepo_user (str)
Used only with pygit2 provider. Used with winrepo_password to authenticate to HTTPS remotes. Default is ''
winrepo_password winrepo_password (str)
Used only with pygit2 provider. Used with winrepo_user to authenticate to HTTPS remotes. Default is ''
Minion Configuration Refreshing the package definitions can take some time, these options were introduced to allow more control of when it occurs. These settings apply to all minions whether in masterless mode or not.
• winrepo_cachefile
• winrepo_source_dir
winrepo_cache_expire_max winrepo_cache_expire_max (int)
Sets the maximum age in seconds of the winrepo metadata file to avoid it becoming stale. If the metadata file is older than this setting it will trigger a pkg.refresh_db on the next run of any pkg module function that requires the metadata file. Default is 604800 (1 week).
Software package definitions are automatically refreshed if stale after winrepo_cache_expire_max.  Running a highstate normal forces the refresh of the package definition and generation of the metadata, unless the metadata is younger than winrepo_cache_expire_max.
winrepo_cache_expire_min winrepo_cache_expire_min (int)
Sets the minimum age in seconds of the winrepo metadata file to avoid refreshing too often. If the metadata file is older than this setting the metadata will be refreshed unless you pass refresh: False in the state. Default is 1800 (30 min).
winrepo_cachefile winrepo_cachefile (str)
The file name of the winrepo cache file. The file is placed at the root of winrepo_dir_ng. Default is winrepo.p.
winrepo_source_dir winrepo_source_dir (str)
The location of the .sls files on the Salt file server. This allows for using different environments. Default is salt://win/repo-ng/.
WARNING: If the default for winrepo_dir_ng is changed, this setting may need to changed on each minion. The default setting for winrepo_dir_ng is /srv/salt/win/repo-ng. If that were changed to /srv/salt/new/repo-ng then the winrepo_source_dir would need to be changed to salt://new/repo-ng
Masterless Minion Configuration The following are settings are available for configuring the winrepo on a masterless minion:
See here for detailed information on all minion config options for winrepo.
This setting is maintained for backwards compatibility with legacy minions. It points to the location in the file_roots where the winrepo files are kept.  The default is: C:\salt\srv\salt\win\repo
The location in the file_roots where the winrepo files are kept. The default is ``C:\salt\srv\salt\win\repo-ng.
IMPORTANT: A common mistake is to change the file_roots setting and fail to update the winrepo_dir_ng and winrepo_dir settings so that they are inside the file_roots. You might also want to verify winrepo_source_dir on the minion as well.
The legacy repo can be disabled by setting it to an empty list in the minion config.
Initialization Populate the Local Repository The SLS files used to install Windows packages are not distributed by default with Salt. Use the winrepo.update_git_repos runner initialize the repository in the location specified by winrepo_dir_ng in the master config. This will pull the software definition files down from the git repository.
salt-run winrepo.update_git_repos
If running a minion in masterless mode, the same command can be run using salt-call. The repository will be initialized in the location specified by winrepo_dir_ng in the minion config.
salt-call --local winrepo.update_git_repos
These commands will also sync down the legacy repo to maintain backwards compatibility with legacy minions. See Legacy Minions
The legacy repo can be disabled by setting it to an empty list in the master or minion config.
Generate the Metadata File (Legacy) This step is only required if you are supporting legacy minions. In current usage the metadata file is generated on the minion in the next step, Update the Minion Database. For legacy minions the metadata file is generated on the master using the winrepo.genrepo runner.
Update the Minion Database Run pkg.refresh_db on each of your Windows minions to synchronize the package repository to the minion and build the package database.
# From the master salt -G 'os:windows' pkg.refresh_db
# From the minion in masterless mode salt-call --local pkg.refresh_db
The above command returns the following summary denoting the number of packages that succeeded or failed to compile:
local: ---------- failed: 0 success: 301 total: 301
NOTE: This command can take a few minutes to complete as the software definition files are copied to the minion and the database is generated.
NOTE: Use pkg.refresh_db when developing new Windows package definitions to check for errors in the definitions against one or more Windows minions.
Usage After completing the configuration and initialization steps, you are ready to manage software on your Windows minions.
NOTE: The following example commands can be run from the master using salt or on a masterless minion using salt-call
List Installed Packages You can get a list of packages installed on the system using pkg.list_pkgs.
# From the master salt -G 'os:windows' pkg.list_pkgs
# From the minion in masterless mode salt-call --local pkg.list_pkgs
This will return all software installed on the system whether it is managed by Salt or not as shown below:
local: ---------- Frhed 1.6.0: 1.6.0 GNU Privacy Guard: 2.2.16 Gpg4win (3.1.9): 3.1.9 git: 2.17.1.2 nsis: 3.03 python3_x64: 3.7.4150.0 salt-minion-py3: 2019.2.3
You can tell by how the software name is displayed which software is managed by Salt and which software is not. When Salt finds a match in the winrepo database it displays the short name as defined in the software definition file. It is usually a single-word, lower-case name. All other software names will be displayed with the full name as they are shown in Add/Remove Programs. So, in the return above, you can see that Git (git), Nullsoft Installer (nsis), Python 3.7 (python3_x64) and Salt (salt-minion-py3) all have a corresponding software definition file. The others do not.
List Available Versions You can query the available version of a package using pkg.list_available and passing the name of the software:
# From the master salt winminion pkg.list_available firefox_x64
# From the minion in masterless mode salt-call --local pkg.list_available firefox_x64
The above command will return the following:
winminion: - 69.0 - 69.0.1 - 69.0.2 - 69.0.3 - 70.0 - 70.0.1 - 71.0 - 72.0 - 72.0.1 - 72.0.2 - 73.0 - 73.0.1 - 74.0
As you can see, there are many versions of Firefox available for installation.  You can refer to a software package by its name or its full_name surrounded by quotes.
NOTE: From a Linux master it is OK to use single-quotes. However, the cmd shell on Windows requires you to use double-quotes when wrapping strings that may contain spaces. Powershell seems to accept either one.
Install a Package You can install a package using pkg.install:
# From the master salt winminion pkg.install 'firefox_x64'
# From the minion in masterless mode salt-call --local pkg.install "firefox_x64"
The above will install the latest version of Firefox.
# From the master salt winminion pkg.install 'firefox_x64' version=74.0
# From the minion in masterless mode salt-call --local pkg.install "firefox_x64" version=74.0
The above will install version 74.0 of Firefox.
If a different version of the package is already installed it will be replaced with the version in the winrepo (only if the package itself supports live updating).
You can also specify the full name:
# From the master salt winminion pkg.install 'Mozilla Firefox 17.0.1 (x86 en-US)'
# From the minion in masterless mode salt-call --local pkg.install "Mozilla Firefox 17.0.1 (x86 en-US)"
Remove a Package You can uninstall a package using pkg.remove:
# From the master salt winminion pkg.remove firefox_x64
# From the minion in masterless mode salt-call --local pkg.remove firefox_x64
Software Definition Files A software definition file is a YAML/JINJA2 file that contains all the information needed to install a piece of software using Salt. It defines information about the package to include version, full name, flags required for the installer and uninstaller, whether or not to use the Windows task scheduler to install the package, where to download the installation package, etc.
Directory Structure and Naming The files are stored in the location designated by the winrepo_dir_ng setting. All files in this directory that have a .sls file extension are considered software definition files. The files are evaluated to create the metadata file on the minion.
You can maintain standalone software definition files that point to software on other servers or on the internet. In this case the file name would be the short name of the software with the .sls extension, ie firefox.sls.
You can also store the binaries for your software together with their software definition files in their own directory. In this scenario, the directory name would be the short name for the software and the software definition file would be inside that directory and named init.sls.
Look at the following example directory structure on a Linux master assuming default config settings:
srv/ |---salt/ |   |---win/ |   |   |---repo-ng/ |   |   |   |---custom_defs/ |   |   |   |   |---ms_office_2013_x64/ |   |   |   |   |   |---access.en-us/ |   |   |   |   |   |---excel.en-us/ |   |   |   |   |   |---outlook.en-us/ |   |   |   |   |   |---powerpoint.en-us/ |   |   |   |   |   |---word.en-us/ |   |   |   |   |   |---init.sls |   |   |   |   |   |---setup.dll |   |   |   |   |   |---setup.exe |   |   |   |   |---openssl.sls |   |   |   |   |---zoom.sls |   |   |   |---salt-winrepo-ng/ |   |   |   |   |---auditbeat/ |   |   |   |   |   |---init.sls |   |   |   |   |   |---install.cmd |   |   |   |   |   |---install.ps1 |   |   |   |   |   |---remove.cmd |   |   |   |   |---gpg4win/ |   |   |   |   |   |---init.sls |   |   |   |   |   |---silent.ini |   |   |   |   |---7zip.sls |   |   |   |   |---adobereader.sls |   |   |   |   |---audacity.sls |   |   |   |   |---ccleaner.sls |   |   |   |   |---chrome.sls |   |   |   |   |---firefox.sls
In the above directory structure, the user has created the custom_defs directory in which to store their custom software definition files. In that directory you see a folder for MS Office 2013 that contains all the installer files along with a software definition file named init.sls. The user has also created two more standalone software definition files; openssl.sls and zoom.sls.
The salt-winrepo-ng directory is created by the winrepo.update_git_repos command. This folder contains the clone of the git repo designated by the winrepo_remotes_ng config setting.
WARNING: It is recommended that the user not modify the files in the salt-winrepo-ng directory as it will break future runs of winrepo.update_git_repos.
WARNING: It is recommended that the user not place any custom software definition files in the salt-winrepo-ng directory. The winrepo.update_git_repos command wipes out the contents of the salt-winrepo-ng directory each time it is run. Any extra files stored there will be lost.
Writing Software Definition Files A basic software definition file is really easy to write if you already know some basic things about your software:
• The full name as shown in Add/Remove Programs
• The exact version number as shown in Add/Remove Programs
• How to install your software silently from the command line
The software definition file itself is just a data structure written in YAML.  The top level item is a short name that Salt will use to reference the software.  There can be only one short name in the file and it must be unique across all software definition files in the repo. This is the name that will be used to install/remove the software. It is also the name that will appear when Salt finds a match in the repo when running pkg.list_pkgs.
The next indentation level is the version number. There can be many of these, but they must be unique within the file. This is also displayed in pkg.list_pkgs.
The last indentation level contains the information Salt needs to actually install the software. Available parameters are:
• full_name : The full name as displayed in Add/Remove Programs
• installer : The location of the installer binary
• install_flags : The flags required to install silently
• uninstaller : The location of the uninstaller binary
• uninstall_flags : The flags required to uninstall silently
• msiexec : Use msiexec to install this package
• allusers : If this is an MSI, install to all users
• cache_dir : Cache the entire directory in the installer URL (salt://)
• cache_file : Cache a single file in the installer URL (salt://)
• use_scheduler : Launch the installer using the task scheduler
• source_hash : The hash sum for the installer
Usage of these parameters is demonstrated in the following examples and discussed in more detail below. To understand these examples you'll need a basic understanding of Jinja. The following links have some basic tips and best practices for working with Jinja in Salt:
Understanding Jinja
Example: Basic Take a look at this basic, pure YAML example for a software definition file for Firefox:
firefox_x64: '74.0': full_name: Mozilla Firefox 74.0 (x64 en-US) installer: 'https://download-installer.cdn.mozilla.net/pub/firefox/releases/74.0/win64/en-US/Firefox%20Setup%2074.0.exe' install_flags: '/S' uninstaller: '%ProgramFiles(x86)%/Mozilla Firefox/uninstall/helper.exe' uninstall_flags: '/S' '73.0.1': full_name: Mozilla Firefox 73.0.1 (x64 en-US) installer: 'https://download-installer.cdn.mozilla.net/pub/firefox/releases/73.0.1/win64/en-US/Firefox%20Setup%2073.0.1.exe' install_flags: '/S' uninstaller: '%ProgramFiles(x86)%/Mozilla Firefox/uninstall/helper.exe' uninstall_flags: '/S'
You can see the first item is the short name for the software, in this case firefox_x64. It is the first line in the definition. The next line is indented two spaces and contains the software version. The lines following the version are indented two more spaces and contain all the information needed to install the Firefox package.
IMPORTANT: The package name must be unique to all other packages in the software repository. The full_name combined with the version must also be unique.  They must also match exactly what is shown in Add/Remove Programs (appwiz.cpl).
IMPORTANT: The version number must be enclosed in quotes, otherwise the YAML parser will remove trailing zeros. For example, 74.0 will just become 74.
As you can see in the example above, a software definition file can define multiple versions for the same piece of software. These are denoted by putting the next version number at the same indentation level as the first with its software definition information indented below it.
Example: Jinja When there are tens or hundreds of versions available for a piece of software definition file can become quite large. This is a scenario where Jinja can be helpful. Consider the following software definition file for Firefox using Jinja:
{%- set lang = salt['config.get']('firefox:pkg:lang', 'en-US') %}
firefox_x64: {% for version in ['74.0', '73.0.1', '73.0', '72.0.2', '72.0.1', '72.0', '71.0', '70.0.1', '70.0', '69.0.3', '69.0.2', '69.0.1'] %} '{{ version }}': full_name: 'Mozilla Firefox {{ version }} (x64 {{ lang }})' installer: 'https://download-installer.cdn.mozilla.net/pub/firefox/releases/{{ version }}/win64/{{ lang }}/Firefox%20Setup%20{{ version }}.exe' install_flags: '/S' uninstaller: '%ProgramFiles%\Mozilla Firefox\uninstall\helper.exe' uninstall_flags: '/S' {% endfor %}
In this example we are able to generate a software definition file that defines how to install 12 versions of Firefox. We use Jinja to create a list of available versions. That list is in a for loop where each version is placed in the version variable. The version is inserted everywhere there is a {{ version }} marker inside the for loop.
You'll notice that there is a single variable (lang) defined at the top of the software definition. Because these files are going through the Salt renderer many Salt modules are exposed via the salt keyword. In this case it is calling the config.get function to get a language setting that can be placed in the minion config. If it is not there, it defaults to en-US.
Example: Latest There are some software vendors that do not provide access to all versions of their software. Instead they provide a single URL to what is always the latest version. In some cases the software keeps itself up to date. One example of this is the Google Chrome web browser.
To handle situations such as these, set the version to latest. Here's an example:
chrome: latest: full_name: 'Google Chrome' installer: 'https://dl.google.com/edgedl/chrome/install/GoogleChromeStandaloneEnterprise.msi' install_flags: '/qn /norestart' uninstaller: 'https://dl.google.com/edgedl/chrome/install/GoogleChromeStandaloneEnterprise.msi' uninstall_flags: '/qn /norestart' msiexec: True
The above example shows us two things. First it demonstrates the usage of latest as the version. In this case Salt will install the version of Chrome at the URL and report that version.
The second thing to note is that this is installing software using an MSI. You can see that msiexec is set to True.
Example: MSI Patch When the msiexec parameter is set to True it uses the /i option for installs and the /x option for uninstalls. This is problematic when trying to install an MSI patch which requires the /p option. You can't combine the /i and /p options. So how do you apply a patch to installed software in winrepo using an .msp file?
One wiley contributor came up with the following solution to this problem by using the %cd% environment variable. Consider the following software definition file:
MyApp: '1.0': full_name: MyApp installer: 'salt://win/repo-ng/MyApp/MyApp.1.0.msi' install_flags: '/qn /norestart' uninstaller: '{B5B5868F-23BA-297A-917D-0DF345TF5764}' uninstall_flags: '/qn /norestart' msiexec: True '1.1': full_name: MyApp installer: 'salt://win/repo-ng/MyApp/MyApp.1.0.msi' install_flags: '/qn /norestart /update "%cd%\\MyApp.1.1.msp" ' uninstaller: '{B5B5868F-23BA-297A-917D-0DF345TF5764}' uninstall_flags: '/qn /norestart' msiexec: True cache_file: salt://win/repo/MyApp/MyApp.1.1.msp
There are a few things to note about this software definition file. First, is the solution we are trying to solve, that of applying a patch. Version 1.0 just installs the application using the 1.0 MSI defined in the installer parameter. There is nothing special in the install_flags and nothing is cached.
Version 1.1 uses the same installer, but uses the cache_file option to specify a single file to cache. In order for this to work the MSP file needs to be in the same directory as the MSI file on the file_roots.
The final step to getting this to work is to add the additional /update flag to the install_flags parameter. Add the path to the MSP file using the %cd% environment variable. %cd% resolves to the current working directory which is the location in the minion cache where the installer file is cached.
See issue #32780 for more details.
This same approach could be used for applying MST files for MSIs and answer files for other types of .exe based installers.
Parameters These are the parameters that can be used to generate a software definition file. These parameters are all placed under the version in the software definition file:
Example usage can be found on the github repo
full_name (str) This is the full name for the software as shown in "Programs and Features" in the control panel. You can also get this information by installing the package manually and then running pkg.list_pkgs. Here's an example of the output from pkg.list_pkgs:
salt 'test-2008' pkg.list_pkgs test-2008 ---------- 7-Zip 9.20 (x64 edition): 9.20.00.0 Mozilla Firefox 74.0 (x64 en-US) 74.0 Mozilla Maintenance Service: 74.0 salt-minion-py3: 3001
Notice the Full Name for Firefox: Mozilla Firefox 74.0 (x64 en-US). That's exactly what should be in the full_name parameter in the software definition file.
If any of the software installed on the machine matches the full name defined in one of the software definition files in the repository the package name will be returned. The example below shows the pkg.list_pkgs for a machine that has Mozilla Firefox 74.0 installed and a software definition for that version of Firefox.
test-2008: ---------- 7zip: 9.20.00.0 Mozilla Maintenance Service: 74.0 firefox_x64: 74.0 salt-minion-py3: 3001
IMPORTANT: The version number and full_name need to match the output from pkg.list_pkgs exactly so that the installation status can be verified by the state system.
NOTE: It is still possible to successfully install packages using pkg.install, even if the full_name or the version number don't match exactly. The module will complete successfully, but continue to display the full name in pkg.list_pkgs. If this is happening, verify that the full_name and the version match exactly what is displayed in Add/Remove Programs.
TIP: To force Salt to display the full name when there's already an existing package definition file on the system, you can pass a bogus saltenv parameter to the command like so: pkg.list_pkgs saltenv=NotARealEnv
TIP: It's important use pkg.refresh_db to check for errors and ensure the latest package definition is on any minion you're testing new definitions on.
installer (str) This is the path to the binary (.exe, .msi) that will install the package. This can be a local path or a URL. If it is a URL or a Salt path (salt://), the package will be cached locally and then executed. If it is a path to a file on disk or a file share, it will be executed directly.
NOTE: When storing software in the same location as the winrepo it is usually best practice to place each installer in its own directory rather than in the root of winrepo.
Best practice is to create a sub folder named after the package. That folder will contain the software definition file named init.sls. The binary installer should be stored in that directory as well if you're hosting those files on the file_roots.
pkg.refresh_db will process all .sls files in all sub directories in the winrepo_dir_ng directory.
install_flags (str) This setting contains any flags that need to be passed to the installer to make it perform a silent install. These can often be found by adding /? or /h when running the installer from the command-line. A great resource for finding these silent install flags is the WPKG project wiki:
WARNING: Salt will appear to hang if the installer is expecting user input. So it is imperative that the software have the ability to install silently.
uninstaller (str) This is the path to the program used to uninstall this software. This can be the path to the same exe or msi used to install the software. Exe uninstallers are pretty straight forward. MSIs, on the other hand, can be handled a couple different ways. You can use the GUID for the software to uninstall or you can use the same MSI used to install the software.
You can usually find uninstall information in the registry:
• Software\Microsoft\Windows\CurrentVersion\Uninstall
• Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall
Here's an example using the GUID to uninstall software.
7zip: '9.20.00.0': full_name: 7-Zip 9.20 (x64 edition) installer: salt://win/repo-ng/7zip/7z920-x64.msi install_flags: '/qn /norestart' uninstaller: '{23170F69-40C1-2702-0920-000001000000}' uninstall_flags: '/qn /norestart' msiexec: True
Here's an example using the same MSI used to install the software:
7zip: '9.20.00.0': full_name: 7-Zip 9.20 (x64 edition) installer: salt://win/repo-ng/7zip/7z920-x64.msi install_flags: '/qn /norestart' uninstaller: salt://win/repo-ng/7zip/7z920-x64.msi uninstall_flags: '/qn /norestart' msiexec: True
uninstall_flags (str) This setting contains any flags that need to be passed to the uninstaller to make it perform a silent uninstall. These can often be found by adding /? or /h when running the uninstaller from the command-line. A great resource for finding these silent install flags the WPKG project wiki:
WARNING: Salt will appear to hang if the uninstaller is expecting user input. So it is imperative that the software have the ability to uninstall silently.
msiexec (bool, str) This tells Salt to use msiexec /i to install the package and msiexec /x to uninstall. This is for .msi installations only.
Possible options are:
• True
• False (default)
• the path to msiexec.exe on your system
7zip: '9.20.00.0': full_name: 7-Zip 9.20 (x64 edition) installer: salt://win/repo/7zip/7z920-x64.msi install_flags: '/qn /norestart' uninstaller: salt://win/repo/7zip/7z920-x64.msi uninstall_flags: '/qn /norestart' msiexec: 'C:\Windows\System32\msiexec.exe'
allusers (bool) This parameter is specific to .msi installations. It tells msiexec to install the software for all users. The default is True.