golden hour
/opt/saltstack/salt/lib/python3.10/site-packages/salt/states
⬆️ Go Up
Upload
File/Folder
Size
Actions
__init__.py
25 B
Del
OK
__pycache__
-
Del
OK
acme.py
5.08 KB
Del
OK
alias.py
2.49 KB
Del
OK
alternatives.py
6.75 KB
Del
OK
ansiblegate.py
7.93 KB
Del
OK
apache.py
3.95 KB
Del
OK
apache_conf.py
2.72 KB
Del
OK
apache_module.py
2.73 KB
Del
OK
apache_site.py
2.66 KB
Del
OK
aptpkg.py
1.42 KB
Del
OK
archive.py
68.24 KB
Del
OK
artifactory.py
6.84 KB
Del
OK
at.py
7.48 KB
Del
OK
augeas.py
10.57 KB
Del
OK
aws_sqs.py
2.59 KB
Del
OK
azurearm_compute.py
11.78 KB
Del
OK
azurearm_dns.py
26.05 KB
Del
OK
azurearm_network.py
89.12 KB
Del
OK
azurearm_resource.py
28.23 KB
Del
OK
beacon.py
7.58 KB
Del
OK
bigip.py
96.63 KB
Del
OK
blockdev.py
5.13 KB
Del
OK
boto3_elasticache.py
48.01 KB
Del
OK
boto3_elasticsearch.py
32.58 KB
Del
OK
boto3_route53.py
37.54 KB
Del
OK
boto3_sns.py
12.69 KB
Del
OK
boto_apigateway.py
82.83 KB
Del
OK
boto_asg.py
31.93 KB
Del
OK
boto_cfn.py
11.53 KB
Del
OK
boto_cloudfront.py
6.01 KB
Del
OK
boto_cloudtrail.py
13.18 KB
Del
OK
boto_cloudwatch_alarm.py
6.4 KB
Del
OK
boto_cloudwatch_event.py
12.33 KB
Del
OK
boto_cognitoidentity.py
13.69 KB
Del
OK
boto_datapipeline.py
18.5 KB
Del
OK
boto_dynamodb.py
29.32 KB
Del
OK
boto_ec2.py
71.98 KB
Del
OK
boto_elasticache.py
16.75 KB
Del
OK
boto_elasticsearch_domain.py
12.27 KB
Del
OK
boto_elb.py
55.1 KB
Del
OK
boto_elbv2.py
12.19 KB
Del
OK
boto_iam.py
69.16 KB
Del
OK
boto_iam_role.py
27.12 KB
Del
OK
boto_iot.py
25.33 KB
Del
OK
boto_kinesis.py
16.69 KB
Del
OK
boto_kms.py
12.11 KB
Del
OK
boto_lambda.py
35.52 KB
Del
OK
boto_lc.py
11.04 KB
Del
OK
boto_rds.py
26 KB
Del
OK
boto_route53.py
19.49 KB
Del
OK
boto_s3.py
9.32 KB
Del
OK
boto_s3_bucket.py
24.67 KB
Del
OK
boto_secgroup.py
32.62 KB
Del
OK
boto_sns.py
8.92 KB
Del
OK
boto_sqs.py
7.97 KB
Del
OK
boto_vpc.py
62.23 KB
Del
OK
bower.py
8.26 KB
Del
OK
btrfs.py
10.34 KB
Del
OK
cabal.py
5.73 KB
Del
OK
ceph.py
1.9 KB
Del
OK
chef.py
3.76 KB
Del
OK
chocolatey.py
16.15 KB
Del
OK
chronos_job.py
4.6 KB
Del
OK
cimc.py
14.32 KB
Del
OK
cisconso.py
3.14 KB
Del
OK
cloud.py
14.4 KB
Del
OK
cmd.py
40.92 KB
Del
OK
composer.py
8.38 KB
Del
OK
consul.py
5.4 KB
Del
OK
cron.py
23.39 KB
Del
OK
cryptdev.py
6.17 KB
Del
OK
csf.py
9.98 KB
Del
OK
cyg.py
7.05 KB
Del
OK
ddns.py
4.2 KB
Del
OK
debconfmod.py
6.33 KB
Del
OK
dellchassis.py
24.49 KB
Del
OK
disk.py
6.49 KB
Del
OK
docker_container.py
85.27 KB
Del
OK
docker_image.py
16.7 KB
Del
OK
docker_network.py
36.78 KB
Del
OK
docker_volume.py
6.72 KB
Del
OK
drac.py
4.17 KB
Del
OK
dvs.py
26.29 KB
Del
OK
elasticsearch.py
20.38 KB
Del
OK
elasticsearch_index.py
3.25 KB
Del
OK
elasticsearch_index_template.py
3.67 KB
Del
OK
environ.py
5.81 KB
Del
OK
eselect.py
2.27 KB
Del
OK
esxcluster.py
22.4 KB
Del
OK
esxdatacenter.py
4.44 KB
Del
OK
esxi.py
63.07 KB
Del
OK
esxvm.py
20.11 KB
Del
OK
etcd_mod.py
11 KB
Del
OK
ethtool.py
9.88 KB
Del
OK
event.py
2.48 KB
Del
OK
file.py
316.7 KB
Del
OK
firewall.py
1.33 KB
Del
OK
firewalld.py
26.08 KB
Del
OK
gem.py
7.13 KB
Del
OK
git.py
123.85 KB
Del
OK
github.py
27.25 KB
Del
OK
glance_image.py
2.26 KB
Del
OK
glassfish.py
21.47 KB
Del
OK
glusterfs.py
12.21 KB
Del
OK
gnomedesktop.py
7.47 KB
Del
OK
gpg.py
5.28 KB
Del
OK
grafana.py
12.11 KB
Del
OK
grafana4_dashboard.py
17.31 KB
Del
OK
grafana4_datasource.py
6.15 KB
Del
OK
grafana4_org.py
7.73 KB
Del
OK
grafana4_user.py
5.52 KB
Del
OK
grafana_dashboard.py
17.74 KB
Del
OK
grafana_datasource.py
5.31 KB
Del
OK
grains.py
15.57 KB
Del
OK
group.py
9.84 KB
Del
OK
heat.py
9.69 KB
Del
OK
helm.py
10.39 KB
Del
OK
hg.py
6.33 KB
Del
OK
highstate_doc.py
1.41 KB
Del
OK
host.py
8.64 KB
Del
OK
http.py
7.46 KB
Del
OK
icinga2.py
9.07 KB
Del
OK
idem.py
3.91 KB
Del
OK
ifttt.py
2.12 KB
Del
OK
incron.py
5.71 KB
Del
OK
influxdb08_database.py
2.85 KB
Del
OK
influxdb08_user.py
3.39 KB
Del
OK
influxdb_continuous_query.py
2.83 KB
Del
OK
influxdb_database.py
2.11 KB
Del
OK
influxdb_retention_policy.py
4.82 KB
Del
OK
influxdb_user.py
4.84 KB
Del
OK
infoblox_a.py
4.24 KB
Del
OK
infoblox_cname.py
4.19 KB
Del
OK
infoblox_host_record.py
6.59 KB
Del
OK
infoblox_range.py
6.85 KB
Del
OK
ini_manage.py
12.67 KB
Del
OK
ipmi.py
8.42 KB
Del
OK
ipset.py
9.66 KB
Del
OK
iptables.py
27.65 KB
Del
OK
jboss7.py
23.95 KB
Del
OK
jenkins.py
3.36 KB
Del
OK
junos.py
17.78 KB
Del
OK
kapacitor.py
6.46 KB
Del
OK
kernelpkg.py
6.42 KB
Del
OK
keyboard.py
2.01 KB
Del
OK
keystone.py
27.12 KB
Del
OK
keystone_domain.py
2.81 KB
Del
OK
keystone_endpoint.py
4.69 KB
Del
OK
keystone_group.py
3.25 KB
Del
OK
keystone_project.py
3.36 KB
Del
OK
keystone_role.py
2.33 KB
Del
OK
keystone_role_grant.py
4.08 KB
Del
OK
keystone_service.py
2.89 KB
Del
OK
keystone_user.py
3.47 KB
Del
OK
keystore.py
5.67 KB
Del
OK
kmod.py
8.59 KB
Del
OK
kubernetes.py
24.87 KB
Del
OK
layman.py
2.44 KB
Del
OK
ldap.py
19.78 KB
Del
OK
libcloud_dns.py
5.7 KB
Del
OK
libcloud_loadbalancer.py
5.66 KB
Del
OK
libcloud_storage.py
5.13 KB
Del
OK
linux_acl.py
24.42 KB
Del
OK
locale.py
2.52 KB
Del
OK
logadm.py
4.67 KB
Del
OK
logrotate.py
3.86 KB
Del
OK
loop.py
7.74 KB
Del
OK
lvm.py
13.33 KB
Del
OK
lvs_server.py
6.28 KB
Del
OK
lvs_service.py
4.38 KB
Del
OK
lxc.py
22.17 KB
Del
OK
lxd.py
7.88 KB
Del
OK
lxd_container.py
22.25 KB
Del
OK
lxd_image.py
10.59 KB
Del
OK
lxd_profile.py
7.11 KB
Del
OK
mac_assistive.py
1.55 KB
Del
OK
mac_keychain.py
5.59 KB
Del
OK
mac_xattr.py
3.15 KB
Del
OK
macdefaults.py
2.65 KB
Del
OK
macpackage.py
6.76 KB
Del
OK
makeconf.py
6.87 KB
Del
OK
marathon_app.py
4.45 KB
Del
OK
mdadm_raid.py
6.41 KB
Del
OK
memcached.py
3.95 KB
Del
OK
modjk.py
2.84 KB
Del
OK
modjk_worker.py
6.49 KB
Del
OK
module.py
18.64 KB
Del
OK
mongodb_database.py
1.65 KB
Del
OK
mongodb_user.py
6.26 KB
Del
OK
monit.py
2.68 KB
Del
OK
mount.py
50.32 KB
Del
OK
mssql_database.py
3 KB
Del
OK
mssql_login.py
3.64 KB
Del
OK
mssql_role.py
2.37 KB
Del
OK
mssql_user.py
3.51 KB
Del
OK
msteams.py
2.53 KB
Del
OK
mysql_database.py
6.05 KB
Del
OK
mysql_grants.py
8.49 KB
Del
OK
mysql_query.py
13.07 KB
Del
OK
mysql_user.py
9.51 KB
Del
OK
net_napalm_yang.py
9.15 KB
Del
OK
netacl.py
31.92 KB
Del
OK
netconfig.py
33.42 KB
Del
OK
netntp.py
12.51 KB
Del
OK
netsnmp.py
11.33 KB
Del
OK
netusers.py
16.1 KB
Del
OK
network.py
23.97 KB
Del
OK
neutron_network.py
3.96 KB
Del
OK
neutron_secgroup.py
4 KB
Del
OK
neutron_secgroup_rule.py
4.75 KB
Del
OK
neutron_subnet.py
4.29 KB
Del
OK
nexus.py
4.97 KB
Del
OK
nfs_export.py
4.92 KB
Del
OK
nftables.py
19.5 KB
Del
OK
npm.py
11.21 KB
Del
OK
ntp.py
2.12 KB
Del
OK
nxos.py
10.37 KB
Del
OK
nxos_upgrade.py
3.5 KB
Del
OK
openstack_config.py
3.26 KB
Del
OK
openvswitch_bridge.py
4.36 KB
Del
OK
openvswitch_db.py
2.24 KB
Del
OK
openvswitch_port.py
17.24 KB
Del
OK
opsgenie.py
4.07 KB
Del
OK
pagerduty.py
1.89 KB
Del
OK
pagerduty_escalation_policy.py
5.42 KB
Del
OK
pagerduty_schedule.py
6.09 KB
Del
OK
pagerduty_service.py
3.93 KB
Del
OK
pagerduty_user.py
1.18 KB
Del
OK
panos.py
48.13 KB
Del
OK
pbm.py
20.46 KB
Del
OK
pcs.py
36.46 KB
Del
OK
pdbedit.py
3.43 KB
Del
OK
pecl.py
3.65 KB
Del
OK
pip_state.py
38.55 KB
Del
OK
pkg.py
138.08 KB
Del
OK
pkgbuild.py
11.37 KB
Del
OK
pkgng.py
685 B
Del
OK
pkgrepo.py
27.53 KB
Del
OK
portage_config.py
5.01 KB
Del
OK
ports.py
5.65 KB
Del
OK
postgres_cluster.py
4.19 KB
Del
OK
postgres_database.py
6.08 KB
Del
OK
postgres_extension.py
5.68 KB
Del
OK
postgres_group.py
8.52 KB
Del
OK
postgres_initdb.py
2.84 KB
Del
OK
postgres_language.py
3.94 KB
Del
OK
postgres_privileges.py
7.86 KB
Del
OK
postgres_schema.py
4.34 KB
Del
OK
postgres_tablespace.py
6.62 KB
Del
OK
postgres_user.py
9.49 KB
Del
OK
powerpath.py
2.34 KB
Del
OK
probes.py
15.06 KB
Del
OK
process.py
1.32 KB
Del
OK
proxy.py
4.94 KB
Del
OK
pushover.py
3.13 KB
Del
OK
pyenv.py
6.07 KB
Del
OK
pyrax_queues.py
2.97 KB
Del
OK
quota.py
1.4 KB
Del
OK
rabbitmq_cluster.py
1.84 KB
Del
OK
rabbitmq_plugin.py
2.77 KB
Del
OK
rabbitmq_policy.py
4.59 KB
Del
OK
rabbitmq_upstream.py
7.9 KB
Del
OK
rabbitmq_user.py
8.89 KB
Del
OK
rabbitmq_vhost.py
3.04 KB
Del
OK
rbac_solaris.py
6.67 KB
Del
OK
rbenv.py
7.36 KB
Del
OK
rdp.py
1.28 KB
Del
OK
redismod.py
4.76 KB
Del
OK
reg.py
19.22 KB
Del
OK
restconf.py
6.41 KB
Del
OK
rsync.py
4.45 KB
Del
OK
rvm.py
6.56 KB
Del
OK
salt_proxy.py
1.34 KB
Del
OK
saltmod.py
33.12 KB
Del
OK
saltutil.py
8.91 KB
Del
OK
schedule.py
12.47 KB
Del
OK
selinux.py
18.61 KB
Del
OK
serverdensity_device.py
6.41 KB
Del
OK
service.py
37.89 KB
Del
OK
slack.py
4.98 KB
Del
OK
smartos.py
44.83 KB
Del
OK
smtp.py
2.3 KB
Del
OK
snapper.py
7.24 KB
Del
OK
solrcloud.py
4.48 KB
Del
OK
splunk.py
4.32 KB
Del
OK
splunk_search.py
3.17 KB
Del
OK
sqlite3.py
14.7 KB
Del
OK
ssh_auth.py
19.57 KB
Del
OK
ssh_known_hosts.py
7.92 KB
Del
OK
stateconf.py
494 B
Del
OK
status.py
2.21 KB
Del
OK
statuspage.py
17.29 KB
Del
OK
supervisord.py
10.48 KB
Del
OK
svn.py
8.14 KB
Del
OK
sysctl.py
4.11 KB
Del
OK
sysfs.py
2.13 KB
Del
OK
syslog_ng.py
2.97 KB
Del
OK
sysrc.py
2.82 KB
Del
OK
telemetry_alert.py
7.04 KB
Del
OK
test.py
13.09 KB
Del
OK
testinframod.py
1.35 KB
Del
OK
timezone.py
3.42 KB
Del
OK
tls.py
1.81 KB
Del
OK
tomcat.py
9.72 KB
Del
OK
trafficserver.py
8.82 KB
Del
OK
tuned.py
3.32 KB
Del
OK
uptime.py
1.87 KB
Del
OK
user.py
38.63 KB
Del
OK
vagrant.py
11.4 KB
Del
OK
vault.py
3.28 KB
Del
OK
vbox_guest.py
4.05 KB
Del
OK
victorops.py
3.32 KB
Del
OK
virt.py
80.41 KB
Del
OK
virtualenv_mod.py
11.21 KB
Del
OK
webutil.py
3.89 KB
Del
OK
win_certutil.py
4.8 KB
Del
OK
win_dacl.py
7.96 KB
Del
OK
win_dism.py
14.97 KB
Del
OK
win_dns_client.py
8.32 KB
Del
OK
win_firewall.py
6.87 KB
Del
OK
win_iis.py
31.56 KB
Del
OK
win_lgpo.py
24.99 KB
Del
OK
win_lgpo_reg.py
10.96 KB
Del
OK
win_license.py
1.6 KB
Del
OK
win_network.py
14.18 KB
Del
OK
win_path.py
6.39 KB
Del
OK
win_pki.py
5.56 KB
Del
OK
win_powercfg.py
3.79 KB
Del
OK
win_servermanager.py
10.4 KB
Del
OK
win_shortcut.py
7.81 KB
Del
OK
win_smtp_server.py
10.01 KB
Del
OK
win_snmp.py
6.64 KB
Del
OK
win_system.py
13.78 KB
Del
OK
win_wua.py
16.27 KB
Del
OK
win_wusa.py
3.53 KB
Del
OK
winrepo.py
2.74 KB
Del
OK
wordpress.py
4.82 KB
Del
OK
x509.py
27.86 KB
Del
OK
x509_v2.py
64.78 KB
Del
OK
xml.py
1.75 KB
Del
OK
xmpp.py
2.61 KB
Del
OK
zabbix_action.py
9.35 KB
Del
OK
zabbix_host.py
27.25 KB
Del
OK
zabbix_hostgroup.py
5.64 KB
Del
OK
zabbix_mediatype.py
16.89 KB
Del
OK
zabbix_template.py
35.14 KB
Del
OK
zabbix_user.py
17.6 KB
Del
OK
zabbix_usergroup.py
9.64 KB
Del
OK
zabbix_usermacro.py
9.69 KB
Del
OK
zabbix_valuemap.py
8.11 KB
Del
OK
zcbuildout.py
5.16 KB
Del
OK
zenoss.py
2.89 KB
Del
OK
zfs.py
34.48 KB
Del
OK
zk_concurrency.py
5.81 KB
Del
OK
zone.py
46.48 KB
Del
OK
zookeeper.py
11.55 KB
Del
OK
zpool.py
13.4 KB
Del
OK
Edit: saltmod.py
""" Control the Salt command interface ================================== This state is intended for use from the Salt Master. It provides access to sending commands down to minions as well as access to executing master-side modules. These state functions wrap Salt's :ref:`Python API <python-api>`. .. versionadded:: 2016.11.0 Support for masterless minions was added to the ``salt.state`` function, so they can run orchestration sls files. This is particularly useful when the rendering of a state is dependent on the execution of another state. Orchestration will render and execute each orchestration block independently, while honoring requisites to ensure the states are applied in the correct order. .. seealso:: More Orchestrate documentation * :ref:`Full Orchestrate Tutorial <orchestrate-runner>` * :py:func:`The Orchestrate runner <salt.runners.state.orchestrate>` """ import fnmatch import logging import sys import threading import time import salt.exceptions import salt.output import salt.syspaths import salt.utils.data import salt.utils.event import salt.utils.versions from salt.features import features log = logging.getLogger(__name__) # Define the module's virtual name __virtualname__ = "salt" def __virtual__(): """ Named salt """ return __virtualname__ def _fire_args(tag_data): try: salt.utils.event.fire_args(__opts__, __orchestration_jid__, tag_data, "run") except NameError: log.debug("Unable to fire args event due to missing __orchestration_jid__") def _parallel_map(func, inputs): """ Applies a function to each element of a list, returning the resulting list. A separate thread is created for each element in the input list and the passed function is called for each of the elements. When all threads have finished execution a list with the results corresponding to the inputs is returned. If one of the threads fails (because the function throws an exception), that exception is reraised. If more than one thread fails, the exception from the first thread (according to the index of the input element) is reraised. func: function that is applied on each input element. inputs: list of elements that shall be processed. The length of this list also defines the number of threads created. """ outputs = len(inputs) * [None] errors = len(inputs) * [None] def create_thread(index): def run_thread(): try: outputs[index] = func(inputs[index]) except: # pylint: disable=bare-except errors[index] = sys.exc_info() thread = threading.Thread(target=run_thread) thread.start() return thread threads = list(map(create_thread, range(len(inputs)))) for thread in threads: thread.join() for error in errors: if error is not None: exc_type, exc_value, exc_traceback = error raise exc_value.with_traceback(exc_traceback) return outputs def state( name, tgt, ssh=False, tgt_type="glob", ret="", ret_config=None, ret_kwargs=None, highstate=None, sls=None, top=None, saltenv=None, test=None, pillar=None, pillarenv=None, expect_minions=True, exclude=None, fail_minions=None, allow_fail=0, concurrent=False, timeout=None, batch=None, queue=False, subset=None, orchestration_jid=None, failhard=None, **kwargs, ): """ Invoke a state run on a given target name An arbitrary name used to track the state execution tgt The target specification for the state run. .. versionadded:: 2016.11.0 Masterless support: When running on a masterless minion, the ``tgt`` is ignored and will always be the local minion. tgt_type The target type to resolve, defaults to ``glob`` ret Optionally set a single or a list of returners to use ret_config Use an alternative returner configuration ret_kwargs Override individual returner configuration items highstate Defaults to None, if set to True the target systems will ignore any sls references specified in the sls option and call state.highstate on the targeted minions top Should be the name of a top file. If set state.top is called with this top file instead of state.sls. sls A group of sls files to execute. This can be defined as a single string containing a single sls file, or a list of sls files test Pass ``test=true`` or ``test=false`` through to the state function. This can be used to override a test mode set in the minion's config file. If left as the default of None and the 'test' mode is supplied on the command line, that value is passed instead. pillar Pass the ``pillar`` kwarg through to the state function pillarenv The pillar environment to grab pillars from .. versionadded:: 2017.7.0 saltenv The default salt environment to pull sls files from ssh Set to `True` to use the ssh client instead of the standard salt client roster In the event of using salt-ssh, a roster system can be set expect_minions An optional boolean for failing if some minions do not respond fail_minions An optional list of targeted minions where failure is an option allow_fail Pass in the number of minions to allow for failure before setting the result of the execution to False exclude Pass exclude kwarg to state concurrent Allow multiple state runs to occur at once. WARNING: This flag is potentially dangerous. It is designed for use when multiple state runs can safely be run at the same Do not use this flag for performance optimization. queue Pass ``queue=true`` through to the state function batch Execute the command :ref:`in batches <targeting-batch>`. E.g.: ``10%``. .. versionadded:: 2016.3.0 subset Number of minions from the targeted set to randomly use .. versionadded:: 2017.7.0 failhard pass failhard down to the executing state .. versionadded:: 2019.2.2 Examples: Run a list of sls files via :py:func:`state.sls <salt.state.sls>` on target minions: .. code-block:: yaml webservers: salt.state: - tgt: 'web*' - sls: - apache - django - core - saltenv: prod Run sls file via :py:func:`state.sls <salt.state.sls>` on target minions with exclude: .. code-block:: yaml docker: salt.state: - tgt: 'docker*' - sls: docker - exclude: docker.swarm - saltenv: prod Run a full :py:func:`state.highstate <salt.state.highstate>` on target mininons. .. code-block:: yaml databases: salt.state: - tgt: role:database - tgt_type: grain - highstate: True """ cmd_kw = {"arg": [], "kwarg": {}, "ret": ret, "timeout": timeout} if ret_config: cmd_kw["ret_config"] = ret_config if ret_kwargs: cmd_kw["ret_kwargs"] = ret_kwargs state_ret = {"name": name, "changes": {}, "comment": "", "result": True} try: allow_fail = int(allow_fail) except ValueError: state_ret["result"] = False state_ret["comment"] = "Passed invalid value for 'allow_fail', must be an int" return state_ret cmd_kw["tgt_type"] = tgt_type cmd_kw["ssh"] = ssh if "roster" in kwargs: cmd_kw["roster"] = kwargs["roster"] cmd_kw["expect_minions"] = expect_minions if highstate: fun = "state.highstate" elif top: fun = "state.top" cmd_kw["arg"].append(top) elif sls: fun = "state.sls" if isinstance(sls, list): sls = ",".join(sls) cmd_kw["arg"].append(sls) else: state_ret["comment"] = "No highstate or sls specified, no execution made" state_ret["result"] = False return state_ret if test is not None or __opts__.get("test"): cmd_kw["kwarg"]["test"] = test if test is not None else __opts__.get("test") if pillar: cmd_kw["kwarg"]["pillar"] = pillar if pillarenv is not None: cmd_kw["kwarg"]["pillarenv"] = pillarenv if saltenv is not None: cmd_kw["kwarg"]["saltenv"] = saltenv if exclude is not None: cmd_kw["kwarg"]["exclude"] = exclude cmd_kw["kwarg"]["queue"] = queue if isinstance(concurrent, bool): cmd_kw["kwarg"]["concurrent"] = concurrent else: state_ret["comment"] = "Must pass in boolean for value of 'concurrent'" state_ret["result"] = False return state_ret if batch is not None: cmd_kw["batch"] = str(batch) if subset is not None: cmd_kw["subset"] = subset if failhard is True or __opts__.get("failhard"): cmd_kw["failhard"] = True masterless = __opts__["__role"] == "minion" and __opts__["file_client"] == "local" if not masterless: _fire_args({"type": "state", "tgt": tgt, "name": name, "args": cmd_kw}) cmd_ret = __salt__["saltutil.cmd"](tgt, fun, **cmd_kw) else: if top: cmd_kw["topfn"] = "".join(cmd_kw.pop("arg")) elif sls: cmd_kw["mods"] = "".join(cmd_kw.pop("arg")) cmd_kw.update(cmd_kw.pop("kwarg")) tmp_ret = __salt__[fun](**cmd_kw) cmd_ret = { __opts__["id"]: { "ret": tmp_ret, "out": tmp_ret.get("out", "highstate") if isinstance(tmp_ret, dict) else "highstate", } } try: state_ret["__jid__"] = cmd_ret[next(iter(cmd_ret))]["jid"] except (StopIteration, KeyError): pass changes = {} fail = set() no_change = set() if fail_minions is None: fail_minions = () elif isinstance(fail_minions, str): fail_minions = [minion.strip() for minion in fail_minions.split(",")] elif not isinstance(fail_minions, list): state_ret.setdefault("warnings", []).append( "'fail_minions' needs to be a list or a comma separated string. Ignored." ) fail_minions = () if not cmd_ret and expect_minions: state_ret["result"] = False state_ret["comment"] = "No minions returned" return state_ret for minion, mdata in cmd_ret.items(): if mdata.get("out", "") != "highstate": log.warning("Output from salt state not highstate") m_ret = False if "return" in mdata and "ret" not in mdata: mdata["ret"] = mdata.pop("return") m_state = True if mdata.get("failed", False): m_state = False else: try: m_ret = mdata["ret"] except KeyError: m_state = False if m_state: m_state = __utils__["state.check_result"](m_ret, recurse=True) if not m_state: if minion not in fail_minions: fail.add(minion) changes[minion] = m_ret continue try: for state_item in m_ret.values(): if isinstance(state_item, dict): if "changes" in state_item and state_item["changes"]: changes[minion] = m_ret break else: no_change.add(minion) except AttributeError: log.error("m_ret did not have changes %s %s", type(m_ret), m_ret) no_change.add(minion) if changes: state_ret["changes"] = {"out": "highstate", "ret": changes} if len(fail) > allow_fail: state_ret["result"] = False state_ret["comment"] = "Run failed on minions: {}".format(", ".join(fail)) else: state_ret["comment"] = "States ran successfully." if changes: state_ret["comment"] += " Updating {}.".format(", ".join(changes)) if no_change: state_ret["comment"] += " No changes made to {}.".format( ", ".join(no_change) ) if test or __opts__.get("test"): if state_ret["changes"] and state_ret["result"] is True: # Test mode with changes is the only case where result should ever be none state_ret["result"] = None return state_ret def function( name, tgt, ssh=False, tgt_type="glob", ret="", ret_config=None, ret_kwargs=None, expect_minions=False, fail_minions=None, fail_function=None, arg=None, kwarg=None, timeout=None, batch=None, subset=None, failhard=None, **kwargs, ): # pylint: disable=unused-argument """ Execute a single module function on a remote minion via salt or salt-ssh name The name of the function to run, aka cmd.run or pkg.install tgt The target specification, aka '*' for all minions tgt_type The target type, defaults to ``glob`` arg The list of arguments to pass into the function kwarg The dict (not a list) of keyword arguments to pass into the function ret Optionally set a single or a list of returners to use ret_config Use an alternative returner configuration ret_kwargs Override individual returner configuration items expect_minions An optional boolean for failing if some minions do not respond fail_minions An optional list of targeted minions where failure is an option fail_function An optional string that points to a salt module that returns True or False based on the returned data dict for individual minions ssh Set to `True` to use the ssh client instead of the standard salt client roster In the event of using salt-ssh, a roster system can be set .. versionadded:: 3005 batch Execute the command :ref:`in batches <targeting-batch>`. E.g.: ``10%``. subset Number of minions from the targeted set to randomly use .. versionadded:: 2017.7.0 failhard pass failhard down to the executing state .. versionadded:: 2019.2.2 """ func_ret = {"name": name, "changes": {}, "comment": "", "result": True} if kwarg is None: kwarg = {} if isinstance(arg, str): func_ret["warnings"] = ["Please specify 'arg' as a list of arguments."] arg = arg.split() cmd_kw = {"arg": arg or [], "kwarg": kwarg, "ret": ret, "timeout": timeout} if batch is not None: cmd_kw["batch"] = str(batch) if subset is not None: cmd_kw["subset"] = subset cmd_kw["tgt_type"] = tgt_type cmd_kw["ssh"] = ssh if "roster" in kwargs: cmd_kw["roster"] = kwargs["roster"] cmd_kw["expect_minions"] = expect_minions cmd_kw["_cmd_meta"] = True if failhard is True or __opts__.get("failhard"): cmd_kw["failhard"] = True if ret_config: cmd_kw["ret_config"] = ret_config if ret_kwargs: cmd_kw["ret_kwargs"] = ret_kwargs fun = name if __opts__["test"] is True: func_ret["comment"] = "Function {} would be executed on target {}".format( fun, tgt ) func_ret["result"] = None return func_ret try: _fire_args({"type": "function", "tgt": tgt, "name": name, "args": cmd_kw}) cmd_ret = __salt__["saltutil.cmd"](tgt, fun, **cmd_kw) except Exception as exc: # pylint: disable=broad-except func_ret["result"] = False func_ret["comment"] = str(exc) return func_ret try: func_ret["__jid__"] = cmd_ret[next(iter(cmd_ret))]["jid"] except (StopIteration, KeyError): pass changes = {} fail = set() if fail_minions is None: fail_minions = () elif isinstance(fail_minions, str): fail_minions = [minion.strip() for minion in fail_minions.split(",")] elif not isinstance(fail_minions, list): func_ret.setdefault("warnings", []).append( "'fail_minions' needs to be a list or a comma separated string. Ignored." ) fail_minions = () for minion, mdata in cmd_ret.items(): m_ret = False if mdata.get("retcode"): func_ret["result"] = False fail.add(minion) if mdata.get("failed", False): m_func = False else: if "return" in mdata and "ret" not in mdata: mdata["ret"] = mdata.pop("return") m_ret = mdata["ret"] m_func = (not fail_function and True) or __salt__[fail_function](m_ret) if m_ret is False: m_func = False if not m_func: if minion not in fail_minions: fail.add(minion) changes[minion] = m_ret if not cmd_ret: func_ret["result"] = False func_ret["comment"] = "No minions responded" else: if changes: func_ret["changes"] = {"ret": changes} if fail: func_ret["result"] = False func_ret["comment"] = "Running function {} failed on minions: {}".format( name, ", ".join(fail) ) else: func_ret["comment"] = "Function ran successfully." if changes: func_ret["comment"] += " Function {} ran on {}.".format( name, ", ".join(changes) ) return func_ret def wait_for_event(name, id_list, event_id="id", timeout=300, node="master"): """ Watch Salt's event bus and block until a condition is met .. versionadded:: 2014.7.0 name An event tag to watch for; supports Reactor-style globbing. id_list A list of event identifiers to watch for -- usually the minion ID. Each time an event tag is matched the event data is inspected for ``event_id``, if found it is removed from ``id_list``. When ``id_list`` is empty this function returns success. event_id : id The name of a key in the event data. Default is ``id`` for the minion ID, another common value is ``name`` for use with orchestrating salt-cloud events. timeout : 300 The maximum time in seconds to wait before failing. The following example blocks until all the listed minions complete a restart and reconnect to the Salt master: .. code-block:: yaml reboot_all_minions: salt.function: - name: system.reboot - tgt: '*' wait_for_reboots: salt.wait_for_event: - name: salt/minion/*/start - id_list: - jerry - stuart - dave - phil - kevin - mike - require: - salt: reboot_all_minions """ ret = {"name": name, "changes": {}, "comment": "", "result": False} if __opts__.get("test"): ret["comment"] = "Orchestration would wait for event '{}'".format(name) ret["result"] = None return ret with salt.utils.event.get_event( node, __opts__["sock_dir"], opts=__opts__, listen=True ) as sevent: del_counter = 0 starttime = time.time() timelimit = starttime + timeout while True: event = sevent.get_event(full=True) is_timedout = time.time() > timelimit if event is None and not is_timedout: log.trace("wait_for_event: No event data; waiting.") continue elif event is None and is_timedout: ret["comment"] = "Timeout value reached." return ret if fnmatch.fnmatch(event["tag"], name): val = event["data"].get(event_id) if val is None and "data" in event["data"]: val = event["data"]["data"].get(event_id) if val is not None: if isinstance(val, list): val_list = [id for id in id_list if id in val] if not val_list: log.trace( "wait_for_event: Event identifier '%s' not in " "id_list; skipping", event_id, ) elif val_list: minions_seen = ret["changes"].setdefault("minions_seen", []) for found_val in val_list: id_list.remove(found_val) del_counter += 1 minions_seen.append(found_val) log.debug( "wait_for_event: Event identifier '%s' removed " "from id_list; %s items remaining.", found_val, len(id_list), ) else: try: val_idx = id_list.index(val) except ValueError: log.trace( "wait_for_event: Event identifier '%s' not in " "id_list; skipping.", event_id, ) else: del id_list[val_idx] del_counter += 1 minions_seen = ret["changes"].setdefault("minions_seen", []) minions_seen.append(val) log.debug( "wait_for_event: Event identifier '%s' removed " "from id_list; %s items remaining.", val, len(id_list), ) else: log.trace( "wait_for_event: Event identifier '%s' not in event " "'%s'; skipping.", event_id, event["tag"], ) else: log.debug("wait_for_event: Skipping unmatched event '%s'", event["tag"]) if len(id_list) == 0: ret["result"] = True ret["comment"] = "All events seen in {} seconds.".format( time.time() - starttime ) return ret if is_timedout: ret["comment"] = "Timeout value reached." return ret def runner(name, **kwargs): """ Execute a runner module on the master .. versionadded:: 2014.7.0 name The name of the function to run kwargs Any keyword arguments to pass to the runner function .. code-block:: yaml run-manage-up: salt.runner: - name: manage.up """ try: jid = __orchestration_jid__ except NameError: log.debug("Unable to fire args event due to missing __orchestration_jid__") jid = None try: kwargs["__pub_user"] = __user__ log.debug( f"added __pub_user to kwargs using dunder user '{__user__}', kwargs '{kwargs}'" ) except NameError: log.warning("unable to find user for fire args event due to missing __user__") if __opts__.get("test", False): ret = { "name": name, "result": None, "changes": {}, "comment": "Runner function '{}' would be executed.".format(name), } return ret out = __salt__["saltutil.runner"]( name, __orchestration_jid__=jid, __env__=__env__, full_return=True, **kwargs ) runner_return = out.get("return") if isinstance(runner_return, dict) and "Error" in runner_return: out["success"] = False success = out.get("success", True) ret = {"name": name, "changes": {"return": runner_return}, "result": success} ret["comment"] = "Runner function '{}' {}.".format( name, "executed" if success else "failed", ) if features.get("enable_deprecated_orchestration_flag", False): ret["__orchestration__"] = True salt.utils.versions.warn_until( "Argon", "The __orchestration__ return flag will be removed in Salt Argon. " "For more information see https://github.com/saltstack/salt/pull/59917.", ) if "jid" in out: ret["__jid__"] = out["jid"] return ret def parallel_runners(name, runners, **kwargs): # pylint: disable=unused-argument """ Executes multiple runner modules on the master in parallel. .. versionadded:: 2018.3.0 A separate thread is spawned for each runner. This state is intended to be used with the orchestrate runner in place of the ``saltmod.runner`` state when different tasks should be run in parallel. In general, Salt states are not safe when used concurrently, so ensure that they are used in a safe way (e.g. by only targeting separate minions in parallel tasks). name: name identifying this state. The name is provided as part of the output, but not used for anything else. runners: list of runners that should be run in parallel. Each element of the list has to be a dictionary. This dictionary's name entry stores the name of the runner function that shall be invoked. The optional kwarg entry stores a dictionary of named arguments that are passed to the runner function. .. code-block:: yaml parallel-state: salt.parallel_runners: - runners: my_runner_1: - name: state.orchestrate - kwarg: mods: orchestrate_state_1 my_runner_2: - name: state.orchestrate - kwarg: mods: orchestrate_state_2 """ # For the sake of consistency, we treat a single string in the same way as # a key without a value. This allows something like # salt.parallel_runners: # - runners: # state.orchestrate # Obviously, this will only work if the specified runner does not need any # arguments. if isinstance(runners, str): runners = {runners: [{name: runners}]} # If the runners argument is not a string, it must be a dict. Everything # else is considered an error. if not isinstance(runners, dict): return { "name": name, "result": False, "changes": {}, "comment": "The runners parameter must be a string or dict.", } # The configuration for each runner is given as a list of key-value pairs. # This is not very useful for what we want to do, but it is the typical # style used in Salt. For further processing, we convert each of these # lists to a dict. This also makes it easier to check whether a name has # been specified explicitly. for runner_id, runner_config in runners.items(): if runner_config is None: runner_config = {} else: runner_config = salt.utils.data.repack_dictlist(runner_config) if "name" not in runner_config: runner_config["name"] = runner_id runners[runner_id] = runner_config try: jid = __orchestration_jid__ except NameError: log.debug("Unable to fire args event due to missing __orchestration_jid__") jid = None def call_runner(runner_config): return __salt__["saltutil.runner"]( runner_config["name"], __orchestration_jid__=jid, __env__=__env__, full_return=True, **(runner_config.get("kwarg", {})), ) try: outputs = _parallel_map(call_runner, list(runners.values())) except salt.exceptions.SaltException as exc: return { "name": name, "result": False, "success": False, "changes": {}, "comment": "One of the runners raised an exception: {}".format(exc), } # We bundle the results of the runners with the IDs of the runners so that # we can easily identify which output belongs to which runner. At the same # time we exctract the actual return value of the runner (saltutil.runner # adds some extra information that is not interesting to us). outputs = { runner_id: out["return"] for runner_id, out in zip(runners.keys(), outputs) } # If each of the runners returned its output in the format compatible with # the 'highstate' outputter, we can leverage this fact when merging the # outputs. highstate_output = all( [ out.get("outputter", "") == "highstate" and "data" in out for out in outputs.values() ] ) # The following helper function is used to extract changes from highstate # output. def extract_changes(obj): if not isinstance(obj, dict): return {} elif "changes" in obj: if ( isinstance(obj["changes"], dict) and obj["changes"].get("out", "") == "highstate" and "ret" in obj["changes"] ): return obj["changes"]["ret"] else: return obj["changes"] else: found_changes = {} for key, value in obj.items(): change = extract_changes(value) if change: found_changes[key] = change return found_changes if highstate_output: failed_runners = [ runner_id for runner_id, out in outputs.items() if out["data"].get("retcode", 0) != 0 ] all_successful = not failed_runners if all_successful: comment = "All runner functions executed successfully." else: runner_comments = [ "Runner {} failed with return value:\n{}".format( runner_id, salt.output.out_format( outputs[runner_id], "nested", __opts__, nested_indent=2 ), ) for runner_id in failed_runners ] comment = "\n".join(runner_comments) changes = {} for runner_id, out in outputs.items(): runner_changes = extract_changes(out["data"]) if runner_changes: changes[runner_id] = runner_changes else: failed_runners = [ runner_id for runner_id, out in outputs.items() if out.get("exit_code", 0) != 0 ] all_successful = not failed_runners if all_successful: comment = "All runner functions executed successfully." else: if len(failed_runners) == 1: comment = "Runner {} failed.".format(failed_runners[0]) else: comment = "Runners {} failed.".format(", ".join(failed_runners)) changes = {"ret": {runner_id: out for runner_id, out in outputs.items()}} ret = { "name": name, "result": all_successful, "changes": changes, "comment": comment, } # The 'runner' function includes out['jid'] as '__jid__' in the returned # dict, but we cannot do this here because we have more than one JID if # we have more than one runner. return ret def wheel(name, **kwargs): """ Execute a wheel module on the master .. versionadded:: 2014.7.0 name The name of the function to run kwargs Any keyword arguments to pass to the wheel function .. code-block:: yaml accept_minion_key: salt.wheel: - name: key.accept - match: frank """ ret = {"name": name, "result": False, "changes": {}, "comment": ""} try: jid = __orchestration_jid__ except NameError: log.debug("Unable to fire args event due to missing __orchestration_jid__") jid = None if __opts__.get("test", False): ret["result"] = None ret["changes"] = {} ret["comment"] = "Wheel function '{}' would be executed.".format(name) return ret out = __salt__["saltutil.wheel"]( name, __orchestration_jid__=jid, __env__=__env__, **kwargs ) wheel_return = out.get("return") if isinstance(wheel_return, dict) and "Error" in wheel_return: out["success"] = False success = out.get("success", True) ret = {"name": name, "changes": {"return": wheel_return}, "result": success} ret["comment"] = "Wheel function '{}' {}.".format( name, "executed" if success else "failed", ) if features.get("enable_deprecated_orchestration_flag", False): ret["__orchestration__"] = True salt.utils.versions.warn_until( "Argon", "The __orchestration__ return flag will be removed in Salt Argon. " "For more information see https://github.com/saltstack/salt/pull/59917.", ) if "jid" in out: ret["__jid__"] = out["jid"] return ret
Save