Hello community,

here is the log from the commit of package salt-shaptools for openSUSE:Factory 
checked in at 2019-12-09 21:35:49
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/salt-shaptools (Old)
 and      /work/SRC/openSUSE:Factory/.salt-shaptools.new.4691 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "salt-shaptools"

Mon Dec  9 21:35:49 2019 rev:5 rq:755180 version:0.2.5

Changes:
--------
--- /work/SRC/openSUSE:Factory/salt-shaptools/salt-shaptools.changes    
2019-11-22 10:27:44.909232429 +0100
+++ /work/SRC/openSUSE:Factory/.salt-shaptools.new.4691/salt-shaptools.changes  
2019-12-09 21:36:05.962077454 +0100
@@ -1,0 +2,11 @@
+Tue Dec  3 06:41:36 UTC 2019 - nick wang <[email protected]>
+
+- Version 0.2.5
+  DRBD: support to get status via json format by default.
+
+-------------------------------------------------------------------
+Thu Nov 21 09:05:07 UTC 2019 - nick wang <[email protected]>
+
+- Version 0.2.4, fix error parsing drbd status when congested.
+
+-------------------------------------------------------------------

Old:
----
  salt-shaptools-0.2.3.tar.gz

New:
----
  salt-shaptools-0.2.5.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ salt-shaptools.spec ++++++
--- /var/tmp/diff_new_pack.jAkuvr/_old  2019-12-09 21:36:07.366076901 +0100
+++ /var/tmp/diff_new_pack.jAkuvr/_new  2019-12-09 21:36:07.366076901 +0100
@@ -19,7 +19,7 @@
 # See also https://en.opensuse.org/openSUSE:Specfile_guidelines
 
 Name:           salt-shaptools
-Version:        0.2.3
+Version:        0.2.5
 Release:        0
 Summary:        Salt modules and states for SAP Applications and SLE-HA 
components management
 

++++++ salt-shaptools-0.2.3.tar.gz -> salt-shaptools-0.2.5.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/salt-shaptools-0.2.3/salt/modules/crmshmod.py 
new/salt-shaptools-0.2.5/salt/modules/crmshmod.py
--- old/salt-shaptools-0.2.3/salt/modules/crmshmod.py   2019-11-06 
09:36:32.167389490 +0100
+++ new/salt-shaptools-0.2.5/salt/modules/crmshmod.py   2019-12-09 
03:44:43.029007691 +0100
@@ -50,9 +50,6 @@
         version = __salt__['pkg.version'](CRMSH)
         use_crm = __salt__['pkg.version_cmp'](
             version, CRM_NEW_VERSION) >= 0
-        LOGGER.info('crmsh version: %s', version)
-        LOGGER.info(
-            '%s will be used', 'crm' if use_crm else 'ha-cluster')
 
     else:
         return (
@@ -66,7 +63,7 @@
             'The crmsh execution module failed to load: the ha-cluster-init'
             ' package is not available.')
 
-    __salt__['crmsh.version'] = use_crm
+    __salt__['crm.version'] = use_crm
     return __virtualname__
 
 
@@ -389,7 +386,7 @@
     '''
     # INFO: 2 different methods are created to make easy to read/understand
     # and create the corresponing UT
-    if __salt__['crmsh.version']:
+    if __salt__['crm.version']:
         return _crm_init(
             name, watchdog, interface, unicast, admin_ip, sbd, sbd_dev, quiet)
 
@@ -475,7 +472,7 @@
     '''
     # INFO: 2 different methods are created to make easy to read/understand
     # and create the corresponing UT
-    if __salt__['crmsh.version']:
+    if __salt__['crm.version']:
         return _crm_join(host, watchdog, interface, quiet)
 
     return _ha_cluster_join(host, watchdog, interface, quiet)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/salt-shaptools-0.2.3/salt/modules/drbdmod.py 
new/salt-shaptools-0.2.5/salt/modules/drbdmod.py
--- old/salt-shaptools-0.2.3/salt/modules/drbdmod.py    2019-11-06 
09:36:32.167389490 +0100
+++ new/salt-shaptools-0.2.5/salt/modules/drbdmod.py    2019-12-09 
03:44:43.029007691 +0100
@@ -30,6 +30,12 @@
 __virtualname__ = 'drbd'
 
 DRBD_COMMAND = 'drbdadm'
+ERR_STR = 'UNKNOWN'
+DUMMY_STR = 'IGNORED'
+WITH_JSON = True
+DRBDADM = 'drbd-utils'
+# drbd-utils >= 9.0.0 for json status
+DRBDADM_JSON_VERSION = '9.0.0'
 
 
 def __virtual__():  # pragma: no cover
@@ -37,6 +43,14 @@
     Only load this module if drbdadm(drbd-utils) is installed
     '''
     if bool(salt.utils.path.which(DRBD_COMMAND)):
+        __salt__['drbd.json'] = WITH_JSON
+
+        version = __salt__['pkg.version'](DRBDADM)
+        json_support = __salt__['pkg.version_cmp'](version,
+            DRBDADM_JSON_VERSION) >= 0
+        if not json_support:
+            __salt__['drbd.json'] = False
+
         return __virtualname__
     return (
         False,
@@ -85,10 +99,12 @@
     switch = {
         0: 'RESOURCE',
         2: {' disk:': 'LOCALDISK', ' role:': 'PEERNODE', ' connection:': 
'PEERNODE'},
-        4: {' peer-disk:': 'PEERDISK'}
+        4: {' peer-disk:': 'PEERDISK'},
+        6: DUMMY_STR,
+        8: DUMMY_STR,
     }
 
-    ret = switch.get(spaces, 'UNKNOWN')
+    ret = switch.get(spaces, ERR_STR)
 
     # isinstance(ret, str) only works when run directly, calling need 
unicode(six)
     if isinstance(ret, six.text_type):
@@ -98,6 +114,9 @@
         if x in line:
             return ret[x]
 
+    # Doesn't find expected KEY in support indent
+    return ERR_STR
+
 
 def _add_res(line):
     '''
@@ -171,7 +190,7 @@
 
 def _empty(dummy):
     '''
-    Action of empty line of ``drbdadm status``
+    Action of empty line or extra verbose info of ``drbdadm status``
     '''
 
 
@@ -179,7 +198,7 @@
     '''
     Action of unsupported line of ``drbdadm status``
     '''
