Run external applications using Python and call their methods inside - python

Wish You all beautiful sunny day! :D,
I have a question for You guys. I have following python "script":
import os
os.system('ubuntu.exe')
Which opens Ubuntu running on my WSL. And now, when the Ubuntu terminal appears:
I would like to execute following commands: sudo /etc/init.d/dbus start and sudo /etc/init.d/xrdp start using my python script (just do them automatically). However, when I run one of the commands above, terminal requests my password:
So the script should be also able to enter the password.
Is there any way, how to do it?
Kind regards,
D.

While the question/answers linked in the comments is a good read (sudoers in particular), there's a better method for WSL. Instead of using ubuntu.exe, use the newer wsl.exe replacement. The wsl command offers more control over the startup, including being able to change the user:
import os
os.system('wsl ~ -u root -e sh -c "nohup service xrdp start"')
os.system('wsl -u root service dbus start')
The nohup is needed because of what seems to be a timing issue. When starting up via the WSL command, the shell (owning process) will terminate before xrdp gets a chance to fork. nohup just makes sure that the full xrdp init script gets a chance to run before that happens. This really isn't a WSL issue, per se. It can also be replicated if you were do something similar with exec sh -c "sudo service xrdp start".
A couple of other notes. First, this does not require a password, since WSL doesn't have the concept of "login." The /init process (WSL's PID1 and initialization) is responsible for setting the owning user for each session. This is not considered a security risk since even the root WSL user runs with no greater than the permissions of the Windows user.
Also note that, in my experience, it's not necessary to start dbus for xrdp access, even though I've seen instructions that say it is. Ultimately it will depend on what you want to run within the xrdp session, of course.

Related

How to launch Linux elevated privileges window from Python?

