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: pcs.py
""" Management of Pacemaker/Corosync clusters with PCS ================================================== A state module to manage Pacemaker/Corosync clusters with the Pacemaker/Corosync configuration system (PCS) .. versionadded:: 2016.11.0 :depends: pcs Walkthrough of a complete PCS cluster setup: http://clusterlabs.org/doc/en-US/Pacemaker/1.1/html/Clusters_from_Scratch/ Requirements: PCS is installed, pcs service is started and the password for the hacluster user is set and known. Remark on the cibname variable used in the examples: The use of the cibname variable is optional. Use it only if you want to deploy your changes into a cibfile first and then push it. This makes only sense if you want to deploy multiple changes (which require each other) at once to the cluster. At first the cibfile must be created: .. code-block:: yaml mysql_pcs__cib_present_cib_for_galera: pcs.cib_present: - cibname: cib_for_galera - scope: None - extra_args: None Then the cibfile can be modified by creating resources (creating only 1 resource for demonstration, see also 7.): .. code-block:: yaml mysql_pcs__resource_present_galera: pcs.resource_present: - resource_id: galera - resource_type: "ocf:heartbeat:galera" - resource_options: - 'wsrep_cluster_address=gcomm://node1.example.org,node2.example.org,node3.example.org' - '--master' - cibname: cib_for_galera After modifying the cibfile, it can be pushed to the live CIB in the cluster: .. code-block:: yaml mysql_pcs__cib_pushed_cib_for_galera: pcs.cib_pushed: - cibname: cib_for_galera - scope: None - extra_args: None Create a cluster from scratch: 1. This authorizes nodes to each other. It probably won't work with Ubuntu as it rolls out a default cluster that needs to be destroyed before the new cluster can be created. This is a little complicated so it's best to just run the cluster_setup below in most cases.: .. code-block:: yaml pcs_auth__auth: pcs.auth: - nodes: - node1.example.com - node2.example.com - pcsuser: hacluster - pcspasswd: hoonetorg 2. Do the initial cluster setup: .. code-block:: yaml pcs_setup__setup: pcs.cluster_setup: - nodes: - node1.example.com - node2.example.com - pcsclustername: pcscluster - extra_args: - '--start' - '--enable' - pcsuser: hacluster - pcspasswd: hoonetorg 3. Optional: Set cluster properties: .. code-block:: yaml pcs_properties__prop_has_value_no-quorum-policy: pcs.prop_has_value: - prop: no-quorum-policy - value: ignore - cibname: cib_for_cluster_settings 4. Optional: Set resource defaults: .. code-block:: yaml pcs_properties__resource_defaults_to_resource-stickiness: pcs.resource_defaults_to: - default: resource-stickiness - value: 100 - cibname: cib_for_cluster_settings 5. Optional: Set resource op defaults: .. code-block:: yaml pcs_properties__resource_op_defaults_to_monitor-interval: pcs.resource_op_defaults_to: - op_default: monitor-interval - value: 60s - cibname: cib_for_cluster_settings 6. Configure Fencing (!is often not optional on production ready cluster!): .. code-block:: yaml pcs_stonith__created_eps_fence: pcs.stonith_present: - stonith_id: eps_fence - stonith_device_type: fence_eps - stonith_device_options: - 'pcmk_host_map=node1.example.org:01;node2.example.org:02' - 'ipaddr=myepsdevice.example.org' - 'power_wait=5' - 'verbose=1' - 'debug=/var/log/pcsd/eps_fence.log' - 'login=hidden' - 'passwd=hoonetorg' - cibname: cib_for_stonith 7. Add resources to your cluster: .. code-block:: yaml mysql_pcs__resource_present_galera: pcs.resource_present: - resource_id: galera - resource_type: "ocf:heartbeat:galera" - resource_options: - 'wsrep_cluster_address=gcomm://node1.example.org,node2.example.org,node3.example.org' - '--master' - cibname: cib_for_galera 8. Optional: Add constraints (locations, colocations, orders): .. code-block:: yaml haproxy_pcs__constraint_present_colocation-vip_galera-haproxy-clone-INFINITY: pcs.constraint_present: - constraint_id: colocation-vip_galera-haproxy-clone-INFINITY - constraint_type: colocation - constraint_options: - 'add' - 'vip_galera' - 'with' - 'haproxy-clone' - cibname: cib_for_haproxy .. versionadded:: 2016.3.0 """ import logging import os import salt.utils.files import salt.utils.path import salt.utils.stringutils log = logging.getLogger(__name__) def __virtual__(): """ Only load if pcs package is installed """ if salt.utils.path.which("pcs"): return "pcs" return (False, "Unable to locate command: pcs") def _file_read(path): """ Read a file and return content """ content = False if os.path.exists(path): with salt.utils.files.fopen(path, "r+") as fp_: content = salt.utils.stringutils.to_unicode(fp_.read()) fp_.close() return content def _file_write(path, content): """ Write content to a file """ with salt.utils.files.fopen(path, "w+") as fp_: fp_.write(salt.utils.stringutils.to_str(content)) fp_.close() def _get_cibpath(): """ Get the path to the directory on the minion where CIB's are saved """ cibpath = os.path.join(__opts__["cachedir"], "pcs", __env__) log.trace("cibpath: %s", cibpath) return cibpath def _get_cibfile(cibname): """ Get the full path of a cached CIB-file with the name of the CIB """ cibfile = os.path.join(_get_cibpath(), "{}.{}".format(cibname, "cib")) log.trace("cibfile: %s", cibfile) return cibfile def _get_cibfile_tmp(cibname): """ Get the full path of a temporary CIB-file with the name of the CIB """ cibfile_tmp = "{}.tmp".format(_get_cibfile(cibname)) log.trace("cibfile_tmp: %s", cibfile_tmp) return cibfile_tmp def _get_cibfile_cksum(cibname): """ Get the full path of the file containing a checksum of a CIB-file with the name of the CIB """ cibfile_cksum = "{}.cksum".format(_get_cibfile(cibname)) log.trace("cibfile_cksum: %s", cibfile_cksum) return cibfile_cksum def _get_node_list_for_version(nodes): """ PCS with version < 0.10 returns lowercase hostnames. Newer versions return the proper hostnames. This accomodates for the old functionality. """ pcs_version = __salt__["pkg.version"]("pcs") if __salt__["pkg.version_cmp"](pcs_version, "0.10") == -1: log.info("Node list converted to lower case for backward compatibility") nodes_for_version = [x.lower() for x in nodes] else: nodes_for_version = nodes return nodes_for_version def _item_present( name, item, item_id, item_type, show="show", create="create", extra_args=None, cibname=None, ): """ Ensure that an item is created name Irrelevant, not used item config, property, resource, constraint etc. item_id id of the item item_type item type show show command (probably None, default: show) create create command (create or set f.e., default: create) extra_args additional options for the pcs command cibname use a cached CIB-file named like cibname instead of the live CIB """ ret = {"name": name, "result": True, "comment": "", "changes": {}} item_create_required = True cibfile = None if isinstance(cibname, str): cibfile = _get_cibfile(cibname) if not isinstance(extra_args, (list, tuple)): extra_args = [] # split off key and value (item_id contains =) item_id_key = item_id item_id_value = None if "=" in item_id: item_id_key = item_id.split("=")[0].strip() item_id_value = item_id.replace(item_id.split("=")[0] + "=", "").strip() log.trace("item_id_key=%s item_id_value=%s", item_id_key, item_id_value) # constraints, properties, resource defaults or resource op defaults # do not support specifying an id on 'show' command item_id_show = item_id if item in ["constraint"] or "=" in item_id: item_id_show = None is_existing = __salt__["pcs.item_show"]( item=item, item_id=item_id_show, item_type=item_type, show=show, cibfile=cibfile ) log.trace( "Output of pcs.item_show item=%s item_id=%s item_type=%s cibfile=%s: %s", item, item_id_show, item_type, cibfile, is_existing, ) # key,value pairs (item_id contains =) - match key and value if item_id_value is not None: for line in is_existing["stdout"].splitlines(): if len(line.split(":")) in [2]: key = line.split(":")[0].strip() value = line.split(":")[1].strip() if item_id_key in [key]: if item_id_value in [value]: item_create_required = False # constraints match on '(id:<id>)' elif item in ["constraint"]: for line in is_existing["stdout"].splitlines(): if "(id:{})".format(item_id) in line: item_create_required = False # item_id was provided, # return code 0 indicates, that resource already exists else: if is_existing["retcode"] in [0]: item_create_required = False if not item_create_required: ret["comment"] += "{} {} ({}) is already existing\n".format( str(item), str(item_id), str(item_type) ) return ret if __opts__["test"]: ret["result"] = None ret["comment"] += "{} {} ({}) is set to be created\n".format( str(item), str(item_id), str(item_type) ) return ret item_create = __salt__["pcs.item_create"]( item=item, item_id=item_id, item_type=item_type, create=create, extra_args=extra_args, cibfile=cibfile, ) log.trace("Output of pcs.item_create: %s", item_create) if item_create["retcode"] in [0]: ret["comment"] += "Created {} {} ({})\n".format(item, item_id, item_type) ret["changes"].update({item_id: {"old": "", "new": str(item_id)}}) else: ret["result"] = False ret["comment"] += "Failed to create {} {} ({})\n".format( item, item_id, item_type ) log.trace("ret: %s", ret) return ret def auth(name, nodes, pcsuser="hacluster", pcspasswd="hacluster", extra_args=None): """ Ensure all nodes are authorized to the cluster name Irrelevant, not used (recommended: pcs_auth__auth) nodes a list of nodes which should be authorized to the cluster pcsuser user for communication with pcs (default: hacluster) pcspasswd password for pcsuser (default: hacluster) extra_args list of extra args for the \'pcs cluster auth\' command, there are none so it's here for compatibility. Example: .. code-block:: yaml pcs_auth__auth: pcs.auth: - nodes: - node1.example.com - node2.example.com - pcsuser: hacluster - pcspasswd: hoonetorg - extra_args: [] """ ret = {"name": name, "result": True, "comment": "", "changes": {}} auth_required = False nodes = _get_node_list_for_version(nodes) authorized = __salt__["pcs.is_auth"]( nodes=nodes, pcsuser=pcsuser, pcspasswd=pcspasswd ) log.trace("Output of pcs.is_auth: %s", authorized) authorized_dict = {} for line in authorized["stdout"].splitlines(): node = line.split(":")[0].strip() auth_state = line.split(":")[1].strip() if node in nodes: authorized_dict.update({node: auth_state}) log.trace("authorized_dict: %s", authorized_dict) for node in nodes: if node in authorized_dict and ( authorized_dict[node] == "Already authorized" or authorized_dict[node] == "Authorized" ): ret["comment"] += "Node {} is already authorized\n".format(node) else: auth_required = True if __opts__["test"]: ret["comment"] += "Node is set to authorize: {}\n".format(node) if not auth_required: return ret if __opts__["test"]: ret["result"] = None return ret authorize = __salt__["pcs.auth"]( nodes=nodes, pcsuser=pcsuser, pcspasswd=pcspasswd, extra_args=extra_args ) log.trace("Output of pcs.auth: %s", authorize) authorize_dict = {} for line in authorize["stdout"].splitlines(): node = line.split(":")[0].strip() auth_state = line.split(":")[1].strip() if node in nodes: authorize_dict.update({node: auth_state}) log.trace("authorize_dict: %s", authorize_dict) for node in nodes: if node in authorize_dict and authorize_dict[node] == "Authorized": ret["comment"] += "Authorized {}\n".format(node) ret["changes"].update({node: {"old": "", "new": "Authorized"}}) else: ret["result"] = False if node in authorized_dict: ret[ "comment" ] += "Authorization check for node {} returned: {}\n".format( node, authorized_dict[node] ) if node in authorize_dict: ret["comment"] += "Failed to authorize {} with error {}\n".format( node, authorize_dict[node] ) return ret def cluster_setup( name, nodes, pcsclustername="pcscluster", extra_args=None, pcsuser="hacluster", pcspasswd="hacluster", pcs_auth_extra_args=None, wipe_default=False, ): """ Setup Pacemaker cluster on nodes. Should be run on one cluster node only to avoid race conditions. This performs auth as well as setup so can be run in place of the auth state. It is recommended not to run auth on Debian/Ubuntu for a new cluster and just to run this because of the initial cluster config that is installed on Ubuntu/Debian by default. name Irrelevant, not used (recommended: pcs_setup__setup) nodes a list of nodes which should be set up pcsclustername Name of the Pacemaker cluster extra_args list of extra args for the \'pcs cluster setup\' command pcsuser The username for authenticating the cluster (default: hacluster) pcspasswd The password for authenticating the cluster (default: hacluster) pcs_auth_extra_args Extra args to be passed to the auth function in case of reauth. wipe_default This removes the files that are installed with Debian based operating systems. Example: .. code-block:: yaml pcs_setup__setup: pcs.cluster_setup: - nodes: - node1.example.com - node2.example.com - pcsclustername: pcscluster - extra_args: - '--start' - '--enable' - pcsuser: hacluster - pcspasswd: hoonetorg """ ret = {"name": name, "result": True, "comment": "", "changes": {}} setup_required = False config_show = __salt__["pcs.config_show"]() log.trace("Output of pcs.config_show: %s", config_show) for line in config_show["stdout"].splitlines(): if len(line.split(":")) in [2]: key = line.split(":")[0].strip() value = line.split(":")[1].strip() if key in ["Cluster Name"]: if value in [pcsclustername]: ret["comment"] += "Cluster {} is already set up\n".format( pcsclustername ) else: setup_required = True if __opts__["test"]: ret["comment"] += "Cluster {} is set to set up\n".format( pcsclustername ) if not setup_required: log.info("No setup required") return ret if __opts__["test"]: ret["result"] = None return ret # Debian based distros deploy corosync with some initial cluster setup. # The following detects if it's a Debian based distro and then stops Corosync # and removes the config files. I've put this here because trying to do all this in the # state file can break running clusters and can also take quite a long time to debug. log.debug("OS_Family: %s", __grains__.get("os_family")) if __grains__.get("os_family") == "Debian" and wipe_default: __salt__["file.remove"]("/etc/corosync/corosync.conf") __salt__["file.remove"]("/var/lib/pacemaker/cib/cib.xml") __salt__["service.stop"]("corosync") auth("pcs_auth__auth", nodes, pcsuser, pcspasswd, pcs_auth_extra_args) nodes = _get_node_list_for_version(nodes) if not isinstance(extra_args, (list, tuple)): extra_args = [] setup = __salt__["pcs.cluster_setup"]( nodes=nodes, pcsclustername=pcsclustername, extra_args=extra_args ) log.trace("Output of pcs.cluster_setup: %s", setup) setup_dict = {} for line in setup["stdout"].splitlines(): log.trace("line: %s", line) log.trace("line.split(:).len: %s", len(line.split(":"))) if len(line.split(":")) in [2]: node = line.split(":")[0].strip() setup_state = line.split(":")[1].strip() if node in nodes: setup_dict.update({node: setup_state}) log.trace("setup_dict: %s", setup_dict) for node in nodes: if node in setup_dict and setup_dict[node] in [ "Succeeded", "Success", "Cluster enabled", ]: ret["comment"] += "Set up {}\n".format(node) ret["changes"].update({node: {"old": "", "new": "Setup"}}) else: ret["result"] = False ret["comment"] += "Failed to setup {}\n".format(node) if node in setup_dict: ret["comment"] += "{}: setup_dict: {}\n".format(node, setup_dict[node]) ret["comment"] += str(setup) log.trace("ret: %s", ret) return ret def cluster_node_present(name, node, extra_args=None): """ Add a node to the Pacemaker cluster via PCS Should be run on one cluster node only (there may be races) Can only be run on a already setup/added node name Irrelevant, not used (recommended: pcs_setup__node_add_{{node}}) node node that should be added extra_args list of extra args for the \'pcs cluster node add\' command Example: .. code-block:: yaml pcs_setup__node_add_node1.example.com: pcs.cluster_node_present: - node: node1.example.com - extra_args: - '--start' - '--enable' """ ret = {"name": name, "result": True, "comment": "", "changes": {}} node_add_required = True current_nodes = [] is_member_cmd = ["pcs", "status", "nodes", "corosync"] is_member = __salt__["cmd.run_all"]( is_member_cmd, output_loglevel="trace", python_shell=False ) log.trace("Output of pcs status nodes corosync: %s", is_member) for line in is_member["stdout"].splitlines(): if len(line.split(":")) in [2]: key = line.split(":")[0].strip() value = line.split(":")[1].strip() if key in ["Offline", "Online"]: if len(value.split()) > 0: if node in value.split(): node_add_required = False ret[ "comment" ] += "Node {} is already member of the cluster\n".format(node) else: current_nodes += value.split() if not node_add_required: return ret if __opts__["test"]: ret["result"] = None ret["comment"] += "Node {} is set to be added to the cluster\n".format(node) return ret if not isinstance(extra_args, (list, tuple)): extra_args = [] node_add = __salt__["pcs.cluster_node_add"](node=node, extra_args=extra_args) log.trace("Output of pcs.cluster_node_add: %s", node_add) node_add_dict = {} for line in node_add["stdout"].splitlines(): log.trace("line: %s", line) log.trace("line.split(:).len: %s", len(line.split(":"))) if len(line.split(":")) in [2]: current_node = line.split(":")[0].strip() current_node_add_state = line.split(":")[1].strip() if current_node in current_nodes + [node]: node_add_dict.update({current_node: current_node_add_state}) log.trace("node_add_dict: %s", node_add_dict) for current_node in current_nodes: if current_node in node_add_dict: if node_add_dict[current_node] not in ["Corosync updated"]: ret["result"] = False ret["comment"] += "Failed to update corosync.conf on node {}\n".format( current_node ) ret["comment"] += "{}: node_add_dict: {}\n".format( current_node, node_add_dict[current_node] ) else: ret["result"] = False ret["comment"] += "Failed to update corosync.conf on node {}\n".format( current_node ) if node in node_add_dict and node_add_dict[node] in ["Succeeded", "Success"]: ret["comment"] += "Added node {}\n".format(node) ret["changes"].update({node: {"old": "", "new": "Added"}}) else: ret["result"] = False ret["comment"] += "Failed to add node{}\n".format(node) if node in node_add_dict: ret["comment"] += "{}: node_add_dict: {}\n".format( node, node_add_dict[node] ) ret["comment"] += str(node_add) log.trace("ret: %s", ret) return ret def cib_present(name, cibname, scope=None, extra_args=None): """ Ensure that a CIB-file with the content of the current live CIB is created Should be run on one cluster node only (there may be races) name Irrelevant, not used (recommended: {{formulaname}}__cib_present_{{cibname}}) cibname name/path of the file containing the CIB scope specific section of the CIB (default: None) extra_args additional options for creating the CIB-file Example: .. code-block:: yaml mysql_pcs__cib_present_cib_for_galera: pcs.cib_present: - cibname: cib_for_galera - scope: None - extra_args: None """ ret = {"name": name, "result": True, "comment": "", "changes": {}} cib_hash_form = "sha256" cib_create_required = False cib_cksum_required = False cib_required = False cibpath = _get_cibpath() cibfile = _get_cibfile(cibname) cibfile_tmp = _get_cibfile_tmp(cibname) cibfile_cksum = _get_cibfile_cksum(cibname) if not os.path.exists(cibpath): os.makedirs(cibpath) if not isinstance(extra_args, (list, tuple)): extra_args = [] if os.path.exists(cibfile_tmp): __salt__["file.remove"](cibfile_tmp) cib_create = __salt__["pcs.cib_create"]( cibfile=cibfile_tmp, scope=scope, extra_args=extra_args ) log.trace("Output of pcs.cib_create: %s", cib_create) if cib_create["retcode"] not in [0] or not os.path.exists(cibfile_tmp): ret["result"] = False ret["comment"] += "Failed to get live CIB\n" return ret cib_hash_live = "{}:{}".format( cib_hash_form, __salt__["file.get_hash"](path=cibfile_tmp, form=cib_hash_form) ) log.trace("cib_hash_live: %s", cib_hash_live) cib_hash_cur = _file_read(path=cibfile_cksum) if cib_hash_cur not in [cib_hash_live]: cib_cksum_required = True log.trace("cib_hash_cur: %s", cib_hash_cur) if not os.path.exists(cibfile) or not __salt__["file.check_hash"]( path=cibfile, file_hash=cib_hash_live ): cib_create_required = True if cib_cksum_required or cib_create_required: cib_required = True if not cib_create_required: __salt__["file.remove"](cibfile_tmp) ret["comment"] += "CIB {} is already equal to the live CIB\n".format(cibname) if not cib_cksum_required: ret["comment"] += "CIB {} checksum is correct\n".format(cibname) if not cib_required: return ret if __opts__["test"]: __salt__["file.remove"](cibfile_tmp) ret["result"] = None if cib_create_required: ret["comment"] += "CIB {} is set to be created/updated\n".format(cibname) if cib_cksum_required: ret["comment"] += "CIB {} checksum is set to be created/updated\n".format( cibname ) return ret if cib_create_required: __salt__["file.move"](cibfile_tmp, cibfile) if __salt__["file.check_hash"](path=cibfile, file_hash=cib_hash_live): ret["comment"] += "Created/updated CIB {}\n".format(cibname) ret["changes"].update({"cibfile": cibfile}) else: ret["result"] = False ret["comment"] += "Failed to create/update CIB {}\n".format(cibname) if cib_cksum_required: _file_write(cibfile_cksum, cib_hash_live) if _file_read(cibfile_cksum) in [cib_hash_live]: ret["comment"] += "Created/updated checksum {} of CIB {}\n".format( cib_hash_live, cibname ) ret["changes"].update({"cibcksum": cib_hash_live}) else: ret["result"] = False ret["comment"] += "Failed to create/update checksum {} CIB {}\n".format( cib_hash_live, cibname ) log.trace("ret: %s", ret) return ret def cib_pushed(name, cibname, scope=None, extra_args=None): """ Ensure that a CIB-file is pushed if it is changed since the creation of it with pcs.cib_present Should be run on one cluster node only (there may be races) name Irrelevant, not used (recommended: {{formulaname}}__cib_pushed_{{cibname}}) cibname name/path of the file containing the CIB scope specific section of the CIB extra_args additional options for creating the CIB-file Example: .. code-block:: yaml mysql_pcs__cib_pushed_cib_for_galera: pcs.cib_pushed: - cibname: cib_for_galera - scope: None - extra_args: None """ ret = {"name": name, "result": True, "comment": "", "changes": {}} cib_hash_form = "sha256" cib_push_required = False cibfile = _get_cibfile(cibname) cibfile_cksum = _get_cibfile_cksum(cibname) if not isinstance(extra_args, (list, tuple)): extra_args = [] if not os.path.exists(cibfile): ret["result"] = False ret["comment"] += "CIB-file {} does not exist\n".format(cibfile) return ret cib_hash_cibfile = "{}:{}".format( cib_hash_form, __salt__["file.get_hash"](path=cibfile, form=cib_hash_form) ) log.trace("cib_hash_cibfile: %s", cib_hash_cibfile) if _file_read(cibfile_cksum) not in [cib_hash_cibfile]: cib_push_required = True if not cib_push_required: ret[ "comment" ] += "CIB {} is not changed since creation through pcs.cib_present\n".format( cibname ) return ret if __opts__["test"]: ret["result"] = None ret["comment"] += "CIB {} is set to be pushed as the new live CIB\n".format( cibname ) return ret cib_push = __salt__["pcs.cib_push"]( cibfile=cibfile, scope=scope, extra_args=extra_args ) log.trace("Output of pcs.cib_push: %s", cib_push) if cib_push["retcode"] in [0]: ret["comment"] += "Pushed CIB {}\n".format(cibname) ret["changes"].update({"cibfile_pushed": cibfile}) else: ret["result"] = False ret["comment"] += "Failed to push CIB {}\n".format(cibname) log.trace("ret: %s", ret) return ret def prop_has_value(name, prop, value, extra_args=None, cibname=None): """ Ensure that a property in the cluster is set to a given value Should be run on one cluster node only (there may be races) name Irrelevant, not used (recommended: pcs_properties__prop_has_value_{{prop}}) prop name of the property value value of the property extra_args additional options for the pcs property command cibname use a cached CIB-file named like cibname instead of the live CIB Example: .. code-block:: yaml pcs_properties__prop_has_value_no-quorum-policy: pcs.prop_has_value: - prop: no-quorum-policy - value: ignore - cibname: cib_for_cluster_settings """ return _item_present( name=name, item="property", item_id="{}={}".format(prop, value), item_type=None, create="set", extra_args=extra_args, cibname=cibname, ) def resource_defaults_to(name, default, value, extra_args=None, cibname=None): """ Ensure a resource default in the cluster is set to a given value Should be run on one cluster node only (there may be races) Can only be run on a node with a functional pacemaker/corosync name Irrelevant, not used (recommended: pcs_properties__resource_defaults_to_{{default}}) default name of the default resource property value value of the default resource property extra_args additional options for the pcs command cibname use a cached CIB-file named like cibname instead of the live CIB Example: .. code-block:: yaml pcs_properties__resource_defaults_to_resource-stickiness: pcs.resource_defaults_to: - default: resource-stickiness - value: 100 - cibname: cib_for_cluster_settings """ return _item_present( name=name, item="resource", item_id="{}={}".format(default, value), item_type=None, show="defaults", create="defaults", extra_args=extra_args, cibname=cibname, ) def resource_op_defaults_to(name, op_default, value, extra_args=None, cibname=None): """ Ensure a resource operation default in the cluster is set to a given value Should be run on one cluster node only (there may be races) Can only be run on a node with a functional pacemaker/corosync name Irrelevant, not used (recommended: pcs_properties__resource_op_defaults_to_{{op_default}}) op_default name of the operation default resource property value value of the operation default resource property extra_args additional options for the pcs command cibname use a cached CIB-file named like cibname instead of the live CIB Example: .. code-block:: yaml pcs_properties__resource_op_defaults_to_monitor-interval: pcs.resource_op_defaults_to: - op_default: monitor-interval - value: 60s - cibname: cib_for_cluster_settings """ return _item_present( name=name, item="resource", item_id="{}={}".format(op_default, value), item_type=None, show=["op", "defaults"], create=["op", "defaults"], extra_args=extra_args, cibname=cibname, ) def stonith_present( name, stonith_id, stonith_device_type, stonith_device_options=None, cibname=None ): """ Ensure that a fencing resource is created Should be run on one cluster node only (there may be races) Can only be run on a node with a functional pacemaker/corosync name Irrelevant, not used (recommended: pcs_stonith__created_{{stonith_id}}) stonith_id name for the stonith resource stonith_device_type name of the stonith agent fence_eps, fence_xvm f.e. stonith_device_options additional options for creating the stonith resource cibname use a cached CIB-file named like cibname instead of the live CIB Example: .. code-block:: yaml pcs_stonith__created_eps_fence: pcs.stonith_present: - stonith_id: eps_fence - stonith_device_type: fence_eps - stonith_device_options: - 'pcmk_host_map=node1.example.org:01;node2.example.org:02' - 'ipaddr=myepsdevice.example.org' - 'power_wait=5' - 'verbose=1' - 'debug=/var/log/pcsd/eps_fence.log' - 'login=hidden' - 'passwd=hoonetorg' - cibname: cib_for_stonith """ return _item_present( name=name, item="stonith", item_id=stonith_id, item_type=stonith_device_type, extra_args=stonith_device_options, cibname=cibname, ) def resource_present( name, resource_id, resource_type, resource_options=None, cibname=None ): """ Ensure that a resource is created Should be run on one cluster node only (there may be races) Can only be run on a node with a functional pacemaker/corosync name Irrelevant, not used (recommended: {{formulaname}}__resource_present_{{resource_id}}) resource_id name for the resource resource_type resource type (f.e. ocf:heartbeat:IPaddr2 or VirtualIP) resource_options additional options for creating the resource cibname use a cached CIB-file named like cibname instead of the live CIB Example: .. code-block:: yaml mysql_pcs__resource_present_galera: pcs.resource_present: - resource_id: galera - resource_type: "ocf:heartbeat:galera" - resource_options: - 'wsrep_cluster_address=gcomm://node1.example.org,node2.example.org,node3.example.org' - '--master' - cibname: cib_for_galera """ return _item_present( name=name, item="resource", item_id=resource_id, item_type=resource_type, extra_args=resource_options, cibname=cibname, ) def constraint_present( name, constraint_id, constraint_type, constraint_options=None, cibname=None ): """ Ensure that a constraint is created Should be run on one cluster node only (there may be races) Can only be run on a node with a functional pacemaker/corosync name Irrelevant, not used (recommended: {{formulaname}}__constraint_present_{{constraint_id}}) constraint_id name for the constraint (try first to create manually to find out the autocreated name) constraint_type constraint type (location, colocation, order) constraint_options options for creating the constraint cibname use a cached CIB-file named like cibname instead of the live CIB Example: .. code-block:: yaml haproxy_pcs__constraint_present_colocation-vip_galera-haproxy-clone-INFINITY: pcs.constraint_present: - constraint_id: colocation-vip_galera-haproxy-clone-INFINITY - constraint_type: colocation - constraint_options: - 'add' - 'vip_galera' - 'with' - 'haproxy-clone' - cibname: cib_for_haproxy """ return _item_present( name=name, item="constraint", item_id=constraint_id, item_type=constraint_type, create=None, extra_args=constraint_options, cibname=cibname, )
Save