We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Resolving RPM/DEB IntegTest having config modify issues.
Hi,

There are issues modifying the config yml files in RPM/DEB if you dont use sudo/root to run test.sh.
However, the issue being that certain OS process and integTest cannot run on root, thus catch 22.

This issue would be resolved if we assume the current running user of test.sh has sudo permission, while still able to change settings without using root.

Thanks.

------

Even when you have everything on root seems like integTest class is still asking the gradle run to happen on non-root:
```

»    ↓ errors and warnings from /tmp/tmp9niemi8p/geospatial/build/testclusters/integTest-0/logs/opensearch.stdout.log ↓
» ERROR][o.o.b.OpenSearchUncaughtExceptionHandler] [integTest-0] uncaught exception in thread [main]
»  org.opensearch.bootstrap.StartupException: java.lang.RuntimeException: can not run opensearch as root
»       at org.opensearch.bootstrap.OpenSearch.init(OpenSearch.java:184) ~[opensearch-2.5.0.jar:2.5.0]
»       at org.opensearch.bootstrap.OpenSearch.execute(OpenSearch.java:171) ~[opensearch-2.5.0.jar:2.5.0]
»       at org.opensearch.cli.EnvironmentAwareCommand.execute(EnvironmentAwareCommand.java:104) ~[opensearch-2.5.0.jar:2.5.0]
»       at org.opensearch.cli.Command.mainWithoutErrorHandling(Command.java:138) ~[opensearch-cli-2.5.0.jar:2.5.0]
»       at org.opensearch.cli.Command.main(Command.java:101) ~[opensearch-cli-2.5.0.jar:2.5.0]
»       at org.opensearch.bootstrap.OpenSearch.main(OpenSearch.java:137) ~[opensearch-2.5.0.jar:2.5.0]
»       at org.opensearch.bootstrap.OpenSearch.main(OpenSearch.java:103) ~[opensearch-2.5.0.jar:2.5.0]
»  Caused by: java.lang.RuntimeException: can not run opensearch as root
»       at org.opensearch.bootstrap.Bootstrap.initializeNatives(Bootstrap.java:124) ~[opensearch-2.5.0.jar:2.5.0]
»       at org.opensearch.bootstrap.Bootstrap.setup(Bootstrap.java:191) ~[opensearch-2.5.0.jar:2.5.0]
»       at org.opensearch.bootstrap.Bootstrap.init(Bootstrap.java:404) ~[opensearch-2.5.0.jar:2.5.0]
»       at org.opensearch.bootstrap.OpenSearch.init(OpenSearch.java:180) ~[opensearch-2.5.0.jar:2.5.0]
»       ... 6 more
»   ↓ last 40 non error or warning messages from /tmp/tmp9niemi8p/geospatial/build/testclusters/integTest-0/logs/opensearch.stdout.log ↓
» [2023-01-30T20:10:26.670011235Z] [BUILD] Configuring custom cluster specific distro directory: /tmp/tmp9niemi8p/geospatial/build/testclusters/integTest-0/distro/2.5.0-ARCHIVE
» [2023-01-30T20:10:26.710573952Z] [BUILD] Copying additional config files from distro [/tmp/tmp9niemi8p/geospatial/build/testclusters/integTest-0/distro/2.5.0-ARCHIVE/config/log4j2.properties, /tmp/tmp9niemi8p/geospatial/build/testclusters/integTest-0/distro/2.5.0-ARCHIVE/config/jvm.options.d, /tmp/tmp9niemi8p/geospatial/build/testclusters/integTest-0/distro/2.5.0-ARCHIVE/config/opensearch.yml, /tmp/tmp9niemi8p/geospatial/build/testclusters/integTest-0/distro/2.5.0-ARCHIVE/config/jvm.options]
» [2023-01-30T20:10:26.711812308Z] [BUILD] installing 1 plugins in a single transaction
» [2023-01-30T20:10:28.341404943Z] [BUILD] installed plugins
» [2023-01-30T20:10:28.341674400Z] [BUILD] Creating opensearch keystore with password set to []
» [2023-01-30T20:10:29.386451250Z] [BUILD] Starting OpenSearch process
» [2023-01-30T20:10:31.909907707Z] [BUILD] Stopping node
```

------

