Hello community,

here is the log from the commit of package crmsh for openSUSE:Factory checked 
in at 2019-11-11 13:01:06
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/crmsh (Old)
 and      /work/SRC/openSUSE:Factory/.crmsh.new.2990 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "crmsh"

Mon Nov 11 13:01:06 2019 rev:166 rq:747268 version:4.1.0+git.1573020742.a0b88227

Changes:
--------
--- /work/SRC/openSUSE:Factory/crmsh/crmsh.changes      2019-11-06 
13:56:49.444203017 +0100
+++ /work/SRC/openSUSE:Factory/.crmsh.new.2990/crmsh.changes    2019-11-11 
13:01:07.965737490 +0100
@@ -1,0 +2,7 @@
+Wed Nov 06 06:17:48 UTC 2019 - [email protected]
+
+- Update to version 4.1.0+git.1573020742.a0b88227:
+  * Test: unittest: test Parallax class
+  * Dev: parallax: create class Parallax to simplify using parallax
+
+-------------------------------------------------------------------

Old:
----
  crmsh-4.1.0+git.1572504697.472361c5.tar.bz2

New:
----
  crmsh-4.1.0+git.1573020742.a0b88227.tar.bz2

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

Other differences:
------------------
++++++ crmsh.spec ++++++
--- /var/tmp/diff_new_pack.IAcYTa/_old  2019-11-11 13:01:09.213738812 +0100
+++ /var/tmp/diff_new_pack.IAcYTa/_new  2019-11-11 13:01:09.229738829 +0100
@@ -36,7 +36,7 @@
 Summary:        High Availability cluster command-line interface
 License:        GPL-2.0-or-later
 Group:          %{pkg_group}
-Version:        4.1.0+git.1572504697.472361c5
+Version:        4.1.0+git.1573020742.a0b88227
 Release:        0
 Url:            http://crmsh.github.io
 Source0:        %{name}-%{version}.tar.bz2

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.IAcYTa/_old  2019-11-11 13:01:09.309738913 +0100
+++ /var/tmp/diff_new_pack.IAcYTa/_new  2019-11-11 13:01:09.309738913 +0100
@@ -1,4 +1,4 @@
 <servicedata>
 <service name="tar_scm">
             <param name="url">git://github.com/ClusterLabs/crmsh.git</param>
-          <param 
name="changesrevision">c8d41bd637dd03b4d60a9f35ca099e41ac32eec4</param></service></servicedata>
\ No newline at end of file
+          <param 
name="changesrevision">b8bb14dbbc9d6a0b1e79d696e64246bec0a98357</param></service></servicedata>
\ No newline at end of file

