Repository: saltstack/salt
Pull request: Update pcs support for > 0.10
### What does this PR do?
This PR accommodates the cluster auth and setup when using newer version of PCS.

### What issues does this PR fix or reference?
Fixes: #56924

### Previous Behavior
When authenticating and setting up a cluster the command would fail against pcs < 0.10

### New Behavior
Creating and authenticating the cluster is successful. 

### Merge requirements satisfied?
**[NOTICE] Bug fixes or features added to Salt require tests.**
<!-- Please review the [test documentation](https://docs.saltstack.com/en/master/topics/tutorials/writing_tests.html) for details on how to implement tests into Salt's test suite. -->
- [ ] Docs
- [x] Changelog - https://docs.saltstack.com/en/master/topics/development/changelog.html
- [x] Tests written/updated

### Commits signed with GPG?
No


Problem statement:
[FEATURE] PCS module/state broken for Pacemaker 2.x
**Description**
Debian Buster saw a version change for both their ```pcs``` and ```pacemaker``` packages. Pacemaker moved from 1.x to 2.x, and it looks like some of the related PCS syntax has changed enough to break the current Salt PCS module/state.

**Setup**

I'm running ```2019.2.2``` but there have been no changes of consequence to this module since then.

**Steps to Reproduce the behavior**
 * ```pcs.auth``` is broken because the authentication approach/syntax has changed
 * ```pcs.resource_present``` fails with the following error:
   ```
   [ERROR   ] Command '['pcs', '-f', '/var/cache/salt/minion/pcs/base/cib.cib', 'resource', 'show', 
   'drbd']' failed with return code: 1
   [ERROR   ] stdout:
   ```
   This seems to be because the syntax of ```pcs resource show``` has changed.

**Expected behavior**

That pcs for both the 1.x and 2.x versions of Pacemaker would continue to work.

Hints from issue discussion:
Including some additional context about the two changes I reported, there are undoubtedly more. This is from the ClusterLabs doc for Pacemaker 2.x:  https://clusterlabs.org/pacemaker/doc/en-US/Pacemaker/2.0/html/Clusters_from_Scratch

 * The command has been changed from ```pcs cluster auth```to ```pcs host auth``` (```pcs cluster auth``` still works, but authorizes all nodes in the cluster based on ```corosync.conf```, I think)
 * To avoid confusion whether the ```pcs resource show``` command displays resources' status or configuration, the command has been deprecated. Two new commands have been introduced for displaying resources' status and configuration: ```pcs resource status``` and ```pcs resource config```, respectively.
Maybe try passing `config` in the `show` parameter in your state. It looks like it uses `pcs resource config` now instead of `pcs resource show`. The `show` parameter is configurable.

Not sure where to find all the syntax differences between the two. I found some here, but I'm not sure if this is the right place.

https://github.com/ClusterLabs/pacemaker/blob/master/doc/pcs-crmsh-quick-ref.md

This state and execution module will need to be modified to detect the version of pcs installed and work with both.
Hitting this as well as Debian 10 ships Pacemaker 2.x by default.
Redhat/CentOS 8.X HA repos ship Pacemaker 2.X so these run into the same problem too.

Commit message: Merge branch 'master' of https://github.com/waynegemmell/salt

Patch to review:
diff --git a/changelog/56924.fixed b/changelog/56924.fixed
new file mode 100644
index 000000000000..3335977350f4
--- /dev/null
+++ b/changelog/56924.fixed
@@ -0,0 +1 @@
+Updated pcs support to handle auth and setup for new syntax supporting version 0.10
diff --git a/salt/modules/pcs.py b/salt/modules/pcs.py
index bf7711436df6..4a8b51748dfc 100644
--- a/salt/modules/pcs.py
+++ b/salt/modules/pcs.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 """
 Configure a Pacemaker/Corosync cluster with PCS
 ===============================================
@@ -10,11 +9,12 @@
 
 .. versionadded:: 2016.3.0
 """
-from __future__ import absolute_import, print_function, unicode_literals
 
-# Import salt libs
+import logging
+
 import salt.utils.path
-from salt.ext import six
+
+log = logging.getLogger(__name__)
 
 
 def __virtual__():
@@ -26,6 +26,23 @@ def __virtual__():
     return (False, "Missing dependency: pcs")
 
 
+def __use_new_commands():
+    """
+    The command line arguments of pcs changed after version 0.10
+    This will return True if the new arguments are needed and
+    false if the ole ones are needed
+    """
+    pcs_version = __salt__["pkg.version"]("pcs")
+    log.debug("PCS package version %s", pcs_version)
+
+    if __salt__["pkg.version_cmp"](pcs_version, "0.10") == 1:
+        log.info("New version, new rules")
+        return True
+    else:
+        log.info("Old Version")
+        return False
+
+
 def item_show(
     item, item_id=None, item_type=None, show="show", extra_args=None, cibfile=None
 ):
@@ -48,10 +65,10 @@ def item_show(
     """
     cmd = ["pcs"]
 
-    if isinstance(cibfile, six.string_types):
+    if isinstance(cibfile, str):
         cmd += ["-f", cibfile]
 
-    if isinstance(item, six.string_types):
+    if isinstance(item, str):
         cmd += [item]
     elif isinstance(item, (list, tuple)):
         cmd += item
@@ -60,12 +77,12 @@ def item_show(
     if item in ["constraint"]:
         cmd += [item_type]
 
-    if isinstance(show, six.string_types):
+    if isinstance(show, str):
         cmd += [show]
     elif isinstance(show, (list, tuple)):
         cmd += show
 
-    if isinstance(item_id, six.string_types):
+    if isinstance(item_id, str):
         cmd += [item_id]
 
     if isinstance(extra_args, (list, tuple)):
@@ -75,7 +92,7 @@ def item_show(
     if item in ["constraint"]:
         if not isinstance(extra_args, (list, tuple)) or "--full" not in extra_args:
             cmd += ["--full"]
-
+    log.debug("Running item show %s", cmd)
     return __salt__["cmd.run_all"](cmd, output_loglevel="trace", python_shell=False)
 
 
@@ -100,20 +117,20 @@ def item_create(
         use cibfile instead of the live CIB
     """
     cmd = ["pcs"]
-    if isinstance(cibfile, six.string_types):
+    if isinstance(cibfile, str):
         cmd += ["-f", cibfile]
 
-    if isinstance(item, six.string_types):
+    if isinstance(item, str):
         cmd += [item]
     elif isinstance(item, (list, tuple)):
         cmd += item
 
     # constraint command follows a different order
     if item in ["constraint"]:
-        if isinstance(item_type, six.string_types):
+        if isinstance(item_type, str):
             cmd += [item_type]
 
-    if isinstance(create, six.string_types):
+    if isinstance(create, str):
         cmd += [create]
     elif isinstance(create, (list, tuple)):
         cmd += create
@@ -122,13 +139,13 @@ def item_create(
     # constraint command follows a different order
     if item not in ["constraint"]:
         cmd += [item_id]
-        if isinstance(item_type, six.string_types):
+        if isinstance(item_type, str):
             cmd += [item_type]
 
     if isinstance(extra_args, (list, tuple)):
         # constraint command needs item_id in format 'id=<id' after all params
         if item in ["constraint"]:
-            extra_args = extra_args + ["id={0}".format(item_id)]
+            extra_args = extra_args + ["id={}".format(item_id)]
         cmd += extra_args
 
     return __salt__["cmd.run_all"](cmd, output_loglevel="trace", python_shell=False)
@@ -151,9 +168,12 @@ def auth(nodes, pcsuser="hacluster", pcspasswd="hacluster", extra_args=None):
 
     .. code-block:: bash
 
-        salt '*' pcs.auth nodes='[ node1.example.org node2.example.org ]' pcsuser=hacluster pcspasswd=hoonetorg extra_args="[ '--force' ]"
+        salt '*' pcs.auth nodes='[ node1.example.org node2.example.org ]' pcsuser=hacluster pcspasswd=hoonetorg"
     """
-    cmd = ["pcs", "cluster", "auth"]
+    if __use_new_commands():
+        cmd = ["pcs", "host", "auth"]
+    else:
+        cmd = ["pcs", "cluster", "auth"]
 
     if pcsuser:
         cmd += ["-u", pcsuser]
@@ -168,22 +188,39 @@ def auth(nodes, pcsuser="hacluster", pcspasswd="hacluster", extra_args=None):
     return __salt__["cmd.run_all"](cmd, output_loglevel="trace", python_shell=False)
 
 
-def is_auth(nodes):
+def is_auth(nodes, pcsuser="hacluster", pcspasswd="hacluster"):
     """
     Check if nodes are already authorized
 
     nodes
         a list of nodes to be checked for authorization to the cluster
+    pcsuser
+        user for communitcation with PCS (default: hacluster)
+    pcspasswd
+        password for pcsuser (default: hacluster)
 
     CLI Example:
 
     .. code-block:: bash
 
-        salt '*' pcs.is_auth nodes='[node1.example.org node2.example.org]'
+        salt '*' pcs.is_auth nodes='[node1.example.org node2.example.org]' pcsuser=hacluster pcspasswd=hoonetorg
     """
-    cmd = ["pcs", "cluster", "auth"]
-    cmd += nodes
+    if __use_new_commands():
+
+        cmd = ["pcs", "host", "auth"]
 
+        if pcsuser:
+            cmd += ["-u", pcsuser]
+
+        if pcspasswd:
+            cmd += ["-p", pcspasswd]
+
+        cmd += nodes
+    else:
+        cmd = ["pcs", "cluster", "auth"]
+        cmd += nodes
+
+    log.info(str(("Commands: ", cmd)))
     return __salt__["cmd.run_all"](
         cmd, stdin="\n\n", output_loglevel="trace", python_shell=False
     )
@@ -208,12 +245,17 @@ def cluster_setup(nodes, pcsclustername="pcscluster", extra_args=None):
     """
     cmd = ["pcs", "cluster", "setup"]
 
-    cmd += ["--name", pcsclustername]
+    if __use_new_commands():
+        cmd += [pcsclustername]
+    else:
+        cmd += ["--name", pcsclustername]
 
     cmd += nodes
     if isinstance(extra_args, (list, tuple)):
         cmd += extra_args
 
+    log.debug("Running cluster setup: %s", cmd)
+
     return __salt__["cmd.run_all"](cmd, output_loglevel="trace", python_shell=False)
 
 
@@ -259,8 +301,8 @@ def cib_create(cibfile, scope="configuration", extra_args=None):
         salt '*' pcs.cib_create cibfile='/tmp/VIP_apache_1.cib' scope=False
     """
     cmd = ["pcs", "cluster", "cib", cibfile]
-    if isinstance(scope, six.string_types):
-        cmd += ["scope={0}".format(scope)]
+    if isinstance(scope, str):
+        cmd += ["scope={}".format(scope)]
     if isinstance(extra_args, (list, tuple)):
         cmd += extra_args
 
@@ -285,8 +327,8 @@ def cib_push(cibfile, scope="configuration", extra_args=None):
         salt '*' pcs.cib_push cibfile='/tmp/VIP_apache_1.cib' scope=False
     """
     cmd = ["pcs", "cluster", "cib-push", cibfile]
-    if isinstance(scope, six.string_types):
-        cmd += ["scope={0}".format(scope)]
+    if isinstance(scope, str):
+        cmd += ["scope={}".format(scope)]
     if isinstance(extra_args, (list, tuple)):
         cmd += extra_args
 
@@ -352,7 +394,7 @@ def prop_set(prop, value, extra_args=None, cibfile=None):
     """
     return item_create(
         item="property",
-        item_id="{0}={1}".format(prop, value),
+        item_id="{}={}".format(prop, value),
         item_type=None,
         create="set",
         extra_args=extra_args,
diff --git a/salt/states/pcs.py b/salt/states/pcs.py
index 18a59e44fb6e..f1f19f165f39 100644
--- a/salt/states/pcs.py
+++ b/salt/states/pcs.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 """
 Management of Pacemaker/Corosync clusters with PCS
 ==================================================
@@ -162,20 +161,14 @@
 
 .. versionadded:: 2016.3.0
 """
-from __future__ import absolute_import, print_function, unicode_literals
 
-# Import Python libs
 import logging
 import os
 
-# Import Salt libs
 import salt.utils.files
 import salt.utils.path
 import salt.utils.stringutils
 
-# Import 3rd-party libs
-from salt.ext import six
-
 log = logging.getLogger(__name__)
 
 
@@ -222,7 +215,7 @@ 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(), "{0}.{1}".format(cibname, "cib"))
+    cibfile = os.path.join(_get_cibpath(), "{}.{}".format(cibname, "cib"))
     log.trace("cibfile: %s", cibfile)
     return cibfile
 
@@ -231,7 +224,7 @@ def _get_cibfile_tmp(cibname):
     """
     Get the full path of a temporary CIB-file with the name of the CIB
     """
-    cibfile_tmp = "{0}.tmp".format(_get_cibfile(cibname))
+    cibfile_tmp = "{}.tmp".format(_get_cibfile(cibname))
     log.trace("cibfile_tmp: %s", cibfile_tmp)
     return cibfile_tmp
 
@@ -240,11 +233,25 @@ 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 = "{0}.cksum".format(_get_cibfile(cibname))
+    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,
@@ -279,7 +286,7 @@ def _item_present(
     item_create_required = True
 
     cibfile = None
-    if isinstance(cibname, six.string_types):
+    if isinstance(cibname, str):
         cibfile = _get_cibfile(cibname)
 
     if not isinstance(extra_args, (list, tuple)):
@@ -324,7 +331,7 @@ def _item_present(
     # constraints match on '(id:<id>)'
     elif item in ["constraint"]:
         for line in is_existing["stdout"].splitlines():
-            if "(id:{0})".format(item_id) in line:
+            if "(id:{})".format(item_id) in line:
                 item_create_required = False
 
     # item_id was provided,
@@ -334,15 +341,15 @@ def _item_present(
             item_create_required = False
 
     if not item_create_required:
-        ret["comment"] += "{0} {1} ({2}) is already existing\n".format(
-            six.text_type(item), six.text_type(item_id), six.text_type(item_type)
+        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"] += "{0} {1} ({2}) is set to be created\n".format(
-            six.text_type(item), six.text_type(item_id), six.text_type(item_type)
+        ret["comment"] += "{} {} ({}) is set to be created\n".format(
+            str(item), str(item_id), str(item_type)
         )
         return ret
 
@@ -358,11 +365,11 @@ def _item_present(
     log.trace("Output of pcs.item_create: %s", item_create)
 
     if item_create["retcode"] in [0]:
-        ret["comment"] += "Created {0} {1} ({2})\n".format(item, item_id, item_type)
-        ret["changes"].update({item_id: {"old": "", "new": six.text_type(item_id)}})
+        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 {0} {1} ({2})\n".format(
+        ret["comment"] += "Failed to create {} {} ({})\n".format(
             item, item_id, item_type
         )
 
@@ -403,7 +410,11 @@ def auth(name, nodes, pcsuser="hacluster", pcspasswd="hacluster", extra_args=Non
     ret = {"name": name, "result": True, "comment": "", "changes": {}}
     auth_required = False
 
-    authorized = __salt__["pcs.is_auth"](nodes=nodes)
+    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 = {}
@@ -415,12 +426,15 @@ def auth(name, nodes, pcsuser="hacluster", pcspasswd="hacluster", extra_args=Non
     log.trace("authorized_dict: %s", authorized_dict)
 
     for node in nodes:
-        if node in authorized_dict and authorized_dict[node] == "Already authorized":
-            ret["comment"] += "Node {0} is already authorized\n".format(node)
+        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: {0}\n".format(node)
+                ret["comment"] += "Node is set to authorize: {}\n".format(node)
 
     if not auth_required:
         return ret
@@ -430,8 +444,6 @@ def auth(name, nodes, pcsuser="hacluster", pcspasswd="hacluster", extra_args=Non
         return ret
     if not isinstance(extra_args, (list, tuple)):
         extra_args = []
-    if "--force" not in extra_args:
-        extra_args += ["--force"]
 
     authorize = __salt__["pcs.auth"](
         nodes=nodes, pcsuser=pcsuser, pcspasswd=pcspasswd, extra_args=extra_args
@@ -448,18 +460,18 @@ def auth(name, nodes, pcsuser="hacluster", pcspasswd="hacluster", extra_args=Non
 
     for node in nodes:
         if node in authorize_dict and authorize_dict[node] == "Authorized":
-            ret["comment"] += "Authorized {0}\n".format(node)
+            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 {0} returned: {1}\n".format(
+                ] += "Authorization check for node {} returned: {}\n".format(
                     node, authorized_dict[node]
                 )
             if node in authorize_dict:
-                ret["comment"] += "Failed to authorize {0} with error {1}\n".format(
+                ret["comment"] += "Failed to authorize {} with error {}\n".format(
                     node, authorize_dict[node]
                 )
 
@@ -508,23 +520,26 @@ def cluster_setup(name, nodes, pcsclustername="pcscluster", extra_args=None):
             value = line.split(":")[1].strip()
             if key in ["Cluster Name"]:
                 if value in [pcsclustername]:
-                    ret["comment"] += "Cluster {0} is already set up\n".format(
+                    ret["comment"] += "Cluster {} is already set up\n".format(
                         pcsclustername
                     )
                 else:
                     setup_required = True
                     if __opts__["test"]:
-                        ret["comment"] += "Cluster {0} is set to set up\n".format(
+                        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
 
+    nodes = _get_node_list_for_version(nodes)
+
     if not isinstance(extra_args, (list, tuple)):
         extra_args = []
 
@@ -546,17 +561,19 @@ def cluster_setup(name, nodes, pcsclustername="pcscluster", extra_args=None):
     log.trace("setup_dict: %s", setup_dict)
 
     for node in nodes:
-        if node in setup_dict and setup_dict[node] in ["Succeeded", "Success"]:
-            ret["comment"] += "Set up {0}\n".format(node)
+        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 {0}\n".format(node)
+            ret["comment"] += "Failed to setup {}\n".format(node)
             if node in setup_dict:
-                ret["comment"] += "{0}: setup_dict: {1}\n".format(
-                    node, setup_dict[node]
-                )
-            ret["comment"] += six.text_type(setup)
+                ret["comment"] += "{}: setup_dict: {}\n".format(node, setup_dict[node])
+            ret["comment"] += str(setup)
 
     log.trace("ret: %s", ret)
 
@@ -609,7 +626,7 @@ def cluster_node_present(name, node, extra_args=None):
                         node_add_required = False
                         ret[
                             "comment"
-                        ] += "Node {0} is already member of the cluster\n".format(node)
+                        ] += "Node {} is already member of the cluster\n".format(node)
                     else:
                         current_nodes += value.split()
 
@@ -618,7 +635,7 @@ def cluster_node_present(name, node, extra_args=None):
 
     if __opts__["test"]:
         ret["result"] = None
-        ret["comment"] += "Node {0} is set to be added to the cluster\n".format(node)
+        ret["comment"] += "Node {} is set to be added to the cluster\n".format(node)
         return ret
 
     if not isinstance(extra_args, (list, tuple)):
@@ -642,29 +659,29 @@ def cluster_node_present(name, node, extra_args=None):
         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 {0}\n".format(
+                ret["comment"] += "Failed to update corosync.conf on node {}\n".format(
                     current_node
                 )
-                ret["comment"] += "{0}: node_add_dict: {1}\n".format(
+                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 {0}\n".format(
+            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 {0}\n".format(node)
+        ret["comment"] += "Added node {}\n".format(node)
         ret["changes"].update({node: {"old": "", "new": "Added"}})
     else:
         ret["result"] = False
-        ret["comment"] += "Failed to add node{0}\n".format(node)
+        ret["comment"] += "Failed to add node{}\n".format(node)
         if node in node_add_dict:
-            ret["comment"] += "{0}: node_add_dict: {1}\n".format(
+            ret["comment"] += "{}: node_add_dict: {}\n".format(
                 node, node_add_dict[node]
             )
-        ret["comment"] += six.text_type(node_add)
+        ret["comment"] += str(node_add)
 
     log.trace("ret: %s", ret)
 
@@ -683,7 +700,7 @@ def cib_present(name, cibname, scope=None, extra_args=None):
     cibname
         name/path of the file containing the CIB
     scope
-        specific section of the CIB (default:
+        specific section of the CIB (default: None)
     extra_args
         additional options for creating the CIB-file
 
@@ -729,7 +746,7 @@ def cib_present(name, cibname, scope=None, extra_args=None):
         ret["comment"] += "Failed to get live CIB\n"
         return ret
 
-    cib_hash_live = "{0}:{1}".format(
+    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)
@@ -751,10 +768,10 @@ def cib_present(name, cibname, scope=None, extra_args=None):
 
     if not cib_create_required:
         __salt__["file.remove"](cibfile_tmp)
-        ret["comment"] += "CIB {0} is already equal to the live CIB\n".format(cibname)
+        ret["comment"] += "CIB {} is already equal to the live CIB\n".format(cibname)
 
     if not cib_cksum_required:
-        ret["comment"] += "CIB {0} checksum is correct\n".format(cibname)
+        ret["comment"] += "CIB {} checksum is correct\n".format(cibname)
 
     if not cib_required:
         return ret
@@ -763,9 +780,9 @@ def cib_present(name, cibname, scope=None, extra_args=None):
         __salt__["file.remove"](cibfile_tmp)
         ret["result"] = None
         if cib_create_required:
-            ret["comment"] += "CIB {0} is set to be created/updated\n".format(cibname)
+            ret["comment"] += "CIB {} is set to be created/updated\n".format(cibname)
         if cib_cksum_required:
-            ret["comment"] += "CIB {0} checksum is set to be created/updated\n".format(
+            ret["comment"] += "CIB {} checksum is set to be created/updated\n".format(
                 cibname
             )
         return ret
@@ -774,23 +791,23 @@ def cib_present(name, cibname, scope=None, extra_args=None):
         __salt__["file.move"](cibfile_tmp, cibfile)
 
         if __salt__["file.check_hash"](path=cibfile, file_hash=cib_hash_live):
-            ret["comment"] += "Created/updated CIB {0}\n".format(cibname)
+            ret["comment"] += "Created/updated CIB {}\n".format(cibname)
             ret["changes"].update({"cibfile": cibfile})
         else:
             ret["result"] = False
-            ret["comment"] += "Failed to create/update CIB {0}\n".format(cibname)
+            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 {0} of CIB {1}\n".format(
+            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 {0} CIB {1}\n".format(
+            ret["comment"] += "Failed to create/update checksum {} CIB {}\n".format(
                 cib_hash_live, cibname
             )
 
@@ -839,10 +856,10 @@ def cib_pushed(name, cibname, scope=None, extra_args=None):
 
     if not os.path.exists(cibfile):
         ret["result"] = False
-        ret["comment"] += "CIB-file {0} does not exist\n".format(cibfile)
+        ret["comment"] += "CIB-file {} does not exist\n".format(cibfile)
         return ret
 
-    cib_hash_cibfile = "{0}:{1}".format(
+    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)
@@ -853,14 +870,14 @@ def cib_pushed(name, cibname, scope=None, extra_args=None):
     if not cib_push_required:
         ret[
             "comment"
-        ] += "CIB {0} is not changed since creation through pcs.cib_present\n".format(
+        ] += "CIB {} is not changed since creation through pcs.cib_present\n".format(
             cibname
         )
         return ret
 
     if __opts__["test"]:
         ret["result"] = None
-        ret["comment"] += "CIB {0} is set to be pushed as the new live CIB\n".format(
+        ret["comment"] += "CIB {} is set to be pushed as the new live CIB\n".format(
             cibname
         )
         return ret
@@ -871,11 +888,11 @@ def cib_pushed(name, cibname, scope=None, extra_args=None):
     log.trace("Output of pcs.cib_push: %s", cib_push)
 
     if cib_push["retcode"] in [0]:
-        ret["comment"] += "Pushed CIB {0}\n".format(cibname)
+        ret["comment"] += "Pushed CIB {}\n".format(cibname)
         ret["changes"].update({"cibfile_pushed": cibfile})
     else:
         ret["result"] = False
-        ret["comment"] += "Failed to push CIB {0}\n".format(cibname)
+        ret["comment"] += "Failed to push CIB {}\n".format(cibname)
 
     log.trace("ret: %s", ret)
 
@@ -913,7 +930,7 @@ def prop_has_value(name, prop, value, extra_args=None, cibname=None):
     return _item_present(
         name=name,
         item="property",
-        item_id="{0}={1}".format(prop, value),
+        item_id="{}={}".format(prop, value),
         item_type=None,
         create="set",
         extra_args=extra_args,
@@ -953,7 +970,7 @@ def resource_defaults_to(name, default, value, extra_args=None, cibname=None):
     return _item_present(
         name=name,
         item="resource",
-        item_id="{0}={1}".format(default, value),
+        item_id="{}={}".format(default, value),
         item_type=None,
         show="defaults",
         create="defaults",
@@ -994,7 +1011,7 @@ def resource_op_defaults_to(name, op_default, value, extra_args=None, cibname=No
     return _item_present(
         name=name,
         item="resource",
-        item_id="{0}={1}".format(op_default, value),
+        item_id="{}={}".format(op_default, value),
         item_type=None,
         show=["op", "defaults"],
         create=["op", "defaults"],


Code review comments:
diff_hunk: @@ -168,22 +188,39 @@ def auth(nodes, pcsuser="hacluster", pcspasswd="hacluster", extra_args=None):
     return __salt__["cmd.run_all"](cmd, output_loglevel="trace", python_shell=False)
 
 
-def is_auth(nodes):
+def is_auth(nodes, pcsuser="hacluster", pcspasswd="hacluster"):
     """
     Check if nodes are already authorized
 
     nodes
         a list of nodes to be checked for authorization to the cluster
+    pcsuser
+        user for communitcation with PCS (default: hacluster)
+    pcspasswd
+        password for pcsuser (default: hacluster)
 
     CLI Example:
 
     .. code-block:: bash
 
-        salt '*' pcs.is_auth nodes='[node1.example.org node2.example.org]'
+        salt '*' pcs.is_auth nodes='[node1.example.org node2.example.org]' pcsuser=hacluster pcspasswd=hoonetorg
     """
-    cmd = ["pcs", "cluster", "auth"]
-    cmd += nodes
+    if __use_new_commands():
+
+        cmd = ["pcs", "host", "auth"]
 
+        if pcsuser:
+            cmd += ["-u", pcsuser]
+
+        if pcspasswd:
+            cmd += ["-p", pcspasswd]
+
+        cmd += nodes
+    else:
+        cmd = ["pcs", "cluster", "auth"]
+        cmd += nodes
+
+    log.info(str(("Commands: ", cmd)))
path: salt/modules/pcs.py
text: @user1:
```suggestion
    log.info("Commands: %s", cmd)
```

diff_hunk: @@ -26,6 +26,23 @@ def __virtual__():
     return (False, "Missing dependency: pcs")
 
 
+def __use_new_commands():
+    """
+    The command line arguments of pcs changed after version 0.10
+    This will return True if the new arguments are needed and
+    false if the ole ones are needed
+    """
+    pcs_version = __salt__["pkg.version"]("pcs")
+    log.debug("PCS package version %s", pcs_version)
+
+    if __salt__["pkg.version_cmp"](pcs_version, "0.10") == 1:
+        log.info("New version, new rules")
path: salt/modules/pcs.py
text: @user1:
Please make these logs at the `debug` level.

@author:
sorted all changes