-    __context__['drbd.statusret'] = {"Unknown parser": line}
+    raise CommandExecutionError('The unknown line:\n' + line)
 
 
 def _line_parser(line):
@@ -195,6 +214,8 @@
         'PEERNODE': _add_peernode,
         'LOCALDISK': _add_volume,
         'PEERDISK': _add_volume,
+        DUMMY_STR: _empty,
+        ERR_STR: _unknown_parser,
     }
 
     func = switch.get(section, _unknown_parser)
@@ -206,14 +227,19 @@
     '''
     Check whether all local volumes are UpToDate.
     '''
+    if __salt__['drbd.json']:
+        output = OUTPUT_OPTIONS['json']
+    else:
+        output = OUTPUT_OPTIONS['text']
+
+    res = output["get_res_func"](name)
 
-    res = status(name)
     if not res:
         return False
 
     # Since name is not all, res only have one element
-    for vol in res[0]['local volumes']:
-        if vol['disk'] != 'UpToDate':
+    for vol in res[0][output["volume"]]:
+        if vol[output["state"]] != 'UpToDate':
             return False
 
     return True
@@ -227,19 +253,23 @@
 
         If peernode is not match, will return None, same as False.
     '''
-    ret = None
+    if __salt__['drbd.json']:
+        output = OUTPUT_OPTIONS['json']
+    else:
+        output = OUTPUT_OPTIONS['text']
+
+    res = output["get_res_func"](name)
 
-    res = status(name)
     if not res:
-        return ret
+        return False
 
     # Since name is not all, res only have one element
-    for node in res[0]['peer nodes']:
-        if peernode != 'all' and node['peernode name'] != peernode:
+    for node in res[0][output["connection"]]:
+        if peernode != 'all' and node[output["peer_node"]] != peernode:
             continue
 
-        for vol in node['peer volumes']:
-            if vol['peer-disk'] != 'UpToDate':
+        for vol in node[output["peer_node_vol"]]:
+            if vol[output["peer_node_state"]] != 'UpToDate':
                 return False
             else:
                 # At lease one volume is 'UpToDate'
@@ -365,8 +395,13 @@
         LOGGER.info('No status due to %s (%s).', result['stderr'], 
result['retcode'])
         return None
 
-    for line in result['stdout'].splitlines():
-        _line_parser(line)
+    try:
+        for line in result['stdout'].splitlines():
+            _line_parser(line)
+    except CommandExecutionError as err:
+        raise CommandExecutionError('UNKNOWN status output format found',
+                                    info=(result['stdout'] + "\n\n" +
+                                    six.text_type(err)))
 
     if __context__['drbd.resource']:
         __context__['drbd.statusret'].append(__context__['drbd.resource'])
@@ -596,18 +631,13 @@
         salt '*' drbd.setup_status name=<resource name>
     '''
 
-    ret = {'name': name,
-           'result': False,
-           'comment': ''}
-
     cmd = 'drbdsetup status --json {}'.format(name)
 
     results = __salt__['cmd.run_all'](cmd)
 
     if 'retcode' not in results or results['retcode'] != 0:
-        ret['comment'] = 'Error({}) happend when show resource via 
drbdsetup.'.format(
-            results['retcode'])
-        return ret
+        LOGGER.info('No drbdsetup status due to %s (%s).', results['stderr'], 
results['retcode'])
+        return None
 
     try:
         ret = salt.utils.json.loads(results['stdout'], strict=False)
@@ -618,6 +648,29 @@
     return ret
 
 
+# Define OUTPUT_OPTIONS after setup_status() and status() defined
+OUTPUT_OPTIONS = {
+  "json": {
+    "volume": "devices",
+    "state": "disk-state",
+    "connection": "connections",
+    "peer_node": "name",
+    "peer_node_vol": "peer_devices",
+    "peer_node_state": "peer-disk-state",
+    "get_res_func": setup_status
+  },
+  "text": {
+    "volume": "local volumes",
+    "state": "disk",
+    "connection": "peer nodes",
+    "peer_node": "peernode name",
+    "peer_node_vol": "peer volumes",
+    "peer_node_state": "peer-disk",
+    "get_res_func": status
+  }
+}
+
+
 def check_sync_status(name, peernode='all'):
     '''
     Query a drbd resource until fully synced for all volumes.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/salt-shaptools-0.2.3/salt/states/drbdmod.py 
new/salt-shaptools-0.2.5/salt/states/drbdmod.py
--- old/salt-shaptools-0.2.3/salt/states/drbdmod.py     2019-11-06 
09:36:32.167389490 +0100
+++ new/salt-shaptools-0.2.5/salt/states/drbdmod.py     2019-12-09 
03:44:43.029007691 +0100
@@ -63,6 +63,15 @@
 
 
 def _get_res_status(name):
+    if __salt__['drbd.json']:
+        res = __get_res_drbdsetup_status(name)
+    else:
+        res = __get_res_drbdadm_status(name)
+
+    return res
+
+
+def __get_res_drbdadm_status(name):
     try:
         result = __salt__['drbd.status'](name=name)
     except CommandExecutionError as err:
@@ -80,6 +89,24 @@
     return None
 
 
+def __get_res_drbdsetup_status(name):
+    try:
+        result = __salt__['drbd.setup_status'](name=name)
+    except CommandExecutionError as err:
+        LOGGER.error(six.text_type(err))
+        return None
+
+    if not result:
+        return None
+
+    for res in result:
+        if res['name'] == name:
+            LOGGER.debug(res)
+            return res
+
+    return None
+
+
 def _get_resource_list():
     ret = []
     cmd = 'drbdadm dump all'
@@ -261,6 +288,17 @@
         return ret
 
 
+# Define OUTPUT_OPTIONS before it used in promoted() and demoted()
+OUTPUT_OPTIONS = {
+  'json': {
+    'role': 'role',
+  },
+  'text': {
+    'role': 'local role',
+  }
+}
+
+
 def promoted(name, force=False):
     '''
     Make sure the DRBD resource is being primary.
@@ -285,10 +323,16 @@
         ret['comment'] = 'Resource {} not defined in your config.'.format(name)
         return ret
 
+    json_format = __salt__['drbd.json']
+    if json_format:
+        output = OUTPUT_OPTIONS['json']
+    else:
+        output = OUTPUT_OPTIONS['text']
+
     # Check resource is running
     res = _get_res_status(name)
     if res:
