Python Inotify for a list of folders - python

I am looking for a way to check a list of document roots of 5 domains to inotify directory watch.
For a single folder it is working like this
DIRECTORY_TO_WATCH = "/home/serveradmin/"
I have a list of folders which needs to be checked recursively for my server.
I just started learning python and have some hands on experience in C language. Just starting learning developments.
Is there anyone who can help me on this? I need to have a recursive inotify watch on 5 folders mentioned in a file named /tmp/folderlist.txt
IS there any similar code available anywhere I can refer?

install inotify-tools:
sudo apt-get install inotify-tools
and try something like:
inotifywait = ['inotifywait',
'--recursive',
'--quiet',
'--monitor', ## '--timeout', '1',
'--event',
'CREATE',
'--format', '%f']
from subprocess import PIPE, Popen
p = Popen(inotifywait + paths, stdout=PIPE)
for line in iter(p.stdout.readline, ''):
print(line)
For macosx you can get similar results using fswatch:
if sys.platform == 'darwin':
inotifywait = ['fswatch', '--event', 'Created']
For windows see : Is there anything like inotify on Windows?

So you want to create a list of the folders then do a for a statement to check if they exist.
So do
import os
list = ['folder1', 'folder2', 'folder3', 'folder4', 'folder5']
for i in list:
print("\nDoes", list[i], "exsist?", os.path.exists("/home/serveradmin/" + list[i]))
Replace the items in list with the correct folder names!
Good luck!

This is the sample code I have started working. I need to replace "DIRECTORY_TO_WATCH" to a list of folders which I will add in a file. So basically it will be a list of folders specified in a txt file so that I can just keep adding future folders in that file and no need to add the core code every time.
import time
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
class Watcher:
DIRECTORY_TO_WATCH = "/path/to/my/directory"
def __init__(self):
self.observer = Observer()
def run(self):
event_handler = Handler()
self.observer.schedule(event_handler, self.DIRECTORY_TO_WATCH, recursive=True)
self.observer.start()
try:
while True:
time.sleep(5)
except:
self.observer.stop()
print "Error"

Related

Get local DNS settings in Python

