From b34b0be559508ebed95397aa5e051dd023c42817 Mon Sep 17 00:00:00 2001
From: Xing Zhang <angeiv.zhang@gmail.com>
Date: Thu, 3 Aug 2023 00:06:44 +0800
Subject: [PATCH] Use processutils to fix TypeError in subprocess

Calling processutils.execute() other than subprocess to
fix bytes-like and str issue in python3.

Closes-bug: #2029392
Change-Id: I16436aa19da2cf53951c9ad27bca14033194651a
(cherry picked from commit e0937b1f097f72238033ccc7182c88ab870bc23f)
---
 requirements.txt                               |  1 +
 zaqar/notification/tasks/mailto.py             |  7 +++----
 zaqar/tests/unit/notification/test_notifier.py | 15 +++++++++------
 3 files changed, 13 insertions(+), 10 deletions(-)

diff --git a/requirements.txt b/requirements.txt
index 5efcdcacf..7b8791560 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -16,6 +16,7 @@ python-swiftclient>=3.10.1 # Apache-2.0
 WebOb>=1.7.1 # MIT
 stevedore>=3.2.2 # Apache-2.0
 oslo.cache>=1.26.0 # Apache-2.0
+oslo.concurrency>=5.0.1 # Apache-2.0
 oslo.config>=8.3.2 # Apache-2.0
 oslo.context>=2.19.2 # Apache-2.0
 oslo.db>=11.0.0 # Apache-2.0
diff --git a/zaqar/notification/tasks/mailto.py b/zaqar/notification/tasks/mailto.py
index 5b9caed7a..11fd27676 100644
--- a/zaqar/notification/tasks/mailto.py
+++ b/zaqar/notification/tasks/mailto.py
@@ -15,9 +15,9 @@
 
 from email.mime import text
 import smtplib
-import subprocess
 from urllib import parse as urllib_parse
 
+from oslo_concurrency import processutils
 from oslo_log import log as logging
 from oslo_serialization import jsonutils
 
@@ -98,9 +98,8 @@ class MailtoTask(object):
                     subject_opt = subscription['options'].get('subject', '')
                     msg["subject"] = params.get('subject', subject_opt)
                 if conf_n.smtp_mode == 'third_part':
-                    p = subprocess.Popen(conf_n.smtp_command.split(' '),
-                                         stdin=subprocess.PIPE)
-                    p.communicate(msg.as_string())
+                    cmd = conf_n.smtp_command.split(' ')
+                    processutils.execute(*cmd, process_input=msg.as_string())
                 elif conf_n.smtp_mode == 'self_local':
                     sender = smtplib.SMTP_SSL(conf_n.smtp_host,
                                               conf_n.smtp_port)
diff --git a/zaqar/tests/unit/notification/test_notifier.py b/zaqar/tests/unit/notification/test_notifier.py
index 9d7f22346..53c740366 100644
--- a/zaqar/tests/unit/notification/test_notifier.py
+++ b/zaqar/tests/unit/notification/test_notifier.py
@@ -19,6 +19,7 @@ import uuid
 import ddt
 
 from oslo_serialization import jsonutils
+from oslo_utils import encodeutils
 
 from zaqar.common import urls
 from zaqar.notification import notifier
@@ -228,11 +229,12 @@ class NotifierTest(testing.TestBase):
                        'from': 'zaqar@example.com', 'subject': 'Hello',
                        'body': jsonutils.dumps(self.notifications[1])}
 
-        def _communicate(msg):
+        def _communicate(msg, timeout=None):
             called.add(msg)
+            return ('', '')
 
         mock_process = mock.Mock()
-        attrs = {'communicate': _communicate}
+        attrs = {'communicate': _communicate, 'returncode': 0}
         mock_process.configure_mock(**attrs)
         mock_popen.return_value = mock_process
         driver.post('fake_queue', self.messages, self.client_id, self.project)
@@ -252,7 +254,7 @@ class NotifierTest(testing.TestBase):
         called_options = []
         called_bodies = []
         for call in called:
-            options, body = call.split('\n\n')
+            options, body = encodeutils.safe_decode(call).split('\n\n')
             called_options.append(options)
             called_bodies.append(jsonutils.dumps(jsonutils.loads(body),
                                  sort_keys=True))
@@ -408,11 +410,12 @@ class NotifierTest(testing.TestBase):
 
         called = set()
 
-        def _communicate(msg):
+        def _communicate(msg, timeout=None):
             called.add(msg)
+            return ('', '')
 
         mock_process = mock.Mock()
-        attrs = {'communicate': _communicate}
+        attrs = {'communicate': _communicate, 'returncode': 0}
         mock_process.configure_mock(**attrs)
         mock_popen.return_value = mock_process
         mock_signed_url.return_value = message
@@ -429,7 +432,7 @@ class NotifierTest(testing.TestBase):
         called_options = []
         called_bodies = []
         for call in called:
-            options, body = call.split('\n\n')
+            options, body = encodeutils.safe_decode(call).split('\n\n')
             called_options.append(options)
             called_bodies.append(body)
         self.assertEqual(expec_options, called_options)