-        if res['local role'] == 'Primary':
+        if res[output['role']] == 'Primary':
             ret['result'] = True
             ret['comment'] = 'Resource {} has already been 
promoted.'.format(name)
             return ret
@@ -345,10 +389,16 @@
         ret['comment'] = 'Resource {} not defined in your config.'.format(name)
         return ret
 
+    json_format = __salt__['drbd.json']
+    if json_format:
+        output = OUTPUT_OPTIONS['json']
+    else:
+        output = OUTPUT_OPTIONS['text']
+
     # Check resource is running
     res = _get_res_status(name)
     if res:
-        if res['local role'] == 'Secondary':
+        if res[output['role']] == 'Secondary':
             ret['result'] = True
             ret['comment'] = 'Resource {} has already been 
demoted.'.format(name)
             return ret
@@ -382,6 +432,9 @@
         return ret
 
 
+# May replace by "drbdsetup wait-sync-resource" in drbd9 with modification.
+# Cause it only suspend when resoure is in syncing.
+# Behavior the same when a resource not and finished sync.
 def wait_for_successful_synced(name, interval=30, timeout=600, **kwargs):
     '''
     Query a drbd resource until fully synced for all volumes.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/salt-shaptools-0.2.3/salt-shaptools.changes 
new/salt-shaptools-0.2.5/salt-shaptools.changes
--- old/salt-shaptools-0.2.3/salt-shaptools.changes     2019-11-06 
09:36:32.167389490 +0100
+++ new/salt-shaptools-0.2.5/salt-shaptools.changes     2019-12-09 
03:44:43.029007691 +0100
@@ -1,4 +1,15 @@
 -------------------------------------------------------------------
+Tue Dec  3 06:41:36 UTC 2019 - nick wang <[email protected]>
+
+- Version 0.2.5
+  DRBD: support to get status via json format by default.
+
+-------------------------------------------------------------------
+Thu Nov 21 09:05:07 UTC 2019 - nick wang <[email protected]>
+
+- Version 0.2.4, fix error parsing drbd status when congested.
+
+-------------------------------------------------------------------
 Mon Nov  5 08:48:50 UTC 2019 - nick wang <[email protected]>
 
 - Create package version 0.2.3 with drbd files renamed.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/salt-shaptools-0.2.3/salt-shaptools.spec 
new/salt-shaptools-0.2.5/salt-shaptools.spec
--- old/salt-shaptools-0.2.3/salt-shaptools.spec        2019-11-06 
09:36:32.167389490 +0100
+++ new/salt-shaptools-0.2.5/salt-shaptools.spec        2019-12-09 
03:44:43.029007691 +0100
@@ -19,7 +19,7 @@
 # See also https://en.opensuse.org/openSUSE:Specfile_guidelines
 
 Name:           salt-shaptools
-Version:        0.2.3
+Version:        0.2.5
 Release:        0
 Summary:        Salt modules and states for SAP Applications and SLE-HA 
components management
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/salt-shaptools-0.2.3/tests/unit/modules/test_crmshmod.py 
new/salt-shaptools-0.2.5/tests/unit/modules/test_crmshmod.py
--- old/salt-shaptools-0.2.3/tests/unit/modules/test_crmshmod.py        
2019-11-06 09:36:32.167389490 +0100
+++ new/salt-shaptools-0.2.5/tests/unit/modules/test_crmshmod.py        
2019-12-09 03:44:43.029007691 +0100
@@ -34,9 +34,8 @@
     def setup_loader_modules(self):
         return {crmshmod: {}}
 
-    @mock.patch('logging.Logger.info')
     @mock.patch('salt.utils.path.which')
-    def test_virtual_crm(self, mock_which, logger):
+    def test_virtual_crm(self, mock_which):
         mock_pkg_version = MagicMock(return_value='1.0.0')
         mock_pkg_version_cmp = MagicMock(return_value=1)
 
@@ -46,10 +45,6 @@
                 'pkg.version_cmp': mock_pkg_version_cmp}):
             assert crmshmod.__virtual__() == 'crm'
             mock_which.assert_called_once_with(crmshmod.CRM_COMMAND)
-            logger.assert_has_calls([
-                mock.call('crmsh version: %s', '1.0.0'),
-                mock.call('%s will be used', 'crm')
-            ])
 
     @mock.patch('salt.utils.path.which')
     def test_virtual_crm_error(self, mock_which):
@@ -61,9 +56,8 @@
             ' is not available.')
         mock_which.assert_called_once_with(crmshmod.CRM_COMMAND)
 
-    @mock.patch('logging.Logger.info')
     @mock.patch('salt.utils.path.which')
-    def test_virtual_ha(self, mock_which, logger):
+    def test_virtual_ha(self, mock_which):
         mock_pkg_version = MagicMock(return_value='1.0.0')
         mock_pkg_version_cmp = MagicMock(return_value=-1)
 
@@ -72,18 +66,13 @@
                 'pkg.version': mock_pkg_version,
                 'pkg.version_cmp': mock_pkg_version_cmp}):
             assert crmshmod.__virtual__() == 'crm'
-            logger.assert_has_calls([
-                mock.call('crmsh version: %s', '1.0.0'),
-                mock.call('%s will be used', 'ha-cluster')
-            ])
             mock_which.assert_has_calls([
                 mock.call(crmshmod.CRM_COMMAND),
                 mock.call(crmshmod.HA_INIT_COMMAND)
             ])
 
-    @mock.patch('logging.Logger.info')
     @mock.patch('salt.utils.path.which')
-    def test_virtual_ha_error(self, mock_which, logger):
+    def test_virtual_ha_error(self, mock_which):
         mock_pkg_version = MagicMock(return_value='1.0.0')
         mock_pkg_version_cmp = MagicMock(return_value=-1)
 
@@ -92,10 +81,6 @@
                 'pkg.version': mock_pkg_version,
                 'pkg.version_cmp': mock_pkg_version_cmp}):
             response = crmshmod.__virtual__()
-            logger.assert_has_calls([
-                mock.call('crmsh version: %s', '1.0.0'),
-                mock.call('%s will be used', 'ha-cluster')
-            ])
             mock_which.assert_has_calls([
                 mock.call(crmshmod.CRM_COMMAND),
                 mock.call(crmshmod.HA_INIT_COMMAND)
@@ -414,7 +399,7 @@
         '''
         Test cluster_init with crm option
         '''
-        with patch.dict(crmshmod.__salt__, {'crmsh.version': True}):
+        with patch.dict(crmshmod.__salt__, {'crm.version': True}):
             crm_init.return_value = 0
             value = crmshmod.cluster_init('hacluster', 'dog', 'eth1')
             assert value == 0
@@ -427,7 +412,7 @@
         '''
         Test cluster_init with ha_cluster_init option
         '''
-        with patch.dict(crmshmod.__salt__, {'crmsh.version': False}):
+        with patch.dict(crmshmod.__salt__, {'crm.version': False}):
             ha_cluster_init.return_value = 0
             value = crmshmod.cluster_init('hacluster', 'dog', 'eth1')
             assert value == 0
@@ -521,7 +506,7 @@
         '''
         Test cluster_join with crm option
         '''
-        with patch.dict(crmshmod.__salt__, {'crmsh.version': True}):
+        with patch.dict(crmshmod.__salt__, {'crm.version': True}):
             crm_join.return_value = 0
             value = crmshmod.cluster_join('host', 'dog', 'eth1')
             assert value == 0
@@ -533,7 +518,7 @@
         '''
         Test cluster_join with ha_cluster_join option
         '''
-        with patch.dict(crmshmod.__salt__, {'crmsh.version': False}):
+        with patch.dict(crmshmod.__salt__, {'crm.version': False}):
             ha_cluster_join.return_value = 0
             value = crmshmod.cluster_join('host', 'dog', 'eth1')
             assert value == 0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/salt-shaptools-0.2.3/tests/unit/modules/test_drbdmod.py 
new/salt-shaptools-0.2.5/tests/unit/modules/test_drbdmod.py
--- old/salt-shaptools-0.2.3/tests/unit/modules/test_drbdmod.py 2019-11-06 
09:36:32.167389490 +0100
+++ new/salt-shaptools-0.2.5/tests/unit/modules/test_drbdmod.py 2019-12-09 
03:44:43.029007691 +0100
@@ -29,7 +29,7 @@
     Test cases for salt.modules.drbd
     '''
     def setup_loader_modules(self):