Part of #2994.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `src/system/process.py`
Content:
```
1 # Copyright OpenSearch Contributors
2 # SPDX-License-Identifier: Apache-2.0
3 #
4 # The OpenSearch Contributors require contributions made to
5 # this file be licensed under the Apache-2.0 license or a
6 # compatible open source license.
7 import logging
8 import os
9 import subprocess
10 import tempfile
11 from typing import Any
12 
13 import psutil
14 
15 
16 class Process:
17     def __init__(self) -> None:
18         self.process: subprocess.Popen[bytes] = None
19         self.stdout: Any = None
20         self.stderr: Any = None
21         self.__stdout_data__: str = None
22         self.__stderr_data__: str = None
23 
24     def start(self, command: str, cwd: str) -> None:
25         if self.started:
26             raise ProcessStartedError(self.pid)
27 
28         self.stdout = tempfile.NamedTemporaryFile(mode="r+", delete=False)
29         self.stderr = tempfile.NamedTemporaryFile(mode="r+", delete=False)
30 
31         self.process = subprocess.Popen(
32             command,
33             cwd=cwd,
34             shell=True,
35             stdout=self.stdout,
36             stderr=self.stderr,
37         )
38 
39     def terminate(self) -> int:
40         if not self.started:
41             raise ProcessNotStartedError()
42 
43         parent = psutil.Process(self.process.pid)
44         logging.debug("Checking for child processes")
45         child_processes = parent.children(recursive=True)
46         for child in child_processes:
47             logging.debug(f"Found child process with pid {child.pid}")
48             if child.pid != self.process.pid:
49                 logging.debug(f"Sending SIGKILL to {child.pid} ")
50                 child.kill()
51         logging.info(f"Sending SIGKILL to PID {self.process.pid}")
52 
53         self.process.kill()
54 
55         logging.info(f"Process killed with exit code {self.process.returncode}")
56 
57         if self.stdout:
58             self.__stdout_data__ = open(self.stdout.name, 'r').read()
59             self.stdout.close()
60             os.remove(self.stdout.name)
61             self.stdout = None
62 
63         if self.stderr:
64             self.__stderr_data__ = open(self.stderr.name, 'r').read()
65             self.stderr.close()
66             os.remove(self.stderr.name)
67             self.stderr = None
68 
69         self.return_code = self.process.returncode
70         self.process = None
71 
72         return self.return_code
73 
74     @property
75     def started(self) -> bool:
76         return True if self.process else False
77 
78     @property
79     def pid(self) -> int:
80         return self.process.pid if self.started else None
81 
82     @property
83     def stdout_data(self) -> Any:
84         return self.stdout.read() if self.stdout else self.__stdout_data__
85 
86     @property
87     def stderr_data(self) -> Any:
88         return self.stderr.read() if self.stderr else self.__stderr_data__
89 
90 
91 class ProcessStartedError(Exception):
92     """
93     Indicates that process already started.
94     """
95 
96     def __init__(self, pid: int) -> None:
97         self.pid = pid
98         super().__init__(f"Process already started, pid: {pid}")
99 
100 
101 class ProcessNotStartedError(Exception):
102     """
103     Indicates that process has not started.
104     """
105 
106     def __init__(self) -> None:
107         super().__init__("Process has not started")
108
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/src/system/process.py b/src/system/process.py
--- a/src/system/process.py
+++ b/src/system/process.py
@@ -16,18 +16,21 @@
 class Process:
     def __init__(self) -> None:
         self.process: subprocess.Popen[bytes] = None
+        self.require_sudo: bool = False
         self.stdout: Any = None
         self.stderr: Any = None
         self.__stdout_data__: str = None
         self.__stderr_data__: str = None
 
-    def start(self, command: str, cwd: str) -> None:
+    def start(self, command: str, cwd: str, require_sudo: bool = False) -> None:
         if self.started:
             raise ProcessStartedError(self.pid)
 
         self.stdout = tempfile.NamedTemporaryFile(mode="r+", delete=False)
         self.stderr = tempfile.NamedTemporaryFile(mode="r+", delete=False)
 
+        self.require_sudo = require_sudo
+
         self.process = subprocess.Popen(
             command,
             cwd=cwd,
@@ -47,10 +50,10 @@
             logging.debug(f"Found child process with pid {child.pid}")
             if child.pid != self.process.pid:
                 logging.debug(f"Sending SIGKILL to {child.pid} ")
-                child.kill()
+                child.kill() if self.require_sudo is False else subprocess.check_call(f"sudo kill -9 {child.pid}", shell=True)
         logging.info(f"Sending SIGKILL to PID {self.process.pid}")
 
-        self.process.kill()
+        self.process.kill() if self.require_sudo is False else subprocess.check_call(f"sudo kill -9 {self.process.pid}", shell=True)
 
         logging.info(f"Process killed with exit code {self.process.returncode}")

{"golden_diff": "diff --git a/src/system/process.py b/src/system/process.py\n--- a/src/system/process.py\n+++ b/src/system/process.py\n@@ -16,18 +16,21 @@\n class Process:\n     def __init__(self) -> None:\n         self.process: subprocess.Popen[bytes] = None\n+        self.require_sudo: bool = False\n         self.stdout: Any = None\n         self.stderr: Any = None\n         self.__stdout_data__: str = None\n         self.__stderr_data__: str = None\n \n-    def start(self, command: str, cwd: str) -> None:\n+    def start(self, command: str, cwd: str, require_sudo: bool = False) -> None:\n         if self.started:\n             raise ProcessStartedError(self.pid)\n \n         self.stdout = tempfile.NamedTemporaryFile(mode=\"r+\", delete=False)\n         self.stderr = tempfile.NamedTemporaryFile(mode=\"r+\", delete=False)\n \n+        self.require_sudo = require_sudo\n+\n         self.process = subprocess.Popen(\n             command,\n             cwd=cwd,\n@@ -47,10 +50,10 @@\n             logging.debug(f\"Found child process with pid {child.pid}\")\n             if child.pid != self.process.pid:\n                 logging.debug(f\"Sending SIGKILL to {child.pid} \")\n-                child.kill()\n+                child.kill() if self.require_sudo is False else subprocess.check_call(f\"sudo kill -9 {child.pid}\", shell=True)\n         logging.info(f\"Sending SIGKILL to PID {self.process.pid}\")\n \n-        self.process.kill()\n+        self.process.kill() if self.require_sudo is False else subprocess.check_call(f\"sudo kill -9 {self.process.pid}\", shell=True)\n \n         logging.info(f\"Process killed with exit code {self.process.returncode}\")\n", "issue": "Resolving RPM/DEB IntegTest having config modify issues.\nHi,\r\n\r\nThere are issues modifying the config yml files in RPM/DEB if you dont use sudo/root to run test.sh.\r\nHowever, the issue being that certain OS process and integTest cannot run on root, thus catch 22.\r\n\r\nThis issue would be resolved if we assume the current running user of test.sh has sudo permission, while still able to change settings without using root.\r\n\r\nThanks.\r\n\r\n------\r\n\r\nEven when you have everything on root seems like integTest class is still asking the gradle run to happen on non-root:\r\n```\r\n\r\n\u00bb    \u2193 errors and warnings from /tmp/tmp9niemi8p/geospatial/build/testclusters/integTest-0/logs/opensearch.stdout.log \u2193\r\n\u00bb ERROR][o.o.b.OpenSearchUncaughtExceptionHandler] [integTest-0] uncaught exception in thread [main]\r\n\u00bb  org.opensearch.bootstrap.StartupException: java.lang.RuntimeException: can not run opensearch as root\r\n\u00bb       at org.opensearch.bootstrap.OpenSearch.init(OpenSearch.java:184) ~[opensearch-2.5.0.jar:2.5.0]\r\n\u00bb       at org.opensearch.bootstrap.OpenSearch.execute(OpenSearch.java:171) ~[opensearch-2.5.0.jar:2.5.0]\r\n\u00bb       at org.opensearch.cli.EnvironmentAwareCommand.execute(EnvironmentAwareCommand.java:104) ~[opensearch-2.5.0.jar:2.5.0]\r\n\u00bb       at org.opensearch.cli.Command.mainWithoutErrorHandling(Command.java:138) ~[opensearch-cli-2.5.0.jar:2.5.0]\r\n\u00bb       at org.opensearch.cli.Command.main(Command.java:101) ~[opensearch-cli-2.5.0.jar:2.5.0]\r\n\u00bb       at org.opensearch.bootstrap.OpenSearch.main(OpenSearch.java:137) ~[opensearch-2.5.0.jar:2.5.0]\r\n\u00bb       at org.opensearch.bootstrap.OpenSearch.main(OpenSearch.java:103) ~[opensearch-2.5.0.jar:2.5.0]\r\n\u00bb  Caused by: java.lang.RuntimeException: can not run opensearch as root\r\n\u00bb       at org.opensearch.bootstrap.Bootstrap.initializeNatives(Bootstrap.java:124) ~[opensearch-2.5.0.jar:2.5.0]\r\n\u00bb       at org.opensearch.bootstrap.Bootstrap.setup(Bootstrap.java:191) ~[opensearch-2.5.0.jar:2.5.0]\r\n\u00bb       at org.opensearch.bootstrap.Bootstrap.init(Bootstrap.java:404) ~[opensearch-2.5.0.jar:2.5.0]\r\n\u00bb       at org.opensearch.bootstrap.OpenSearch.init(OpenSearch.java:180) ~[opensearch-2.5.0.jar:2.5.0]\r\n\u00bb       ... 6 more\r\n\u00bb   \u2193 last 40 non error or warning messages from /tmp/tmp9niemi8p/geospatial/build/testclusters/integTest-0/logs/opensearch.stdout.log \u2193\r\n\u00bb [2023-01-30T20:10:26.670011235Z] [BUILD] Configuring custom cluster specific distro directory: /tmp/tmp9niemi8p/geospatial/build/testclusters/integTest-0/distro/2.5.0-ARCHIVE\r\n\u00bb [2023-01-30T20:10:26.710573952Z] [BUILD] Copying additional config files from distro [/tmp/tmp9niemi8p/geospatial/build/testclusters/integTest-0/distro/2.5.0-ARCHIVE/config/log4j2.properties, /tmp/tmp9niemi8p/geospatial/build/testclusters/integTest-0/distro/2.5.0-ARCHIVE/config/jvm.options.d, /tmp/tmp9niemi8p/geospatial/build/testclusters/integTest-0/distro/2.5.0-ARCHIVE/config/opensearch.yml, /tmp/tmp9niemi8p/geospatial/build/testclusters/integTest-0/distro/2.5.0-ARCHIVE/config/jvm.options]\r\n\u00bb [2023-01-30T20:10:26.711812308Z] [BUILD] installing 1 plugins in a single transaction\r\n\u00bb [2023-01-30T20:10:28.341404943Z] [BUILD] installed plugins\r\n\u00bb [2023-01-30T20:10:28.341674400Z] [BUILD] Creating opensearch keystore with password set to []\r\n\u00bb [2023-01-30T20:10:29.386451250Z] [BUILD] Starting OpenSearch process\r\n\u00bb [2023-01-30T20:10:31.909907707Z] [BUILD] Stopping node\r\n```\r\n\r\n------\r\n\r\nPart of #2994.\n", "before_files": [{"content": "# Copyright OpenSearch Contributors\n# SPDX-License-Identifier: Apache-2.0\n#\n# The OpenSearch Contributors require contributions made to\n# this file be licensed under the Apache-2.0 license or a\n# compatible open source license.\nimport logging\nimport os\nimport subprocess\nimport tempfile\nfrom typing import Any\n\nimport psutil\n\n\nclass Process:\n    def __init__(self) -> None:\n        self.process: subprocess.Popen[bytes] = None\n        self.stdout: Any = None\n        self.stderr: Any = None\n        self.__stdout_data__: str = None\n        self.__stderr_data__: str = None\n\n    def start(self, command: str, cwd: str) -> None:\n        if self.started:\n            raise ProcessStartedError(self.pid)\n\n        self.stdout = tempfile.NamedTemporaryFile(mode=\"r+\", delete=False)\n        self.stderr = tempfile.NamedTemporaryFile(mode=\"r+\", delete=False)\n\n        self.process = subprocess.Popen(\n            command,\n            cwd=cwd,\n            shell=True,\n            stdout=self.stdout,\n            stderr=self.stderr,\n        )\n\n    def terminate(self) -> int:\n        if not self.started:\n            raise ProcessNotStartedError()\n\n        parent = psutil.Process(self.process.pid)\n        logging.debug(\"Checking for child processes\")\n        child_processes = parent.children(recursive=True)\n        for child in child_processes:\n            logging.debug(f\"Found child process with pid {child.pid}\")\n            if child.pid != self.process.pid:\n                logging.debug(f\"Sending SIGKILL to {child.pid} \")\n                child.kill()\n        logging.info(f\"Sending SIGKILL to PID {self.process.pid}\")\n\n        self.process.kill()\n\n        logging.info(f\"Process killed with exit code {self.process.returncode}\")\n\n        if self.stdout:\n            self.__stdout_data__ = open(self.stdout.name, 'r').read()\n            self.stdout.close()\n            os.remove(self.stdout.name)\n            self.stdout = None\n\n        if self.stderr:\n            self.__stderr_data__ = open(self.stderr.name, 'r').read()\n            self.stderr.close()\n            os.remove(self.stderr.name)\n            self.stderr = None\n\n        self.return_code = self.process.returncode\n        self.process = None\n\n        return self.return_code\n\n    @property\n    def started(self) -> bool:\n        return True if self.process else False\n\n    @property\n    def pid(self) -> int:\n        return self.process.pid if self.started else None\n\n    @property\n    def stdout_data(self) -> Any:\n        return self.stdout.read() if self.stdout else self.__stdout_data__\n\n    @property\n    def stderr_data(self) -> Any:\n        return self.stderr.read() if self.stderr else self.__stderr_data__\n\n\nclass ProcessStartedError(Exception):\n    \"\"\"\n    Indicates that process already started.\n    \"\"\"\n\n    def __init__(self, pid: int) -> None:\n        self.pid = pid\n        super().__init__(f\"Process already started, pid: {pid}\")\n\n\nclass ProcessNotStartedError(Exception):\n    \"\"\"\n    Indicates that process has not started.\n    \"\"\"\n\n    def __init__(self) -> None:\n        super().__init__(\"Process has not started\")\n", "path": "src/system/process.py"}], "after_files": [{"content": "# Copyright OpenSearch Contributors\n# SPDX-License-Identifier: Apache-2.0\n#\n# The OpenSearch Contributors require contributions made to\n# this file be licensed under the Apache-2.0 license or a\n# compatible open source license.\nimport logging\nimport os\nimport subprocess\nimport tempfile\nfrom typing import Any\n\nimport psutil\n\n\nclass Process:\n    def __init__(self) -> None:\n        self.process: subprocess.Popen[bytes] = None\n        self.require_sudo: bool = False\n        self.stdout: Any = None\n        self.stderr: Any = None\n        self.__stdout_data__: str = None\n        self.__stderr_data__: str = None\n\n    def start(self, command: str, cwd: str, require_sudo: bool = False) -> None:\n        if self.started:\n            raise ProcessStartedError(self.pid)\n\n        self.stdout = tempfile.NamedTemporaryFile(mode=\"r+\", delete=False)\n        self.stderr = tempfile.NamedTemporaryFile(mode=\"r+\", delete=False)\n\n        self.require_sudo = require_sudo\n\n        self.process = subprocess.Popen(\n            command,\n            cwd=cwd,\n            shell=True,\n            stdout=self.stdout,\n            stderr=self.stderr,\n        )\n\n    def terminate(self) -> int:\n        if not self.started:\n            raise ProcessNotStartedError()\n\n        parent = psutil.Process(self.process.pid)\n        logging.debug(\"Checking for child processes\")\n        child_processes = parent.children(recursive=True)\n        for child in child_processes:\n            logging.debug(f\"Found child process with pid {child.pid}\")\n            if child.pid != self.process.pid:\n                logging.debug(f\"Sending SIGKILL to {child.pid} \")\n                child.kill() if self.require_sudo is False else subprocess.check_call(f\"sudo kill -9 {child.pid}\", shell=True)\n        logging.info(f\"Sending SIGKILL to PID {self.process.pid}\")\n\n        self.process.kill() if self.require_sudo is False else subprocess.check_call(f\"sudo kill -9 {self.process.pid}\", shell=True)\n\n        logging.info(f\"Process killed with exit code {self.process.returncode}\")\n\n        if self.stdout:\n            self.__stdout_data__ = open(self.stdout.name, 'r').read()\n            self.stdout.close()\n            os.remove(self.stdout.name)\n            self.stdout = None\n\n        if self.stderr:\n            self.__stderr_data__ = open(self.stderr.name, 'r').read()\n            self.stderr.close()\n            os.remove(self.stderr.name)\n            self.stderr = None\n\n        self.return_code = self.process.returncode\n        self.process = None\n\n        return self.return_code\n\n    @property\n    def started(self) -> bool:\n        return True if self.process else False\n\n    @property\n    def pid(self) -> int:\n        return self.process.pid if self.started else None\n\n    @property\n    def stdout_data(self) -> Any:\n        return self.stdout.read() if self.stdout else self.__stdout_data__\n\n    @property\n    def stderr_data(self) -> Any:\n        return self.stderr.read() if self.stderr else self.__stderr_data__\n\n\nclass ProcessStartedError(Exception):\n    \"\"\"\n    Indicates that process already started.\n    \"\"\"\n\n    def __init__(self, pid: int) -> None:\n        self.pid = pid\n        super().__init__(f\"Process already started, pid: {pid}\")\n\n\nclass ProcessNotStartedError(Exception):\n    \"\"\"\n    Indicates that process has not started.\n    \"\"\"\n\n    def __init__(self) -> None:\n        super().__init__(\"Process has not started\")\n", "path": "src/system/process.py"}]}