++++++ crmsh-4.1.0+git.1572504697.472361c5.tar.bz2 -> 
crmsh-4.1.0+git.1573020742.a0b88227.tar.bz2 ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/crmsh-4.1.0+git.1572504697.472361c5/crmsh/parallax.py 
new/crmsh-4.1.0+git.1573020742.a0b88227/crmsh/parallax.py
--- old/crmsh-4.1.0+git.1572504697.472361c5/crmsh/parallax.py   1970-01-01 
01:00:00.000000000 +0100
+++ new/crmsh-4.1.0+git.1573020742.a0b88227/crmsh/parallax.py   2019-11-06 
07:12:22.000000000 +0100
@@ -0,0 +1,104 @@
+# Copyright (C) 2019 Xin Liang <[email protected]>
+# See COPYING for license information.
+
+
+import os
+import parallax
+
+
+class Parallax(object):
+    """
+    # Parallax SSH API
+    # call: Executes the given command on a set of hosts, collecting the output
+    # copy: Copies files from the local machine to a set of remote hosts
+    # slurp: Copies files from a set of remote hosts to local folders
+    """
+    def __init__(self, nodes, cmd=None, localdir=None, filename=None,
+                 src=None, dst=None, askpass=False, ssh_options=None):
+        self.nodes = nodes
+        self.askpass = askpass
+        self.ssh_options = ssh_options
+
+        # used for call
+        self.cmd = cmd
+        # used for slurp
+        self.localdir = localdir
+        self.filename = filename
+        # used for copy
+        self.src = src
+        self.dst = dst
+
+        self.opts = self.prepare()
+
+    def prepare(self):
+        opts = parallax.Options()
+        if self.ssh_options is None:
+            self.ssh_options = ['StrictHostKeyChecking=no', 
'ConnectTimeout=10']
+        opts.ssh_options = self.ssh_options
+        opts.askpass = self.askpass
+        # warn_message will available from parallax-1.0.5
+        if hasattr(opts, 'warn_message'):
+            opts.warn_message = False
+        opts.localdir = self.localdir
+        return opts
+
+    def handle(self, results):
+        for host, result in results:
+            if isinstance(result, parallax.Error):
+                raise ValueError("Failed on {}: {}".format(host, result))
+        return results
+
+    def call(self):
+        results = parallax.call(self.nodes, self.cmd, self.opts)
+        return self.handle(list(results.items()))
+
+    def slurp(self):
+        dst = os.path.basename(self.filename)
+        results = parallax.slurp(self.nodes, self.filename, dst, self.opts)
+        return self.handle(list(results.items()))
+
+    def copy(self):
+        results = parallax.copy(self.nodes, self.src, self.dst, self.opts)
+        return self.handle(list(results.items()))
+
+
+def parallax_call(nodes, cmd, askpass=False, ssh_options=None):
+    """
+    Executes the given command on a set of hosts, collecting the output
+    nodes:       a set of hosts
+    cmd:         command
+    askpass:     Ask for a password if passwordless not configured
+    ssh_options: Extra options to pass to SSH
+    Returns [(host, (rc, stdout, stdin)), ...] or ValueError exception
+    """
+    p = Parallax(nodes, cmd=cmd, askpass=askpass, ssh_options=ssh_options)
+    return p.call()
+
+
+def parallax_slurp(nodes, localdir, filename, askpass=False, ssh_options=None):
+    """
+    Copies from the remote node to the local node
+    nodes:       a set of hosts
+    localdir:    localpath
+    filename:    remote filename want to slurp
+    askpass:     Ask for a password if passwordless not configured
+    ssh_options: Extra options to pass to SSH
+    Returns [(host, (rc, stdout, stdin, localpath)), ...] or ValueError 
exception
+    """
+    p = Parallax(nodes, localdir=localdir, filename=filename,
+                 askpass=askpass, ssh_options=ssh_options)
+    return p.slurp()
+
+
+def parallax_copy(nodes, src, dst, askpass=False, ssh_options=None):
+    """
+    Copies from the local node to a set of remote hosts
+    nodes:       a set of hosts
+    src:         local path
+    dst:         remote path
+    askpass:     Ask for a password if passwordless not configured
+    ssh_options: Extra options to pass to SSH
+    Returns [(host, (rc, stdout, stdin)), ...] or ValueError exception
+    """
+    p = Parallax(nodes, src=src, dst=dst, askpass=askpass, 
ssh_options=ssh_options)
+    return p.copy()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/crmsh-4.1.0+git.1572504697.472361c5/data-manifest 
new/crmsh-4.1.0+git.1573020742.a0b88227/data-manifest
--- old/crmsh-4.1.0+git.1572504697.472361c5/data-manifest       2019-10-31 
07:51:37.000000000 +0100
+++ new/crmsh-4.1.0+git.1573020742.a0b88227/data-manifest       2019-11-06 
07:12:22.000000000 +0100
@@ -155,6 +155,7 @@
 test/unittests/scripts/vipinc/main.yml
 test/unittests/scripts/vip/main.yml
 test/unittests/scripts/workflows/10-webserver.xml
+test/unittests/test_bootstrap.py
 test/unittests/test_bugs.py
 test/unittests/test_cib.py
 test/unittests/test_cliformat.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/crmsh-4.1.0+git.1572504697.472361c5/test/unittests/test_parallax.py 