-        return {drbd: {}}
+        return {drbd: {'__salt__': {'drbd.json': True}}}
 
     # 'overview' function tests: 1
     def test_overview(self):
@@ -186,7 +186,7 @@
         with patch.dict(drbd.__salt__, {'cmd.run_all': mock_cmd}):
             assert drbd.status() == ret
 
-        ret = {'Unknown parser': ' single role:Primary'}
+        # SubTest: Test the _unknown_parser
         fake = {}
         fake['stdout'] = '''
  single role:Primary
@@ -197,7 +197,23 @@
         mock_cmd = MagicMock(return_value=fake)
 
         with patch.dict(drbd.__salt__, {'cmd.run_all': mock_cmd}):
-            assert drbd.status() == ret
+            self.assertRaises(exceptions.CommandExecutionError, drbd.status)
+
+        # SubTest: Test the right indent but no expected KEY
+        fake = {}
+        fake['stdout'] = '''
+single role:Primary
+  error-key:UpToDate
+  opensuse-node2 role:Secondary
+    replication:SyncSource peer-disk:Inconsistent done:96.47
+'''
+        fake['stderr'] = ""
+        fake['retcode'] = 0
+
+        mock_cmd = MagicMock(return_value=fake)
+
+        with patch.dict(drbd.__salt__, {'cmd.run_all': mock_cmd}):
+            self.assertRaises(exceptions.CommandExecutionError, drbd.status)
 
     def test_createmd(self):
         '''
@@ -471,16 +487,14 @@
             mock_cmd.assert_called_once_with('drbdsetup status --json all')
 
         # Test 2: Return code is not 0
