This chapter provides an introduction for using Salt Formulas with Uyuni. Creation of custom formulas will also be introduced.
Formulas are collections of Salt States that have been pre-written by other Salt users and contain generic parameter fields. Formulas allow for reliable reproduction of a specific configuration again and again. Formulas can be installed from RPM packages or an external git repository.
The following list will help you in making the decision to use a state or a formula.
When writing states for trivial tasks, formulas are probably not worth the time investment.
For large, non-trivial configurations use formulas.
Formulas and States both act as a kind of configuration documentation. Once written and stored you will have a snapshot of what your infrastructure should look like.
You can greatly decrease the amount of time required for writing a formula by grabbing one of the many pre-written formulas on github. There are pre-written formulas for hundreds of configurations. You can find these located at https://github.com/saltstack-formulas.
Formula data can now be managed via the XMLRPC API
New types were added to help SUSE Manager handle almost any kind of upstream formula.
SUSE releases formulas as RPM packages.
Available formulas can be located within the SUSE-Manager-Server-3.2-Pool channel.
To search for available formulas, execute the following command on your Uyuni server:
zypper se --type package formula
You will see a list of available Salt formulas:
S | Name | Summary | Type --+-------------------+------------------------------------------------------------+----------- | locale-formula | Locale Salt Formula for SUSE Manager | package
For more information about a formula, run the following command:
zypper info locale-formula
Information for package locale-formula:
-----------------------------------------
Repository: SUSE-Manager-Server-{productnumber}-Pool
Name: locale-formula
Version: 0.2-1.1
Arch: noarch
Vendor: SUSE LLC <https://www.suse.com/>
Support Level: Level 3
Status: not installed
Installed Size: 47.9 KiB
Installed: No
Source package : locale-formula-0.2-1.1.src
Summary : Locale Salt Formula for SUSE Manager
Description : Salt Formula for SUSE Manager. Sets up the locale.To install a formula run as root:
zypper in locale-formula
RPM-based formulas must be placed in a specific directory structure to ensure proper functionality.
A formula always consists of two separate directories: The states directory and the metadata directory.
Folders in these directories need to have an exactly matching name, for example locale.
The formula states directory contains anything necessary for a Salt state to work independently.
This includes .sls files, a map.jinja file and any other required files.
This directory should only be modified by RPMs and should not be edited manually.
For example, the locale-formula states directory is located in:
/usr/share/susemanager/formulas/states/locale/
The metadata directory contains a form.yml
file which defines the forms for Uyuni
and an optional metadata.yml
file that can contain additional information about a formula.
For example, the locale-formula
metadata directory is located in:
/usr/share/susemanager/formulas/metadata/locale/
Custom formula data or (non-RPM) formulas need to be placed into any state directory configured as a Salt file root:
Custom state formula data need to be placed in:
/srv/salt/custom/
Custom metadata (information) need to be placed in:
/srv/formula_metadata/custom/
All custom folders located in the following directories needs to contain a form.yml file.
These files are detected as form recipes and may be applied to groups and systems from the Web UI:
/srv/salt/formula_metadata/`custom-formula-name`/form.yml
Uyuni requires a file called form.yml, to describe how formula data should look within the Web UI.
form.yml is used by Uyuni to generate the desired form, with values editable by a user.
For example, the form.yml that is included with the locale-formula is placed in:
/usr/share/susemanager/formulas/metadata/locale/form.yml
See part of the following locale-formula example:
# This file is part of locale-formula.
#
# Foobar is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Foobar is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Foobar. If not, see <http://www.gnu.org/licenses/>.
timezone:
$type: group
name:
$type: select
$values: ["CET",
"CST6CDT",
"EET",
"EST",
"EST5EDT",
"GMT",
"GMT+0",
"GMT-0",
"GMT0",
"Greenwich",
"HST",
"MET",
"MST",
"MST7MDT",
"NZ",
"NZ-CHAT",
"Navajo",
"PST8PDT",
"UCT",
"UTC",
"Universal",
"W-SU",
"WET",
"Zulu",
"Etc/GMT+1",
"Etc/GMT+2",
"Etc/GMT+3",
"Etc/GMT+4",
"Etc/GMT+5",
"Etc/GMT+6",
"Etc/GMT+7",
"Etc/GMT+8",
"Etc/GMT+9",
"Etc/GMT+10",
"Etc/GMT+11",
"Etc/GMT+12",
"Etc/GMT-1",
"Etc/GMT-2",
"Etc/GMT-3",
"Etc/GMT-4",
"Etc/GMT-5",
"Etc/GMT-6",
"Etc/GMT-7",
"Etc/GMT-8",
"Etc/GMT-9",
"Etc/GMT-10",
"Etc/GMT-11",
"Etc/GMT-12",
"Etc/GMT-13",
"Etc/GMT-14",
"Etc/GMT",
"Etc/GMT+0",
"Etc/GMT-0",
"Etc/GMT0",
"Etc/Greenwich",
"Etc/UCT",
"Etc/UTC",
"Etc/Universal",
"Etc/Zulu"
]
$default: CET
hardware_clock_set_to_utc:
$type: boolean
$default: True
...form.yml contains additional information that describes how the form for a pillar should look for Uyuni.
This information is contained in attributes that always start with a $ sign.
All values that start with a $ sign are annotations used to display the UI that users interact with.
These annotations are not part of pillar data itself and are handled as metadata.
The following are valid attributes.
The most important attribute is the $type attribute.
It defines the type of the pillar value and the form-field that is generated.
The following represent the supported types:
text
password
number
url
email
date
time
datetime
boolean
color
select
group
edit-group
namespace
hidden-group (obsolete, renamed to namespace)
The text attribute is the default and does not need to be specified explicitly.
Many of these values are self-explanatory:
The text type generates a simple text field
The password type generates a password field
The color type generates a color picker.
The group, edit-group, and namespace (formerly hidden-group) types do not generate an editable field and are used to structure form and pillar data.
The difference between group and namespace is group generates a visible border with a heading, and namespace shows nothing visually (and is only used to structure pillar data).
The difference between group and edit-group is edit-group allows to structure and restrict editable fields in a more flexible way.
For example, edit-group supports the $minItems and $maxItems attributes, and thus it simplifies complex and repeatable input structures.
For an edit-group example, see Section 4.4.1, “Simple edit-group Example”.
$default allows you to specify a default value that is displayed and used, if no other value is entered.
In an edit-group it allows to create initial members of the group and populate them with specified data.
$name allows you to specify the name of a value that is shown in the form.
If this value is not set, the pillar name is used and capitalized without underscores and dashes.
You reference it in the same section with ${name}.
The $help and $placeholder attributes are used to give a user a better understanding of what the value should be.
$help defines the message a user sees when hovering over a field
$placeholder displays a gray placeholder text in the field.
$placeholder may only be used with text fields like text, password, email or date.
It does not make sense to add a placeholder if you also use $default as this will hide the placeholder.
In an edit-group, $minItems and $maxItems allow you to specify the lowest and highest number the group can occur.
In an edit-group, $itemName allows to define a template for the name to be used for the members of the group.
In an edit-group, $prototype allows to define default (or pre-filled) values for newly added members in the group.
$scope allows you to specify a hierarchy level at which a value may be edited.
Possible values are system, group and readonly.
The default $scope: system allows values to be edited at group and system levels.
A value can be entered for each system but if no value is entered the system will fall back to the group default.
If using $scope: group, a value may only be edited for a group.
On the system level you will be able to see the value, but not edit it.
The $scope: readonly option makes a field read-only.
It can be used to show a user data which should be known, but should not be editable.
This option only makes sense in combination with the $default attribute.
$visibleIf allows you to show a field or group if a simple condition is met.
A condition always looks similar to the following example:
some_group#another_group#my_checkbox == true
The left part of the above statement is the path to another value, and groups are separated by $ signs.
The middle section of the command should be either == for a value to be equal or != for values that should be not equal.
The last field in the statement can be any value which a field should have or not have.
The field with this attribute associated with it will now be shown only when the condition is met.
In this example the field will be shown only if my_checkbox is checked.
The ability to use conditional statements is not limited to check boxes.
It may also be used to check values of select-fields, text-fields, etc.
A check box should be structured like the following example:
some_group:
$type: group
another_group:
$type: group
my_checkbox:
$type: booleanRelative paths can be specified using prefix dots. One dot means sibling, 2 dots mean parent, etc. This is mostly useful for edit-group.
some_group:
$type: group
another_group:
$type: group
my_checkbox:
$type: boolean
my_text:
$visibleIf: .my_checkbox
yet_another_group:
$type: group
my_text2:
$visibleIf: ..another_group#my_checkboxBy using multiple groups with the attribute, you can allow a user to select an option and show a completely different form, dependent upon the selected value.
Values from hidden fields may be merged into the pillar data and sent to the minion. A formula must check the condition again and use the appropriate data. For example:
show_option: $type: checkbox some_text: $visibleIf: show_option == true
{% if pillar.show_option %}
do_something:
with: {{ pillar.some_text }}
{% endif %}$values can only be used together with $type: select to specify the different options in the select-field.
$values must be a list of possible values to select.
For example:
select_something: $type: select $values: ["option1", "option2"]
Or alternatively:
select_something:
$type: select
$values:
- option1
- option2See the following edit-group example:
partitions:
$name: "Hard Disk Partitions"
$type: "edit-group"
$minItems: 1
$maxItems: 4
$itemName: "Partition ${name}"
$prototype:
name:
$default: "New partition"
mountpoint:
$default: "/var"
size:
$type: "number"
$name: "Size in GB"
$default:
- name: "Boot"
mountpoint: "/boot"
- name: "Root"
mountpoint: "/"
size: 5000After clicking for one time you will see Figure 4.1, “edit-group Example in the Web UI” filled with the default values.
The formula itself is called hd-partitions and will appear as Hd Partitions in the Web UI.
edit-group Example in the Web UI #To remove definition of a partition click the minus symbol in the title line of an inner group. When form fields are properly filled confirm with clicking in the upper right corner of the formula.
Salt formulas are pre-written Salt states, which may be configured with pillar data. You can parametrize state files using Jinja. Jinja allows you to access pillar data by using the following syntax. (This syntax works best when your uncertain a pillar value exists as it will throw an error):
pillar.some.value
When you are sure a pillar exists may also use the following syntax:
salt['pillar.get']('some:value', 'default value')You may also replace the pillar value with grains (for example, grains.some.value) allowing access to grains.
Using data this way allows you to make a formula configurable.
The following code snippet will install a package specified in the pillar package_name.
For example:
install_a_package:
pkg.installed:
- name: {{ pillar.package_name }}You may also use more complex constructs such as if/else and for-loops to provide greater functionality.
For Example:
{% if pillar.installSomething %}
something:
pkg.installed
{% else %}
anotherPackage:
pkg.installed
{% endif %}Another example:
{% for service in pillar.services %}
start_{{ service }}:
service.running:
- name: {{ service }}
{% endfor %}Jinja also provides other helpful functions. For example, you can iterate over a dictionary:
{% for key, value in some_dictionary.items() %}
do_something_with_{{ key }}: {{ value }}
{% endfor %}You may want to have Salt manage your files (for example, configuration files for a program), and you can change these with pillar data. For example, the following snippet shows how you can manage a file using Salt:
/etc/my_program/my_program.conf:
file.managed:
- source: salt://my_state/files/my_program.conf
- template: jinjaSalt will copy the file salt-file_roots/my_state/files/my_program.conf on the salt master to /etc/my_program/my_program.conf on the minion and template it with Jinja.
This allows you to use Jinja in the file, exactly like shown above for states:
some_config_option = {{ pillar.config_option_a }}It is often a good idea to separate data from a state to increase its flexibility and add re-usability value.
This is often done by writing values into a separate file named map.jinja.
This file should be placed within the same directory as your state files.
The following example will set data to a dictionary with different values, depending on which system the state runs on.
It will also merge data with the pillar using the some.pillar.data value so you can access some.pillar.data.value by just using data.value.
You can also choose to override defined values from pillars (for example, by overriding some.pillar.data.package in the example).
{% set data = salt['grains.filter_by']({
'Suse': {
'package': 'packageA',
'service': 'serviceA'
},
'RedHat': {
'package': 'package_a',
'service': 'service_a'
}
}, merge=salt['pillar.get']('some:pillar:data')) %}After creating a map file like the above example, you can easily maintain compatibility with multiple system types while accessing "deep" pillar data in a simpler way.
Now you can import and use data in any file.
For example:
{% from "some_folder/map.jinja" import data with context %}
install_package_a:
pkg.installed:
- name: {{ data.package }}You can also define multiple variables by copying the {% set …%} statement with different values and then merge it with other pillars.
For example:
{% set server = salt['grains.filter_by']({
'Suse': {
'package': 'my-server-pkg'
}
}, merge=salt['pillar.get']('myFormula:server')) %}
{% set client = salt['grains.filter_by']({
'Suse': {
'package': 'my-client-pkg'
}
}, merge=salt['pillar.get']('myFormula:client')) %}To import multiple variables, separate them with a comma. For Example:
{% from "map.jinja" import server, client with context %}Formulas utilized with Uyuni should follow formula conventions listed in the official documentation:
When pillar data is generated (for example, after applying the highstate) the following external pillar script generates pillar data for packages, group ids, etc. and includes all pillar data for a system:
/usr/share/susemanager/modules/pillar/suma_minion.py
The process is executed as follows:
The suma_minion.py script starts and finds all formulas for a system (by checking the group_formulas.json and server_formulas.json files).
suma_minion.py loads the values for each formula (groups and from the system) and merges them with the highstate (default: if no values are found, a group overrides a system if $scope: group etc.).
suma_minion.py also includes a list of formulas applied to the system in a pillar named formulas.
This structure makes it possible to include states.
The top file (in this case specifically generated by the mgr_master_tops.py script) includes a state called formulas for each system.
This includes the formulas.sls file located in:
/usr/share/susemanager/formulas/states/
The content looks similar to the following:
include: {{ pillar["formulas"] }}This pillar includes all formulas, that are specified in pillar data generated from the external pillar script.
Formulas should be designed/created directly after a Uyuni installation, but if you encounter any issues check the following:
The external pillar script (suma_minion.py) must include formula data.
Data is saved to /srv/susemanager/formula_data and the pillar and group_pillar sub-directories.
These should be automatically generated by the server.
Formulas must be included for every minion listed in the top file.
Currently this process is initiated by the mgr_master_tops.py script which includes the formulas.sls file located in:
/usr/share/susemanager/formulas/states/
This directory must be a salt file root. File roots are configured on the salt-master (Uyuni) located in:
/etc/salt/master.d/susemanager.conf
The following procedure provides an overview on using Salt Formulas with Uyuni.
Official formulas may be installed as RPMs.
Place the custom states within /srv/salt/your-formula-name/ and the metadata (form.yml and metadata.yml) in /srv/formula_metadata/your-formula-name/.
After installing your formulas they will appear in › .
To begin using a formula, apply it to a group or system.
Apply a formula to a group or system by selecting the › tab of a System Details page or System Group. From the › page you can select any formulas you wish to apply to a group or system.
Click the button to save your changes to the database.
After applying one or more formulas to a group or system, additional tabs will become available from the top menu, one for each formula selected. From these tabs you may configure your formulas.
When you have finished customizing your formula values you will need to apply the highstate for them to take effect. Applying the highstate will execute the state associated with the formula and configure targeted systems. You can use the button from any formulas page of a group.
When a change to any of your values is required or you need to re-apply the formula state because of a failure or bug, change values located on your formula pages and re-apply the highstate. Salt will ensure that only modified values are adjusted and restart or reinstall services only when necessary.
This conclude your introduction to Salt Formulas. For additional information, see:
= SUSE Manager for Retail Salt Formulas
This section provides an introduction to Salt Formulas shipped with SUSE Manager for Retail. These formulas such as the PXE boot, branch server network, or saltboot formulas are used to fine-tune the SUSE Manager for Retail infrastructure.
== Pxe Formula
The Pxe formula (pxe-formula) for installing, setting up, and uninstalling syslinux PXE boot on the POS branchserver.
== Branch Network Formula
The Branch Network formula (branch-network-formula) for configuring the branch server network.
== Saltboot Formula
The Saltboot formula (saltboot-formula) is a formula for configuring a boot image of a POS terminal.
Then you configure one or more partitions:
== Image Sync Formula
The Image Sync formula (image-sync-formula) is a formula for syncing images to a Branch Server.
For now, there is nothing configurable and it is not part of the highstate. This means it is not visible in the Web UI. Apply it from the command-line or via cron as follows (replace <branchserver> with the name of your branch server):
salt <branchserver> state.apply image-sync
== Salt Formulas Coming with SUSE Manager
For general information, see the Salt Formulas installation and usage instructions at https://docs.saltstack.com/en/latest/topics/development/conventions/formulas.html.
=== Domain Name System (Bind)
With the bind formula you set up and configure a Domain Name System (DNS) server.
For technical information about the bind formula and low-level pillar data, see the README.rst file on the Uyuni server: /usr/share/susemanager/formulas/metadata/bind/README.rst.
DNS is needed to resolve the domain names and host names into IP addresses. For more information about DNS, see the SLES Administration Guide, Services, The Domain Name System.
In the Config group you can set arbitrary options such as directory where are the zone data files (usually /var/lib/named/) or forwarders.
Click to provide more Key/Value fields for configuration.
Check Include Forwarders if you want to rely on an external DNS server if your DNS is down (or is otherwise not able to resolve an address).
At least, you will configure one zone. In Configured Zones define
your zone; for example, example.com. Then in Available Zones
configure this zone: as Name enter your zone (in this case
example.com) and the File to which this configuration should be
written (example.com.txt). Enter the mandatory SOA record (start
of authority), and the A, NS, and CNAME Records you need.
On the other hand, if no records entry exists, the zone file is not generated by this state rather than taken from salt://zones. For how to overwrite
this URL, see pillar.example.
In Generate Reverse, and define reverse mapping and for which zones:
When saved, data is written to /srv/susemanager/formula_data/pillar/<salt-minion.example.com>_bind.json
If you apply the highstate ( › › ), it first ensures that bind and all required packages will get installed.
Then it will start the DNS service (named).
=== Dhcpd
With the dhcpd formula you set up and configure a DHCP server (Dynamic Host Configuration Protocol).
For technical information about the dhcpd formula and low-level pillar data, see the Pillar example file
/usr/share/susemanager/formulas/metadata/dhcpd/pillar.example.
DHCP is needed to define network settings centrally (on a server) and let clients retrieve and use this information for local host configuration. For more information about DHCP, see the SLES Administration Guide, Services, DHCP.
Domain Name.
Domain Name Servers. One or more Domain Name Service (DNS) servers.
On which interface(s) the DHCP server should listen (Listen interfaces).
Set option for this interface:
Authoritative:
Max Lease Time:
Default Lease Time:
Next is at least one network in the Network configuration (subnet) group (with IP address, netmask, etc.). You define every network with Dynamic IP range, Routers, and Hosts with static IP addresses (with defaults from subnet) (optionally).
And finally Hosts with static IP addresses (with global defaults).
If you apply the highstate ( › › ), it first ensures that dhcp-server and all required packages will get installed.
Then it will start the DHCP service (dhcpd).
=== Tftpd
With the tftpd formula you set up and configure a TFTP server (Trivial File Transfer Protocol). A TFTP server is a component that provides infrastructure for booting with PXE.
For more information about setting up TFTP, see the SLES Deployment Guide, Preparing Network Boot Environment, Setting Up a TFTP Server.
For setting up a TFTP server, specify the Internal Network Address,
TFTP base directory (default: /srv/tftpboot), and run
TFTP under user (default: sftp).
If you apply the highstate ( › › ), it first ensures that atftp and all required packages will get installed.
Then it will start TFTP (atftpd).
=== Vsftpd
With the vsftpd formula you set up and configure Vsftpd. Vsftpd is an FTP server or daemon, written with security in mind. "vs" in its name stands for "Very Secure".
For configuring a VSFTP server, specify the settings and options in the Vsftpd formula. There are settings such as
FTP server directory,
Internal Network Address
Enable ssl, etc.
If you apply the highstate ( › › ), it first ensures that vsftpd and all required packages will get installed.
Then it will start the VSFTP service (vsftpd).
For more information about setting up and tuning Vsftpd, see the documentation coming with the vsftpd package (/usr/share/doc/packages/vsftpd/ when the package is installed).
<<<<<<< HEAD
>>>>>>> eadc4168… Removed entities from top of files, added a single include, added missing entities for retail
>>>>>>> eadc4168… Removed entities from top of files, added a single include, added missing entities for retail