Is there any elegant and cross platform (Python) way to get the local DNS settings?
It could probably work with a complex combination of modules such as platform and subprocess, but maybe there is already a good module, such as netifaces which can retrieve it in low-level and save some "reinventing the wheel" effort.
Less ideally, one could probably query something like dig, but I find it "noisy", because it would run an extra request instead of just retrieving something which exists already locally.
Any ideas?
Using subprocess you could do something like this, in a MacBook or Linux system
import subprocess
process = subprocess.Popen(['cat', '/etc/resolv.conf'],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdout, stderr = process.communicate()
print(stdout, stderr)
or do something like this
import subprocess
with open('dns.txt', 'w') as f:
process = subprocess.Popen(['cat', '/etc/resolv.conf'], stdout=f)
The first output will go to stdout and the second to a file
Maybe this one will solve your problem
import subprocess
def get_local_dns(cmd_):
with open('dns1.txt', 'w+') as f:
with open('dns_log1.txt', 'w+') as flog:
try:
process = subprocess.Popen(cmd_, stdout=f, stderr=flog)
except FileNotFoundError as e:
flog.write(f"Error while executing this command {str(e)}")
linux_cmd = ['cat', '/etc/resolv.conf']
windows_cmd = ['windows_command', 'parameters']
commands = [linux_cmd, windows_cmd]
if __name__ == "__main__":
for cmd in commands:
get_local_dns(cmd)
Thanks #MasterOfTheHouse.
I ended up writing my own function. It's not so elegant, but it does the job for now. There's plenty of room for improvement, but well...
import os
import subprocess
def get_dns_settings()->dict:
# Initialize the output variables
dns_ns, dns_search = [], ''
# For Unix based OSs
if os.path.isfile('/etc/resolv.conf'):
for line in open('/etc/resolv.conf','r'):
if line.strip().startswith('nameserver'):
nameserver = line.split()[1].strip()
dns_ns.append(nameserver)
elif line.strip().startswith('search'):
search = line.split()[1].strip()
dns_search = search
# If it is not a Unix based OS, try "the Windows way"
elif os.name == 'nt':
cmd = 'ipconfig /all'
raw_ipconfig = subprocess.check_output(cmd)
# Convert the bytes into a string
ipconfig_str = raw_ipconfig.decode('cp850')
# Convert the string into a list of lines
ipconfig_lines = ipconfig_str.split('\n')
for n in range(len(ipconfig_lines)):
line = ipconfig_lines[n]
# Parse nameserver in current line and next ones
if line.strip().startswith('DNS-Server'):
nameserver = ':'.join(line.split(':')[1:]).strip()
dns_ns.append(nameserver)
next_line = ipconfig_lines[n+1]
# If there's too much blank at the beginning, assume we have
# another nameserver on the next line
if len(next_line) - len(next_line.strip()) > 10:
dns_ns.append(next_line.strip())
next_next_line = ipconfig_lines[n+2]
if len(next_next_line) - len(next_next_line.strip()) > 10:
dns_ns.append(next_next_line.strip())
elif line.strip().startswith('DNS-Suffix'):
dns_search = line.split(':')[1].strip()
return {'nameservers': dns_ns, 'search': dns_search}
print(get_dns_settings())
By the way... how did you manage to write two answers with the same account?

Using python how to display dns

Using Python, is there a way using psutil or something else to return the output of "ipconfig /displaydns" or something similar?
Spawning a cmd process and running the command is not an option.
To execute a command, you can use the os library. Executing the command you've shown above is as simple as:
import os
os.system('ipconfig /displaydns')
If you want to store the output of a command in a variable, you can use:
x = os.popen('ipconfig /displaydns')
You can try using dnspython's resolver class, which has a nameservers list attached to it.
import dns.resolver
resolver = dns.resolver.Resolver()
resolver.nameservers
# Returns ['8.8.8.8', '8.8.4.4', '8.8.8.8'] on my pc
This python script I made creates a directory in widows user profile and copies windows dns information into a log.txt,So if directory does not exist it will create it. Hope it works for you.
#!/usr/bin/env python3
import time
import os
def dns():
path = os.system("ipconfig /displaydns >> %USERPROFILE%\DNS\logdns.txt")
if path == False:
os.system("ipconfig /displaydns >> %USERPROFILE%\DNS\logdns.txt")
print("Please wait copying information........")
time.sleep(5 )
os.system("cls")
print("Information copy complete.")
time.sleep(3)
else:
print("Making directory please wait a second....")
time.sleep(5)
os.system("cls")
os.system("mkdir %USERPROFILE%\DNS")
time.sleep(1)
dns()
dns()

Python subprocess in .exe

I'm creating a python script that will copy files and folder over the network. it's cross-platform so I make an .exe file using cx_freeze
I used Popen method of the subprocess module
if I run .py file it is running as expected but when i create .exe subprocess is not created in the system
I've gone through all documentation of subprocess module but I didn't find any solution
everything else (I am using Tkinter that also works fine) is working in the .exe accept subprocess.
any idea how can I call subprocess in .exe.file ??
This file is calling another .py file
def start_scheduler_action(self, scheduler_id, scheduler_name, list_index):
scheduler_detail=db.get_scheduler_detail_using_id(scheduler_id)
for detail in scheduler_detail:
source_path=detail[2]
if not os.path.exists(source_path):
showerror("Invalid Path","Please select valid path", parent=self.new_frame)
return
self.forms.new_scheduler.start_scheduler_button.destroy()
#Create stop scheduler button
if getattr(self.forms.new_scheduler, "stop_scheduler_button", None)==None:
self.forms.new_scheduler.stop_scheduler_button = tk.Button(self.new_frame, text='Stop scheduler', width=10, command=lambda:self.stop_scheduler_action(scheduler_id, scheduler_name, list_index))
self.forms.new_scheduler.stop_scheduler_button.grid(row=11, column=1, sticky=E, pady=10, padx=1)
scheduler_id=str(scheduler_id)
# Get python paths
if sys.platform == "win32":
proc = subprocess.Popen(['where', "python"], env=None, stdout=subprocess.PIPE)
else:
proc = subprocess.Popen(['which', "python"], env=None,stdout=subprocess.PIPE)
out, err = proc.communicate()
if err or not out:
showerror("", "Python not found", parent=self.new_frame)
else:
try:
paths = out.split(os.pathsep)
# Create python path
python_path = (paths[len(paths) - 1]).split('\n')[0]
cmd = os.path.realpath('scheduler.py')
#cmd='scheduler.py'
if sys.platform == "win32":
python_path=python_path.splitlines()
else:
python_path=python_path
# Run the scheduler file using scheduler id
proc = subprocess.Popen([python_path, cmd, scheduler_id], env=None, stdout=subprocess.PIPE)
message="Started the scheduler : %s" %(scheduler_name)
showinfo("", message, parent=self.new_frame)
#Add process id to scheduler table
process_id=proc.pid
#showinfo("pid", process_id, parent=self.new_frame)
def get_process_id(name):
child = subprocess.Popen(['pgrep', '-f', name], stdout=subprocess.PIPE, shell=False)
response = child.communicate()[0]
return [int(pid) for pid in response.split()]
print(get_process_id(scheduler_name))
# Add the process id in database
self.db.add_process_id(scheduler_id, process_id)
# Add the is_running status in database
self.db.add_status(scheduler_id)
except Exception as e:
showerror("", e)
And this file is called:
def scheduler_copy():
date= strftime("%m-%d-%Y %H %M %S", localtime())
logFile = scheduler_name + "_"+scheduler_id+"_"+ date+".log"
#file_obj=open(logFile, 'w')
# Call __init__ method of xcopy file
xcopy=XCopy(connection_ip, username , password, client_name, server_name, domain_name)
check=xcopy.connect()
# Cretae a log file for scheduler
file_obj=open(logFile, 'w')
if check is False:
file_obj.write("Problem in connection..Please check connection..!!")
return
scheduler_next_run=schedule.next_run()
scheduler_next_run="Next run at: " +str(scheduler_next_run)
# If checkbox_value selected copy all the file to new directory
if checkbox_value==1:
new_destination_path=xcopy.create_backup_directory(share_folder, destination_path, date)
else:
new_destination_path=destination_path
# Call backup method for coping data from source to destination
try:
xcopy.backup(share_folder, source_path, new_destination_path, file_obj, exclude)
file_obj.write("Scheduler completed successfully..\n")
except Exception as e:
# Write the error message of the scheduler to log file
file_obj.write("Scheduler failed to copy all data..\nProblem in connection..Please check connection..!!\n")
# #file_obj.write("Error while scheduling")
# return
# Write the details of scheduler to log file
file_obj.write("Total skipped unmodified file:")
file_obj.write(str(xcopy.skipped_unmodified_count))
file_obj.write("\n")
file_obj.write("Total skipped file:")
file_obj.write(str(xcopy.skipped_file))
file_obj.write("\n")
file_obj.write("Total copied file:")
file_obj.write(str(xcopy.copy_count))
file_obj.write("\n")
file_obj.write("Total skipped folder:")
file_obj.write(str(xcopy.skipped_folder))
file_obj.write("\n")
# file_obj.write(scheduler_next_run)
file_obj.close()
There is some awkwardness in your source code, but I won't spend time on that. For instance, if you want to find the source_path, it's better to use a for loop with break/else:
for detail in scheduler_detail:
source_path = detail[2]
break # found
else:
# not found: raise an exception
...
Some advice:
Try to separate the user interface code and the sub-processing, avoid mixing the two.
Use exceptions and exception handlers.
If you want portable code: avoid system call (there are no pgrep on Windows).
Since your application is packaged in a virtualenv (I make the assumption cx_freeze does this kind of thing), you have no access to the system-wide Python. You even don't have that on Windows. So you need to use the packaged Python (this is a best practice anyway).
If you want to call a Python script like a subprocess, that means you have two packaged applications: you need to create an exe for the main application and for the scheduler.py script. But, that's not easy to communicate with it.
Another solution is to use multiprocessing to spawn a new Python process. Since you don't want to wait for the end of processing (which may be long), you need to create daemon processes. The way to do that is explained in the multiprocessing module.
Basically:
import time
from multiprocessing import Process
def f(name):
print('hello', name)
if __name__ == '__main__':
p = Process(target=f, args=('bob',))
p.daemon = True
p.start()
# let it live and die, don't call: `p.join()`
time.sleep(1)
Of course, we need to adapt that with your problem.
Here is how I would do that (I removed UI-related code for clarity):
import scheduler
class SchedulerError(Exception):
pass
class YourClass(object):
def start_scheduler_action(self, scheduler_id, scheduler_name, list_index):
scheduler_detail = db.get_scheduler_detail_using_id(scheduler_id)
for detail in scheduler_detail:
source_path = detail[2]
break
else:
raise SchedulerError("Invalid Path", "Missing source path", parent=self.new_frame)
if not os.path.exists(source_path):
raise SchedulerError("Invalid Path", "Please select valid path", parent=self.new_frame)
p = Process(target=scheduler.scheduler_copy, args=('source_path',))
p.daemon = True
p.start()
self.db.add_process_id(scheduler_id, p.pid)
To check if your process is still running, I recommend you to use psutil. It's really a great tool!
You can define your scheduler.py script like that:
def scheduler_copy(source_path):
...
Multiprocessing vs Threading Python
Quoting this answer: https://stackoverflow.com/a/3044626/1513933
The threading module uses threads, the multiprocessing module uses processes. The difference is that threads run in the same memory space, while processes have separate memory. This makes it a bit harder to share objects between processes with multiprocessing. Since threads use the same memory, precautions have to be taken or two threads will write to the same memory at the same time. This is what the global interpreter lock is for.
Here, the advantage of multiprocessing over multithreading is that you can kill (or terminate) a process; you can't kill a thread. You may need psutil for that.
This is not an exact solution you are looking for, but following suggestion should be preferred for two reasons.
These are more pythonic way
subprocess is slightly expensive
Suggestions you can consider
Don't use subprocess for fetching system path. Try check os.getenv('PATH') to get env variable & try to find if python is in the path. For windows, one has to manually add Python path or else you can directly check in Program Files I guess
For checking process ID's you can try psutils. A wonderful answer is provided here at how do I get the process list in Python?
Calling another script from a python script. This does not look cool. Not bad, but I would not prefer this at all.
In above code, line - if sys.platform == "win32": has same value in if and else condition ==> you dont need a conditional statement here.
You wrote pretty fine working code to tell you. Keep Coding!
If you want to run a subprocess in an exe file, then you can use
import subprocess
program=('example')
arguments=('/command')
subprocess.call([program, arguments])

copy file, keep permissions and owner

The docs of shutil tells me:
Even the higher-level file copying functions (shutil.copy(), shutil.copy2()) can’t copy all file metadata. On POSIX platforms, this means that file owner and group are lost as well as ACLs
How can I keep the file owner and group if I need to copy a file in python?
The process runs on linux as root.
Update: We don't use ACLs. We only need to keep the stuff which is preserved with tools like tar and rsync.
You perhaps could use os.stat to get the guid and uid like in this answer and then reset the uid and guid after coping using os.chown.
I did it this way:
import os
import stat
import shutil
def copyComplete(source, target):
# copy content, stat-info (mode too), timestamps...
shutil.copy2(source, target)
# copy owner and group
st = os.stat(source)
os.chown(target, st.st_uid, st.st_gid)
You can use the subprocess module:
from subprocess import Popen
p = Popen(['cp','-p','--preserve',src,dest])
p.wait()
See Keeping fileowner and permissions after copying file in C on how cp itself does this, then just replicate its logic. Python has all the system calls mentioned in its os module.
I suggest you use the OS and subprocess modules. This will only work in Unix, but it should work well. Use the os.fchown to change file ownership, and subprocess.Popen() to pipe ls -l into a variable to read ownership. For one file, the permissions reader would look like this:
import os
import subprocess
def readfile(filepath):
process = subprocess.Popen(["ls","-l"],stdout=subprocess.PIPE)
output = process.communicate()[0]
output = output.split()
return (output[0],output[1]) #insert into this tuple the indexing for the words you want from ls -l
and for the uid setter (just a wrapper for os function):
def setuid(filepath,uid,gid):
os.chown(filepath,uid,gid)
as #Thom Wiggers 's answer
os.stat get uid,gid
os.chmod set uid,gid
demo code:
import os
st = os.stat(src_path)
os.chown(dst_path, st.st_uid, st.st_gid)
check except:
import os
def copy_owner_group(src, dst):
try:
st = os.stat(src)
except Exception as e:
print 'stat except:', e
else:
try:
os.chown(dst, st.st_uid, st.st_gid)
except Exception as e:
print 'chmod except:', e

Run a .bat program in the background on Windows

I am trying to run a .bat file (which acts as a simulator) in a new window, so it must always be running in the background. I think that creating a new process is the only option that I have. Basically, I want my code to do something like this:
def startSim:
# open .bat file in a new window
os.system("startsim.bat")
# continue doing other stuff here
print("Simulator started")
I'm on Windows so I can't do os.fork.
Use subprocess.Popen (not tested on Windows, but should work).
import subprocess
def startSim():
child_process = subprocess.Popen("startsim.bat")
# Do your stuff here.
# You can terminate the child process after done.
child_process.terminate()
# You may want to give it some time to terminate before killing it.
time.sleep(1)
if child_process.returncode is None:
# It has not terminated. Kill it.
child_process.kill()
Edit: you could also use os.startfile (Windows only, not tested too).
import os
def startSim():
os.startfile("startsim.bat")
# Do your stuff here.
Looks like you want "os.spawn*", which seems to equate to os.fork, but for Windows.
Some searching turned up this example:
# File: os-spawn-example-3.py
import os
import string
if os.name in ("nt", "dos"):
exefile = ".exe"
else:
exefile = ""
def spawn(program, *args):
try:
# check if the os module provides a shortcut
return os.spawnvp(program, (program,) + args)
except AttributeError:
pass
try:
spawnv = os.spawnv
except AttributeError:
# assume it's unix
pid = os.fork()
if not pid:
os.execvp(program, (program,) + args)
return os.wait()[0]
else:
# got spawnv but no spawnp: go look for an executable
for path in string.split(os.environ["PATH"], os.pathsep):
file = os.path.join(path, program) + exefile
try:
return spawnv(os.P_WAIT, file, (file,) + args)
except os.error:
pass
raise IOError, "cannot find executable"
#
# try it out!
spawn("python", "hello.py")
print "goodbye"
On Windows, a background process is called a "service". Check this other question about how to create a Windows service with Python: Creating a python win32 service
import subprocess
proc = subprocess.Popen(['/path/script.bat'],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
Using subprocess.Popen() will run the given .bat path ( or any other executable).
If you do wish to wait for the process to finish just add proc.wait():
proc.wait()

Categories

Resources