-        ret = {'name': 'all',
-               'result': False,
-               'comment': 'Error(10) happend when show resource via 
drbdsetup.'}
-
-        fake = {'retcode': 10}
+        fake = {}
+        fake['stderr'] = ""
+        fake['retcode'] = 10
 
         mock_cmd = MagicMock(return_value=fake)
 
         with patch.dict(drbd.__salt__, {'cmd.run_all': mock_cmd}):
-            assert drbd.setup_status() == ret
+            assert drbd.setup_status() is None
             mock_cmd.assert_called_once_with('drbdsetup status --json all')
 
         # Test 3: Raise json ValueError
@@ -519,8 +533,10 @@
         fake['retcode'] = 0
 
         mock_cmd = MagicMock(return_value=fake)
+        mock_drbdsetup = MagicMock(return_value="")
 
-        with patch.dict(drbd.__salt__, {'cmd.run_all': mock_cmd}):
+        with patch.dict(drbd.__salt__, {'cmd.run_all': mock_cmd,
+                                        'drbd.json': False}):
             assert drbd.check_sync_status('beijing')
             mock_cmd.assert_called_with('drbdadm status beijing')
 
@@ -543,7 +559,8 @@
 
         mock_cmd = MagicMock(return_value=fake)
 
-        with patch.dict(drbd.__salt__, {'cmd.run_all': mock_cmd}):
+        with patch.dict(drbd.__salt__, {'cmd.run_all': mock_cmd,
+                                        'drbd.json': False}):
             assert not drbd.check_sync_status('beijing')
             mock_cmd.assert_called_with('drbdadm status beijing')
 
@@ -566,7 +583,8 @@
 
         mock_cmd = MagicMock(return_value=fake)
 
-        with patch.dict(drbd.__salt__, {'cmd.run_all': mock_cmd}):
+        with patch.dict(drbd.__salt__, {'cmd.run_all': mock_cmd,
+                                        'drbd.json': False}):
             assert not drbd.check_sync_status('beijing')
             mock_cmd.assert_called_with('drbdadm status beijing')
 
@@ -589,7 +607,8 @@
 
         mock_cmd = MagicMock(return_value=fake)
 
-        with patch.dict(drbd.__salt__, {'cmd.run_all': mock_cmd}):
+        with patch.dict(drbd.__salt__, {'cmd.run_all': mock_cmd,
+                                        'drbd.json': False}):
             assert drbd.check_sync_status('beijing', peernode='node3')
 
         # Test 4.1: Test status return Error
@@ -600,7 +619,8 @@
 
         mock_cmd = MagicMock(return_value=fake)
 
-        with patch.dict(drbd.__salt__, {'cmd.run_all': mock_cmd}):
+        with patch.dict(drbd.__salt__, {'cmd.run_all': mock_cmd,
+                                        'drbd.json': False}):
             assert not drbd.check_sync_status('beijing')
 
         # Test 4.2: Test status return Error
@@ -626,5 +646,76 @@
         fake1['retcode'] = 1
         mock_cmd = MagicMock(side_effect=[fake, fake1])
 
-        with patch.dict(drbd.__salt__, {'cmd.run_all': mock_cmd}):
+        with patch.dict(drbd.__salt__, {'cmd.run_all': mock_cmd,
+                                        'drbd.json': False}):
             assert not drbd.check_sync_status('beijing')
+
+    def test_check_sync_status_drbdsetup_json(self):
+        '''
+        Test if check_sync_status function work well with drbdsetup status 
--json
+        in drbd9 and drbd-utils >= 9.0.0
+        '''
+
+        # Test 1: Test all UpToDate
+        fake = {}
+        fake['stdout'] = '''
+[
+{
+  "name": "shanghai",
+  "node-id": 1,
+  "role": "Secondary",
+  "suspended": false,
+  "write-ordering": "flush",
+  "devices": [
+    {
+      "volume": 0,
+      "minor": 2,
+      "disk-state": "UpToDate",
+      "client": false,
+      "quorum": true,
+      "size": 699332,
+      "read": 0,
+      "written": 0,
+      "al-writes": 0,
+      "bm-writes": 0,
+      "upper-pending": 0,
+      "lower-pending": 0
+    } ],
+  "connections": [
+    {
+      "peer-node-id": 2,
+      "name": "dummytest-drbd02",
+      "connection-state": "Connected",
+      "congested": false,
+      "peer-role": "Secondary",
+      "ap-in-flight": 0,
+      "rs-in-flight": 0,
+      "peer_devices": [
+        {
+          "volume": 0,
+          "replication-state": "Established",
+          "peer-disk-state": "UpToDate",
+          "peer-client": false,
+          "resync-suspended": "no",
+          "received": 0,
+          "sent": 0,
+          "out-of-sync": 0,
+          "pending": 0,
+          "unacked": 0,
+          "has-sync-details": false,
+          "has-online-verify-details": false,
+          "percent-in-sync": 100.00
+        } ]
+    } ]
+}
+]
+
+'''
+        fake['stderr'] = ""
+        fake['retcode'] = 0
+
+        mock_cmd = MagicMock(return_value=fake)
+
+        with patch.dict(drbd.__salt__, {'cmd.run_all': mock_cmd}):
+            assert drbd.check_sync_status('shanghai')
+            mock_cmd.assert_called_with('drbdsetup status --json shanghai')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/salt-shaptools-0.2.3/tests/unit/states/test_drbdmod.py 
new/salt-shaptools-0.2.5/tests/unit/states/test_drbdmod.py
--- old/salt-shaptools-0.2.3/tests/unit/states/test_drbdmod.py  2019-11-06 
09:36:32.167389490 +0100
+++ new/salt-shaptools-0.2.5/tests/unit/states/test_drbdmod.py  2019-12-09 
03:44:43.029007691 +0100
@@ -31,7 +31,8 @@
     Test cases for salt.states.drbd
     '''
     def setup_loader_modules(self):
-        return {drbd: {'__opts__': {'test': False}}}
+        return {drbd: {'__opts__': {'test': False},
+                       '__salt__': {'drbd.json': True}}}
 
     def test_initialized(self):
         '''
@@ -143,7 +144,8 @@
         mock_status = MagicMock(side_effect=exceptions.CommandExecutionError)
 
         with patch.dict(drbd.__salt__, {'cmd.retcode': mock_cmd,
-                                        'drbd.status': mock_status}):
+                                        'drbd.status': mock_status,
+                                        'drbd.json': False}):
             assert drbd.stopped(RES_NAME) == ret
 
         # Test 2: drbd status return empty []
@@ -158,7 +160,8 @@
         mock_status = MagicMock(return_value=[{'resource name': 
'not_the_same'}])
 
         with patch.dict(drbd.__salt__, {'cmd.retcode': mock_cmd,
-                                        'drbd.status': mock_status}):
+                                        'drbd.status': mock_status,
+                                        'drbd.json': False}):
             assert drbd.stopped(RES_NAME) == ret
 
     def test_get_resource_list(self):
@@ -228,7 +231,8 @@
         mock_status = MagicMock(return_value=res_status)
 
         with patch.dict(drbd.__salt__, {'cmd.retcode': mock_cmd,
-                                        'drbd.status': mock_status}):
+                                        'drbd.status': mock_status,
+                                        'drbd.json': False}):
             assert drbd.started(RES_NAME) == ret
 
         # SubTest 3: The test option
@@ -246,7 +250,8 @@
 
         with patch.dict(drbd.__opts__, {'test': True}):
             with patch.dict(drbd.__salt__, {'cmd.retcode': mock_cmd,
-                                            'drbd.status': mock_status}):
+                                            'drbd.status': mock_status,
+                                            'drbd.json': False}):
                 assert drbd.started(RES_NAME) == ret
 
         # SubTest 4: Error in start
@@ -265,6 +270,7 @@
 
         with patch.dict(drbd.__salt__, {'cmd.retcode': mock_cmd,
                                         'drbd.status': mock_status,
+                                        'drbd.json': False,
                                         'drbd.up': mock_up}):
             assert drbd.started(RES_NAME) == ret
             mock_up.assert_called_once_with(name=RES_NAME)
@@ -285,6 +291,7 @@
 
         with patch.dict(drbd.__salt__, {'cmd.retcode': mock_cmd,
                                         'drbd.status': mock_status,
+                                        'drbd.json': False,
                                         'drbd.up': mock_up}):
             assert drbd.started(RES_NAME) == ret
             mock_up.assert_called_once_with(name=RES_NAME)
@@ -306,6 +313,7 @@
 
         with patch.dict(drbd.__salt__, {'cmd.retcode': mock_cmd,
                                         'drbd.status': mock_status,
+                                        'drbd.json': False,
                                         'drbd.up': mock_up}):
             assert drbd.started(RES_NAME) == ret
             mock_up.assert_called_once_with(name=RES_NAME)