new/crmsh-4.1.0+git.1573020742.a0b88227/test/unittests/test_parallax.py
--- old/crmsh-4.1.0+git.1572504697.472361c5/test/unittests/test_parallax.py     
1970-01-01 01:00:00.000000000 +0100
+++ new/crmsh-4.1.0+git.1573020742.a0b88227/test/unittests/test_parallax.py     
2019-11-06 07:12:22.000000000 +0100
@@ -0,0 +1,127 @@
+from __future__ import unicode_literals
+# Copyright (C) 2019 Xin Liang <[email protected]>
+# See COPYING for license information.
+#
+# unit tests for parallax.py
+
+
+import os
+import unittest
+from unittest import mock
+import parallax
+from crmsh import parallax as cparallax
+
+
+class TestParallax(unittest.TestCase):
+    @classmethod
+    def setUpClass(cls):
+        """
+        Global setUp.
+        """
+
+    def setUp(self):
+        """
+        Test setUp.
+        """
+        # Use the setup to create a fresh instance for each test
+        self.parallax_call_instance = cparallax.Parallax(["node1"], cmd="ls")
+        self.parallax_slurp_instance = cparallax.Parallax(["node1"], 
localdir="/opt", filename="/opt/file.c")
+        self.parallax_copy_instance = cparallax.Parallax(["node1", "node2"], 
src="/opt/file.c", dst="/tmp")
+
+    def tearDown(self):
+        """
+        Test tearDown.
+        """
+
+    @classmethod
+    def tearDownClass(cls):
+        """
+        Global tearDown.
+        """
+
+    @mock.patch("parallax.call")
+    @mock.patch("crmsh.parallax.Parallax.handle")
+    def test_call(self, mock_handle, mock_call):
+        mock_call.return_value = {"node1": (0, None, None)}
+        mock_handle.return_value = [("node1", (0, None, None))]
+
+        result = self.parallax_call_instance.call()
+        self.assertEqual(result, mock_handle.return_value)
+
+        mock_call.assert_called_once_with(["node1"], "ls", 
self.parallax_call_instance.opts)
+        
mock_handle.assert_called_once_with(list(mock_call.return_value.items()))
+
+    @mock.patch("parallax.Error")
+    @mock.patch("parallax.call")
+    @mock.patch("crmsh.parallax.Parallax.handle")
+    def test_call_exception(self, mock_handle, mock_call, mock_error):
+        mock_error = mock.Mock()
+        mock_call.return_value = {"node1": mock_error}
+        mock_handle.side_effect = ValueError("error happen")
+
+        with self.assertRaises(ValueError) as err:
+            self.parallax_call_instance.call()
+        self.assertEqual("error happen", str(err.exception))
+
+        mock_call.assert_called_once_with(["node1"], "ls", 
self.parallax_call_instance.opts)
+        
mock_handle.assert_called_once_with(list(mock_call.return_value.items()))
+
+    @mock.patch("crmsh.parallax.Parallax.handle")
+    @mock.patch("parallax.slurp")
+    @mock.patch("os.path.basename")
+    def test_slurp(self, mock_basename, mock_slurp, mock_handle):
+        mock_basename.return_value = "file.c"
+        mock_slurp.return_value = {"node1": (0, None, None, "/opt")}
+        mock_handle.return_value = [("node1", (0, None, None, "/opt"))]
+
+        result = self.parallax_slurp_instance.slurp()
+        self.assertEqual(result, mock_handle.return_value)
+
+        mock_basename.assert_called_once_with("/opt/file.c")
+        mock_slurp.assert_called_once_with(["node1"], "/opt/file.c", "file.c", 
self.parallax_slurp_instance.opts)
+        
mock_handle.assert_called_once_with(list(mock_slurp.return_value.items()))
+
+    @mock.patch("parallax.Error")
+    @mock.patch("crmsh.parallax.Parallax.handle")
+    @mock.patch("parallax.slurp")
+    @mock.patch("os.path.basename")
+    def test_slurp_exception(self, mock_basename, mock_slurp, mock_handle, 
mock_error):
+        mock_basename.return_value = "file.c"
+        mock_error = mock.Mock()
+        mock_slurp.return_value = {"node1": mock_error}
+        mock_handle.side_effect = ValueError("error happen")
+
+        with self.assertRaises(ValueError) as err:
+            self.parallax_slurp_instance.slurp()
+        self.assertEqual("error happen", str(err.exception))
+
+        mock_basename.assert_called_once_with("/opt/file.c")
+        mock_slurp.assert_called_once_with(["node1"], "/opt/file.c", "file.c", 
self.parallax_slurp_instance.opts)
+        
mock_handle.assert_called_once_with(list(mock_slurp.return_value.items()))
+
+    @mock.patch("parallax.copy")
+    @mock.patch("crmsh.parallax.Parallax.handle")
+    def test_copy(self, mock_handle, mock_copy):
+        mock_copy.return_value = {"node1": (0, None, None), "node2": (0, None, 
None)}
+        mock_handle.return_value = [("node1", (0, None, None)), ("node2", (0, 
None, None))]
+
+        result = self.parallax_copy_instance.copy()
+        self.assertEqual(result, mock_handle.return_value)
+
+        mock_copy.assert_called_once_with(["node1", "node2"], "/opt/file.c", 
"/tmp", self.parallax_copy_instance.opts)
+        
mock_handle.assert_called_once_with(list(mock_copy.return_value.items()))
+
+    @mock.patch("parallax.Error")
+    @mock.patch("parallax.copy")
+    @mock.patch("crmsh.parallax.Parallax.handle")
+    def test_copy_exception(self, mock_handle, mock_copy, mock_error):
+        mock_error = mock.Mock()
+        mock_copy.return_value = {"node1": mock_error, "node2": (0, None, 
None)}
+        mock_handle.side_effect = ValueError("error happen")
+
+        with self.assertRaises(ValueError) as err:
+            self.parallax_copy_instance.copy()
+        self.assertEqual("error happen", str(err.exception))
+
+        mock_copy.assert_called_once_with(["node1", "node2"], "/opt/file.c", 
"/tmp", self.parallax_copy_instance.opts)
+        
mock_handle.assert_called_once_with(list(mock_copy.return_value.items()))


Reply via email to