I am writing a python3 app, running with a GUI (not in the terminal) as the user. While this app is running as the user, I need to also execute a command that requires root privileges. I've seen numerous examples of how to do this in the terminal, like this one, which does in fact work great in the terminal:
import subprocess
subprocess.call('sudo echo "Hello world!"', shell=True)
...but my python app is not running in the terminal, and this method doesn't seem to automatically provoke a visible system prompt when my GUI code calls it.
Other apps, notably the Snap Store, somehow launch what appears to be a system popup when they need to do something with root privileges. For example, when I use the Snap Store to install Notepad++ on Ubuntu, I get this popup, which I suspect is a system popup rather than something the Snap Store folks custom-designed.
I'm not super familiar with Linux systems, but I assume this is not a custom popup instead of a system popup because who wants to give their root password to the makers of one of their apps? Instead, users would be giving it to the system (which already knows it), and the 3rd-party app itself doesn't have access to the actual password, but can now run a command as root.
How can I launch an identical popup from my Python app in order to run a command that requires root privileges? Or, alternatively, how else can I run a root command from my python GUI running as the user?
Thanks in advance for any clear assistance you can provide!
Have you tried pkexec?
Not sure about your GUI but running a simple python script (python3.8, pycharm, ubuntu 18.04) results in the popup you desire (can't do the screen print of the pop-up).
import os
os.system("pkexec ls -l")

how to run chmod in python?

I was working with a sensor called Rplidar. To connect the Rplidar with my operating system(Ubuntu) sometimes i have to use this command in the terminal:
sudo chmod 666 /dev/ttyUSB0
After running this instruction, ubuntu can detect the Rplidar. Later on, i will run a python script to work with the Rplidar. Now I want to include this command inside my python script so that i do not need to run it in the terminal before working with the Rplidar. Is there any way that i could do it in python script?
The simple answer is that chmod is provided in the os module in Python:
https://docs.python.org/3/library/os.html#os.chmod
so all you need to do is run:
import os
filename = 'example.dat'
os.chmod(filename,
stat.S_IRUSR |
stat.S_IWUSR |
stat.S_IRGRP |
stat.S_IWGRP |
stat.S_IROTH)
so there's no need to shell out to perform this operation normally. Also have a look at the os.path and shutil modules for much more support in this area.
Things get a little complicated if you need to perform this operation with elevated privileges, but that's actually not the solution here.
Also, it is not a good idea to give 666 permissions to system devices. This can open up security problems when any user on the system has read/write access to system devices. As a matter of principle, use the least permissions required for correct operation.
As #KlausD. comments, you shouldn't be forcing permission changes on these device nodes anyway. The correct approach is to perform a one-time operation of adding the relevant user to the dialout group on your system. Then by being in the correct group, the user running your application will have access to the device. This is already answered here:
https://askubuntu.com/questions/112568/how-do-i-allow-a-non-default-user-to-use-serial-device-ttyusb0
Just run this once:
sudo adduser kazi dialout
then log out and back in for it to take effect. Your Rplidar app will run fine.
You can use the subprocess library to run shell command in Python
import subprocess
subprocess.Popen(["sudo", "chmod", "666", "/dev/ttyUSB0"], stdout=subprocess.PIPE, shell=True)

How to install SageMath kernel in Anaconda?

I'm trying to use Sage in Anaconda 3 but it looks that the libraries are not imported.
I firstly created a new environment 'ipykernel_py2' and then installed Python 2 as explained in here. With this I can have both Python 3 and Python 3 up and running in Anaconda 3.
Then I went to the kernel's folder created (C:\Users\YOUR_USERNAME\AppData\Local\Continuum\anaconda3\envs\ipykernel_py2\share\jupyter\kernels) and pasted Sage's kernel (taken from C:\Program Files\SageMath 8.2\runtime\opt\sagemath-8.2\local\share\jupyter\kernels). This allows to create new SageMath files in Jupyter but the kernel is dead.
To activate the kernel I used Anaconda Prompt and typed:
activate ipykernel_py2
python -m ipykernel install --user --name sagemath --display-name "SageMath 8.2"
So the kernel is now activated and I can create and run Sage files. However the libraries are still not working. It seems that the file is running like a normal Python 2 file.
Does anyone know how to fix this? Do I need to create a seperate environment?
Sage for Windows runs under a UNIX emulation environment called Cygwin. Looking at the sagemath/kernel.json it contains:
{"display_name": "SageMath 8.2", "argv": ["/opt/sagemath-8.2/local/bin/sage", "--python", "-m", "sage.repl.ipython_kernel", "-f", "{connection_file}"]}
You can see here that it has a UNIX-style path to the sage executable. This path only makes sense to other programs running under Sage's Cygwin environment, and is meaningless to native Windows programs. Simply converting it to the equivalent Windows path won't work either, because bin/sage is actually a shell script. At the very least you need to provide a Windows path to the bash that comes with Cygwin and pass it the UNIX path to the sage executable (the same as the one above). Without a login shell, most environment variables needed won't be set either, so you probably need bash -l.
So, something like:
{"display_name": "SageMath 8.2", "argv": ["C:\\Program Files\\SageMath 8.2\\runtime\\bin\\bash.exe", "-l", "/opt/sagemath-8.2/local/bin/sage", "--python", "-m", "sage.repl.ipython_kernel", "-f", "{connection_file}"]}
might work. The one thing I'm not sure about is whether the {connection_file} argument will be handled properly either. I haven't tested it.
Update: Indeed, the above partially works, but there are a few problems: The {connection_file} argument as passed as the absolute Windows path to the file. While Cygwin can normally translate transparently from Windows paths to a corresponding UNIX path, there is a known issue that Python's os.path module on Cygwin does not handle Windows-style paths well, and this leads to issues.
The other major problem I encountered was that IPKernelApp, the class that drives generic Jupyter kernels, has a thread which polls to see if the kernel's parent process (in this case the notebook server) has exited, so it can appropriately shut down if the parent shuts down. This is how kernels know to automatically shut down when you kill the notebook server.
How this is done is very different depending on the platform--Windows versus UNIX-like. Because Sage's kernel runs in Cygwin, it chooses the UNIX-like poller. However, this is wrong if the notebook server happens to be a native Windows process, as is the case when running the Sage kernel in a Windows-native Jupyter. Remarkably, the parent poller for Windows can work just as well on Cygwin since it accesses the Windows API through ctypes. Therefore, this can be worked around by providing a wrapper to IPKernelApp that forces uses of ParentPollerWindows.
A possible solution then looks something like this: From within the SageMath Shell do:
$ cd "$SAGE_LOCAL"
$ mkdir -p ./share/jupyter/kernels/sagemath
$ cd ./share/jupyter/kernels/sagemath
$ cat <<_EOF_ > kernel-wrapper.sh
#!/bin/sh
here="$(dirname "$0")"
connection_file="$(cygpath -u -a "$1")"
exec /opt/sagemath-8.2/local/bin/sage --python "${here}/kernel-wrapper.py" -f "${connection_file}"
_EOF_
$ cat <<_EOF_ > kernel-wrapper.py
from ipykernel.kernelapp import IPKernelApp as OrigIPKernelApp
from ipykernel.parentpoller import ParentPollerWindows
from sage.repl.ipython_kernel.kernel import SageKernel
class IPKernelApp(OrigIPKernelApp):
"""
Although this kernel runs under Cygwin, its parent is a native Windows
process, so we force use of the ParentPollerWindows.
"""
def init_poller(self):
if self.interrupt or self.parent_handle:
self.poller = ParentPollerWindows(self.interrupt,
self.parent_handle)
IPKernelApp.launch_instance(kernel_class=SageKernel)
_EOF_
Now edit the kernel.json (in its existing location under share\jupyter\kernels\sagemath) to read:
{"display_name": "SageMath 8.2", "argv": ["C:\\Program Files\\SageMath 8.2\\runtime\\bin\\bash.exe", "-l", "/opt/sagemath-8.2/local/share/jupyter/kernels/sagemath/kernel-wrapper.sh", "{connection_file}"]}
This runs kernel-wrapper.sh which in turn runs kernel-wrapper.py. (There are a few simplifications I could make to get rid of the need for kernel-wrapper.sh completely, but that would be easier in SageMath 8.3 which includes PyCygwin.)
Make sure to change every "8.2" to the appropriate "X.Y" version for your Sage installation.
Update: Made some updates thanks to feedback from a user, but I haven't tested these changes yet, so please make sure instead of blindly copy/pasting that every file/directory path in my instructions exists and looks correct.
As you can see, this was not trivial, and was never by design meant to be possible. But it can be done. Once the kernel itself is up and running it's just a matter of talking to it over TCP/IP sockets so there's not too much magic involved after that. I believe there are some small improvements that could be made on both the Jupyter side and on the Sage side that would facilitate this sort of thing in the future...

Cron job can't run bash script (that shells python script requiring xsession) that runs perfectly well from console

I am using dryscrape in a python script. The python script is called in a bash script, which is run by cron. For those who may not be aware, dryscrape is a headless browser (use QtWebkit in the background - so requires an xsession).
Here are the main points concerning the issue I'm having
When I run the python script from the command line, it works
When I run the bash script from the command line, it works too
I figured out that this may have something to do with different environments between my command prompt and when the cron job is running, so I modified my bash script to source my .profile as follows:
#/bin/bash
. /full/path/to/my/home/directory/.profile
python script_to_run.py
This is what my cronjob crontab entry looks like:
0,55 14-22 * * 1-5 /path/to/script.sh >> $(date "+/path/to/logs/\%Y\%m\%d.mydownload.log" )
By the way, I know that the job is being run (I can see entries in /var/log/syslog, and the script also writes to a log file - which is where I get the error message below):
In all cases, I got the following error message:
Could not connect to X server. Try calling dryscrape.start_xvfb()
before creating a session
I have installed the prerequisites, on my machine (obviously - since it runs at the command line). At the moment, I have run out of ideas.
What is causing the script to run fine at the console, and then fail when run by cron?
[[Relevant Details]]
OS: Linux 16.0.4 LTS
bash: version 4.3.46(1)
cron user: myself (i.e. same user at the command prompt)
dryscrape: version 1.0.1
The solution to this was to call the dryscrape.start_xvfb() method before starting the dryscrape session.
Cron user does not have display, so you cannot run any command which requires a display.
You need to modify the python script to do not use any type of display (check carefully, because some python commands, even though they do not open any display , they internally check for this variable).
The best way to test is to ssh into the machine without Display, and check if you can run it from there without erros.

Is there Windows analog to supervisord?

I need to run python script and be sure that it will restart after it terminates. I know that there is UNIX solution called supervisord. But unfortunately server where my script has to be run is on Windows. Do you know what tool can be useful?
Thanks
Despite the big fat disclaimer here, you can run Supervisor with Cygwin in Windows; it turns out that Cygwin goes a long way to simulate a Posix environment, so well that in fact supervisord runs unchanged. There is no need to learn a new tool, and you will even save quite a bit of work if you need to deploy a complicated project across multiple platforms.
Here's my recipe:
If you have not done it yet, install Cygwin. During the installation process, select Python.
From the Cygwin terminal, install virtualenv as usual.
Create a virtualenv for supervisord, and then install as usual:
pip install supervisord
Configure supervisord in the usual way. Keep in mind that supervisord will be running with Cygwin, so you better use paths the Cygwin way (C:\myservers\project1 translates to /cygdrive/c/myservers/project1 in Cygwin).
Now you probably want to install supervisord as a service. Here's how I do it:
cygrunsrv --install supervisord --path /home/Administrator/supervisor/venv/bin/python --args "/home/Administrator/supervisor/venv/bin/supervisord -n -c /home/Administrator/supervisor/supervisord.conf"
Go to the Windows service manager and start the service supervisord that you just installed.
Point 5 installs supervisord as a Windows service, so that you can control it (start/stop/restart) from the Windows service manager. But the things that you can do with supervisorctl work as usual, meaning that you can simply deploy your old configuration file.
You likely want to run your script as a Windows Service. To do so you'll need the python-win32 library. This question has a good description of how you go about doing this, as well as a bunch of links to other related resources. This question may also be of use.
A Windows Service is how you want to wrap up any script that needs to run continuously on Windows. They can be configured to automatically start on boot, and handle failures. Nothing is going to stop anyone from killing the process itself, but to handle that potential situation, you can just create a bat file and use the sc command to poll the service to see if it is running and if not restart the service. Just schedule the bat file to run every 60 seconds (or whatever is reasonable for your script to potentially be down).
If you want a supervisord-like process manager that runs on most posix OS and is Python-based like supervisord, then you should look at honcho which is a Python port of foreman (Ruby-based):
http://pypi.python.org/pypi/honcho/
It works great on mac, linux but (actually) not yet windows... (editing my initial answer where I had said optimistically it was already working on Windows based on a pull request that has been discarded since)
There is a fork that provides Windows support here https://github.com/redpie/honcho
and some work in progress to support Windows here https://github.com/nickstenning/honcho/issues/28 ... at least it could become a possible solution in a near future.
There is also a foreman fork to support Windows here: https://github.com/ddollar/foreman-windows that may be working for you, though I never tried it.
So for now, a Windows service might be your best short term option.
supervisor for windows worked for us on python27 - 32 bit. I had to install pypiwin32 and pywin32==223.
As it is an old question with old answers I will update it with latest news:
There is a supervisor-win project that claims to support supervisor on Windows.
No, supervisord is not supported under Windows.
BUT what you can do is, to restart it automatically from a wrapper script:
#!/usr/bin/python
from subprocess import Popen
file_path = " script_to_be_restarted.py"
args_as_str = " --arg1=woop --arg2=woop"
while True:
print("(Re-)Start script %s %s" % (file_path, args_as_str))
p = Popen("python " + file_path + args_as_str, shell=True)
p.wait()

Categories