@@ -353,7 +361,8 @@
         mock_status = MagicMock(return_value=res_status)
 
         with patch.dict(drbd.__salt__, {'cmd.retcode': mock_cmd,
-                                        'drbd.status': mock_status}):
+                                        'drbd.status': mock_status,
+                                        'drbd.json': False}):
             assert drbd.stopped(RES_NAME) == ret
 
         # SubTest 3: The test option
@@ -371,7 +380,8 @@
 
         with patch.dict(drbd.__opts__, {'test': True}):
             with patch.dict(drbd.__salt__, {'cmd.retcode': mock_cmd,
-                                            'drbd.status': mock_status}):
+                                            'drbd.status': mock_status,
+                                            'drbd.json': False}):
                 assert drbd.stopped(RES_NAME) == ret
 
         # SubTest 4: Error in stop
@@ -390,6 +400,7 @@
 
         with patch.dict(drbd.__salt__, {'cmd.retcode': mock_cmd,
                                         'drbd.status': mock_status,
+                                        'drbd.json': False,
                                         'drbd.down': mock_down}):
             assert drbd.stopped(RES_NAME) == ret
             mock_down.assert_called_once_with(name=RES_NAME)
@@ -410,6 +421,7 @@
 
         with patch.dict(drbd.__salt__, {'cmd.retcode': mock_cmd,
                                         'drbd.status': mock_status,
+                                        'drbd.json': False,
                                         'drbd.down': mock_down}):
             assert drbd.stopped(RES_NAME) == ret
             mock_down.assert_called_once_with(name=RES_NAME)
@@ -431,6 +443,7 @@
 
         with patch.dict(drbd.__salt__, {'cmd.retcode': mock_cmd,
                                         'drbd.status': mock_status,
+                                        'drbd.json': False,
                                         'drbd.down': mock_down}):
             assert drbd.stopped(RES_NAME) == ret
             mock_down.assert_called_once_with(name=RES_NAME)
@@ -478,7 +491,8 @@
         mock_status = MagicMock(return_value=res_status)
 
         with patch.dict(drbd.__salt__, {'cmd.retcode': mock_cmd,
-                                        'drbd.status': mock_status}):
+                                        'drbd.status': mock_status,
+                                        'drbd.json': False}):
             assert drbd.promoted(RES_NAME) == ret
 
         # SubTest 2.2: Resource is stopped
@@ -506,7 +520,8 @@
         mock_status = MagicMock(return_value=res_status)
 
         with patch.dict(drbd.__salt__, {'cmd.retcode': mock_cmd,
-                                        'drbd.status': mock_status}):
+                                        'drbd.status': mock_status,
+                                        'drbd.json': False}):
             assert drbd.promoted(RES_NAME) == ret
 
         # SubTest 3: The test option
@@ -524,7 +539,8 @@
 
         with patch.dict(drbd.__opts__, {'test': True}):
             with patch.dict(drbd.__salt__, {'cmd.retcode': mock_cmd,
-                                            'drbd.status': mock_status}):
+                                            'drbd.status': mock_status,
+                                            'drbd.json': False}):
                 assert drbd.promoted(RES_NAME) == ret
 
         # SubTest 4: Error in promotion
@@ -543,11 +559,12 @@
 
         with patch.dict(drbd.__salt__, {'cmd.retcode': mock_cmd,
                                         'drbd.status': mock_status,
+                                        'drbd.json': False,
                                         'drbd.primary': mock_primary}):
             assert drbd.promoted(RES_NAME) == ret
             mock_primary.assert_called_once_with(force=False, name=RES_NAME)
 
-        # SubTest 5: Succeed in promotion
+        # SubTest 5.1: Succeed in promotion
         ret = {
             'name': RES_NAME,
             'result': True,
@@ -563,6 +580,28 @@
 
         with patch.dict(drbd.__salt__, {'cmd.retcode': mock_cmd,
                                         'drbd.status': mock_status,
+                                        'drbd.json': False,
+                                        'drbd.primary': mock_primary}):
+            assert drbd.promoted(RES_NAME) == ret
+            mock_primary.assert_called_once_with(force=False, name=RES_NAME)
+
+        # SubTest 5.2: Succeed in promotion with json
+        ret = {
+            'name': RES_NAME,
+            'result': True,
+            'changes': {'name': RES_NAME},
+            'comment': 'Resource {} is promoted.'.format(RES_NAME),
+        }
+
+        res_status = [{'name': RES_NAME, 'role': 'Secondary'}]
+
+        mock_cmd = MagicMock(side_effect=[0, 1])
+        mock_status = MagicMock(return_value=res_status)
+        mock_primary = MagicMock(return_value=0)
+
+        with patch.dict(drbd.__salt__, {'cmd.retcode': mock_cmd,
+                                        'drbd.setup_status': mock_status,
+                                        'drbd.json': True,
                                         'drbd.primary': mock_primary}):
             assert drbd.promoted(RES_NAME) == ret
             mock_primary.assert_called_once_with(force=False, name=RES_NAME)
@@ -584,6 +623,7 @@
 
         with patch.dict(drbd.__salt__, {'cmd.retcode': mock_cmd,
                                         'drbd.status': mock_status,
+                                        'drbd.json': False,
                                         'drbd.primary': mock_primary}):
             assert drbd.promoted(RES_NAME) == ret
             mock_primary.assert_called_once_with(force=False, name=RES_NAME)
@@ -631,7 +671,8 @@
         mock_status = MagicMock(return_value=res_status)
 
         with patch.dict(drbd.__salt__, {'cmd.retcode': mock_cmd,
-                                        'drbd.status': mock_status}):
+                                        'drbd.status': mock_status,
+                                        'drbd.json': False}):
             assert drbd.demoted(RES_NAME) == ret
 
         # SubTest 2.2: Resource is stopped
@@ -659,7 +700,8 @@
         mock_status = MagicMock(return_value=res_status)
 
         with patch.dict(drbd.__salt__, {'cmd.retcode': mock_cmd,
-                                        'drbd.status': mock_status}):
+                                        'drbd.status': mock_status,
+                                        'drbd.json': False}):
             assert drbd.demoted(RES_NAME) == ret
 
         # SubTest 3: The test option
@@ -677,7 +719,8 @@
 
         with patch.dict(drbd.__opts__, {'test': True}):
             with patch.dict(drbd.__salt__, {'cmd.retcode': mock_cmd,
-                                            'drbd.status': mock_status}):
+                                            'drbd.status': mock_status,
+                                            'drbd.json': False}):
                 assert drbd.demoted(RES_NAME) == ret
 
         # SubTest 4: Error in demotion
@@ -696,11 +739,12 @@
 
         with patch.dict(drbd.__salt__, {'cmd.retcode': mock_cmd,
                                         'drbd.status': mock_status,
+                                        'drbd.json': False,
                                         'drbd.secondary': mock_secondary}):
             assert drbd.demoted(RES_NAME) == ret
             mock_secondary.assert_called_once_with(name=RES_NAME)
 
-        # SubTest 5: Succeed in demotion
+        # SubTest 5.1: Succeed in demotion
         ret = {
             'name': RES_NAME,
             'result': True,
@@ -716,6 +760,28 @@
 
         with patch.dict(drbd.__salt__, {'cmd.retcode': mock_cmd,
                                         'drbd.status': mock_status,
+                                        'drbd.json': False,
+                                        'drbd.secondary': mock_secondary}):
+            assert drbd.demoted(RES_NAME) == ret
+            mock_secondary.assert_called_once_with(name=RES_NAME)
+
+        # SubTest 5.2: Succeed in demotion with json
+        ret = {
+            'name': RES_NAME,
+            'result': True,
+            'changes': {'name': RES_NAME},
+            'comment': 'Resource {} is demoted.'.format(RES_NAME),
+        }
+
+        res_status = [{'name': RES_NAME, 'role': 'Primary'}]
+
+        mock_cmd = MagicMock(side_effect=[0, 1])
+        mock_status = MagicMock(return_value=res_status)
+        mock_secondary = MagicMock(return_value=0)
+
+        with patch.dict(drbd.__salt__, {'cmd.retcode': mock_cmd,
+                                        'drbd.setup_status': mock_status,
+                                        'drbd.json': True,
                                         'drbd.secondary': mock_secondary}):
             assert drbd.demoted(RES_NAME) == ret
             mock_secondary.assert_called_once_with(name=RES_NAME)
@@ -737,6 +803,7 @@
 
         with patch.dict(drbd.__salt__, {'cmd.retcode': mock_cmd,
                                         'drbd.status': mock_status,
+                                        'drbd.json': False,
                                         'drbd.secondary': mock_secondary}):
             assert drbd.demoted(RES_NAME) == ret
             mock_secondary.assert_called_once_with(name=RES_NAME)
@@ -786,6 +853,7 @@
 
         with patch.dict(drbd.__salt__, {'cmd.retcode': mock_cmd,
                                         'drbd.status': mock_status,
+                                        'drbd.json': False,
                                         'drbd.check_sync_status': 
mock_sync_status}):
             assert drbd.wait_for_successful_synced(RES_NAME) == ret
 
@@ -814,7 +882,8 @@
         mock_status = MagicMock(return_value=res_status)
 
         with patch.dict(drbd.__salt__, {'cmd.retcode': mock_cmd,
-                                        'drbd.status': mock_status}):
+                                        'drbd.status': mock_status,
+                                        'drbd.json': False}):
             assert drbd.wait_for_successful_synced(RES_NAME) == ret
 
         # SubTest 3: The test option
@@ -835,6 +904,7 @@
         with patch.dict(drbd.__opts__, {'test': True}):
             with patch.dict(drbd.__salt__, {'cmd.retcode': mock_cmd,
                                             'drbd.status': mock_status,
+                                            'drbd.json': False,
                                             'drbd.check_sync_status': 
mock_sync_status}):
                 assert drbd.wait_for_successful_synced(RES_NAME) == ret
                 mock_sync_status.assert_called_once_with(name=RES_NAME)
@@ -872,6 +942,7 @@
 
         with patch.dict(drbd.__salt__, {'cmd.retcode': mock_cmd,
                                         'drbd.status': mock_status,
+                                        'drbd.json': False,
                                         'drbd.check_sync_status': 
mock_sync_status}):
             with patch.object(time, 'time', mock_time_time):
                 with patch.object(time, 'sleep', mock_time_sleep):
@@ -902,11 +973,12 @@
 
         with patch.dict(drbd.__salt__, {'cmd.retcode': mock_cmd,
                                         'drbd.status': mock_status,
+                                        'drbd.json': False,
                                         'drbd.check_sync_status': 
mock_sync_status}):
-            with patch.object(time, 'time', mock_time_time):
-                with patch.object(time, 'sleep', mock_time_sleep):
-                    assert drbd.wait_for_successful_synced(RES_NAME, 
interval=0.3, timeout=1) == ret
-                    mock_sync_status.assert_called_with(name=RES_NAME)
+            with patch.object(time, 'time', mock_time_time), \
+                    patch.object(time, 'sleep', mock_time_sleep):
+                assert drbd.wait_for_successful_synced(RES_NAME, interval=0.3, 
timeout=1) == ret
+                mock_sync_status.assert_called_with(name=RES_NAME)
 
         # SubTest 6: Command error
         ret = {
@@ -933,8 +1005,179 @@
 
         with patch.dict(drbd.__salt__, {'cmd.retcode': mock_cmd,
                                         'drbd.status': mock_status,
+                                        'drbd.json': False,
                                         'drbd.check_sync_status': 
mock_sync_status}):
-            with patch.object(time, 'time', mock_time_time):
-                with patch.object(time, 'sleep', mock_time_sleep):
-                    assert drbd.wait_for_successful_synced(RES_NAME, 
interval=0.3, timeout=1) == ret
-                    mock_sync_status.assert_called_with(name=RES_NAME)
+            with patch.object(time, 'time', mock_time_time), \
+                    patch.object(time, 'sleep', mock_time_sleep):
+                assert drbd.wait_for_successful_synced(RES_NAME, interval=0.3, 
timeout=1) == ret
+                mock_sync_status.assert_called_with(name=RES_NAME)
+
+    def test_get_resource_status_drbdsetup_json(self):
+        '''
+        Test __get_res_drbdsetup_status with json support via started()
+             and wait_for_successful_synced().
+        '''
+
+        # SubTest 1: Resource is already started with json support. started()
+        ret = {
+            'name': RES_NAME,
+            'result': True,
+            'changes': {},
+            'comment': 'Resource {} is already started.'.format(RES_NAME),
+        }
+
+        # A full 'drbdsetup status --json xxx' output:
+        # [
+        # {
+        #   "name": "shanghai",
+        #   "node-id": 1,
+        #   "role": "Primary",
+        #   "suspended": false,
+        #   "write-ordering": "flush",
+        #   "devices": [
+        #     {
+        #       "volume": 0,
+        #       "minor": 2,
+        #       "disk-state": "UpToDate",
+        #       "client": false,
+        #       "quorum": true,
+        #       "size": 699332,
+        #       "read": 21,
+        #       "written": 2504,
+        #       "al-writes": 2,
+        #       "bm-writes": 0,
+        #       "upper-pending": 0,
+        #       "lower-pending": 0
+        #     } ],
+        #   "connections": [
+        #     {
+        #       "peer-node-id": 2,
+        #       "name": "dummytest-drbd02",
+        #       "connection-state": "Connected",
+        #       "congested": false,
+        #       "peer-role": "Secondary",
+        #       "ap-in-flight": 0,
+        #       "rs-in-flight": 0,
+        #       "peer_devices": [
+        #         {
+        #           "volume": 0,
+        #           "replication-state": "Established",
+        #           "peer-disk-state": "UpToDate",
+        #           "peer-client": false,
+        #           "resync-suspended": "no",
+        #           "received": 0,
+        #           "sent": 2504,
+        #           "out-of-sync": 0,
+        #           "pending": 0,
+        #           "unacked": 0,
+        #           "has-sync-details": false,
+        #           "has-online-verify-details": false,
+        #           "percent-in-sync": 100.00
+        #         } ]
+        #     } ]
+        # }
+        # ]
+        #
+        # A full resource example
+        # {'name': 'shanghai', 'node-id': 1, 'role': 'Primary', 'suspended': 
False, 'write-ordering': 'flush',
+        #  'devices': [{'volume': 0, 'minor': 2, 'disk-state': 'UpToDate', 
'client': False, 'quorum': True,
+        #               'size': 699332, 'read': 21, 'written': 2880, 
'al-writes': 2, 'bm-writes': 0,
+        #               'upper-pending': 0, 'lower-pending': 0}],
+        #  'connections': [{'peer-node-id': 2, 'name': 'dummytest-drbd02', 
'connection-state': 'Connected',
+        #                   'congested': False, 'peer-role': 'Secondary', 
'ap-in-flight': 0, 'rs-in-flight': 0,
+        #                   'peer_devices': [{'volume': 0, 
'replication-state': 'Established',
+        #                                     'peer-disk-state': 'UpToDate', 
'peer-client': False,
+        #                                     'resync-suspended': 'no', 
'received': 0, 'sent': 2880,
+        #                                     'out-of-sync': 0, 'pending': 0, 
'unacked': 0,
+        #                                     'has-sync-details': False, 
'has-online-verify-details': False,
+        #                   'percent-in-sync': 100.0}]
+        #                  }]
+        # }
+
+        res_status = [{'name': RES_NAME}]
+
+        mock_cmd = MagicMock(return_value=0)
+        mock_status = MagicMock(return_value=res_status)
+
+        with patch.dict(drbd.__salt__, {'cmd.retcode': mock_cmd,
+                                        'drbd.setup_status': mock_status}):
+            assert drbd.started(RES_NAME) == ret
+
+        # Test 2: drbdsetup status --json raise Exception
+        ret = {
+            'name': RES_NAME,
+            'result': True,
+            'changes': {},
+            'comment': 'Resource {} is already stopped.'.format(RES_NAME),
+        }
+
+        mock_cmd = MagicMock(return_value=0)
+        mock_status = MagicMock(side_effect=exceptions.CommandExecutionError)
+
+        with patch.dict(drbd.__salt__, {'cmd.retcode': mock_cmd,
+                                        'drbd.setup_status': mock_status}):
+            assert drbd.stopped(RES_NAME) == ret
+
+        # Test 3: drbdsetup status --json get empty result
+        ret = {
+            'name': RES_NAME,
+            'result': True,
+            'changes': {},
+            'comment': 'Resource {} is already stopped.'.format(RES_NAME),
+        }
+
+        mock_cmd = MagicMock(return_value=0)
+        mock_status = MagicMock(return_value=None)
+
+        with patch.dict(drbd.__salt__, {'cmd.retcode': mock_cmd,
+                                        'drbd.setup_status': mock_status}):
+            assert drbd.stopped(RES_NAME) == ret
+
+        # Test 4: drbdsetup status --json get result but name is not the same
+        ret = {
+            'name': RES_NAME,
+            'result': True,
+            'changes': {},
+            'comment': 'Resource {} is already stopped.'.format(RES_NAME),
+        }
+
+        result = [{'name': 'not same name'}]
+
+        mock_cmd = MagicMock(return_value=0)
+        mock_status = MagicMock(return_value=result)
+
+        with patch.dict(drbd.__salt__, {'cmd.retcode': mock_cmd,
+                                        'drbd.setup_status': mock_status}):
+            assert drbd.stopped(RES_NAME) == ret
+
+        # SubTest 5: Command error with json support. 
wait_for_successful_synced()
+        ret = {
+            'name': RES_NAME,
+            'result': False,
+            'changes': {},
+            'comment': 'drbd.check_sync_status: (drdbsetup status --json {}) 
error.'.format(
+                       RES_NAME),
+        }
+
+        res_status = [{'name': RES_NAME}]
+
+        mock_cmd = MagicMock(side_effect=[0, 1])
+        mock_status = MagicMock(return_value=res_status)
+        mock_sync_status = MagicMock(side_effect=[0, 0, 0, 
exceptions.CommandExecutionError(
+            'drbd.check_sync_status: (drdbsetup status --json {}) 
error.'.format(RES_NAME))])
+
+        mock_time_sleep = MagicMock()
+        mock_time_time = MagicMock(side_effect=[1557121667.98029,
+                                                1557121667.99029,
+                                                1557121668.29029,
+                                                1557121668.59029,
+                                                1557121668.89029,
+                                                1557121669.19029])
+
+        with patch.dict(drbd.__salt__, {'cmd.retcode': mock_cmd,
+                                        'drbd.setup_status': mock_status,
+                                        'drbd.check_sync_status': 
mock_sync_status}):
+            with patch.object(time, 'time', mock_time_time), \
+                    patch.object(time, 'sleep', mock_time_sleep):
+                assert drbd.wait_for_successful_synced(RES_NAME, interval=0.3, 
timeout=1) == ret
+                mock_sync_status.assert_called_with(name=RES_NAME)


Reply via email to