203 lines
5.7 KiB
Plaintext
203 lines
5.7 KiB
Plaintext
This is a collection of snippets that I tend to use frequently, or would need
|
|
in the future.
|
|
|
|
###############################################################################
|
|
|
|
To programmatically import a list of modules by name:
|
|
_____
|
|
import importlib
|
|
|
|
mods = ['os', 'sys', 'shutil', 'platform']
|
|
|
|
for m in mods:
|
|
globals()[m] = importlib.import_module(m)
|
|
_____
|
|
you can then use them as if you did:
|
|
|
|
import os
|
|
import sys
|
|
import shutil
|
|
import platform
|
|
etc.
|
|
|
|
this breaks pep-8, but sometimes you need to programmatically import modules.
|
|
|
|
ref: https://www.python.org/dev/peps/pep-0008/#imports
|
|
|
|
###############################################################################
|
|
|
|
To programmatically install modules via pip if they aren't installed (BROKEN IN RECENT PIP VERSIONS; pip._internal.main() i think):
|
|
|
|
____
|
|
import importlib
|
|
import pip
|
|
|
|
# I don't *think* pip/pypi is case-sensitive, but frequently module names are
|
|
# not the same as their package names. ugh.
|
|
# The key is the package name, the value is the module name. We use the above
|
|
# trick here to try to import and install if it fails.
|
|
mods = {'PyMySQL': 'pymysql',
|
|
'Jinja2': 'jinja2',
|
|
'psutil': None, # We show off a little bit here with this, see below.
|
|
'paramiko': None} # ""
|
|
|
|
for m in mods.keys():
|
|
modname = mods[m]
|
|
if not modname:
|
|
modname = m
|
|
try:
|
|
globals()[modname] = importlib.import_module(modname)
|
|
except ImportError:
|
|
# We use --user to avoid conflicts with the host's python system.
|
|
# pip.main() accepts all of pip (commandline)'s args!
|
|
pip.main(['install', '--user', m])
|
|
try:
|
|
globals()[modname] = importlib.import_module(modname)
|
|
except ImportError:
|
|
raise RuntimeError('Unable to install {0}!'.format(m))
|
|
____
|
|
|
|
###############################################################################
|
|
|
|
To convert an argparse set of parsed arguments into a dict from a class, you
|
|
simply do:
|
|
____
|
|
def GenArgs():
|
|
args = argparse.ArgumentParser()
|
|
# args here
|
|
return(args)
|
|
|
|
def somefunc():
|
|
args = vars(GenArgs().parse_args())
|
|
____
|
|
"args" in somefunc is a dict now.
|
|
|
|
###############################################################################
|
|
|
|
To dynamically allocate class parameters into constants from a dict (such as
|
|
from argparse - see above), do something like this:
|
|
____
|
|
class ClassName(object):
|
|
def __init__(self, **kwargs):
|
|
for i in kwargs.keys():
|
|
setattr(self, i, kwargs[i])
|
|
----
|
|
|
|
###############################################################################
|
|
|
|
To store stdout and stderr to different files in a subprocess call:
|
|
----
|
|
with open('/tmp/test.o', 'w') as out, open('/tmp/test.e', 'w') as err:
|
|
subprocess.run(['command'], stdout = out, stderr = err)
|
|
----
|
|
###############################################################################
|
|
|
|
To use optools logging lib (or other "shared" modules):
|
|
----
|
|
import os
|
|
import re
|
|
import importlib
|
|
spec = importlib.util.spec_from_file_location(
|
|
'logger',
|
|
'/opt/dev/optools/lib/python/logger.py')
|
|
logger = importlib.util.module_from_spec(spec)
|
|
spec.loader.exec_module(logger)
|
|
log = logger.log(name = 'project.name')
|
|
----
|
|
|
|
###############################################################################
|
|
|
|
# TODO #
|
|
https://stackoverflow.com/questions/10265193/python-can-a-class-act-like-a-module
|
|
|
|
|
|
###############################################################################
|
|
|
|
To issue an equivalent of "reset" command in linux, assuming console is ANSI-compat,
|
|
|
|
print('\x1bc', end = '')
|
|
|
|
###############################################################################
|
|
|
|
|
|
To get the default route via pyroute2,
|
|
----
|
|
import socket
|
|
from pyroute2 import IPDB
|
|
ip = IPDB()
|
|
def_rt = ip.routes['default'] # a route object
|
|
iface = ip.interfaces[def_rt.oif] # an interface object. name is e.g. iface.ifname, IPs are in tuple-of-tuples iface.ipaddr, etc.
|
|
gw = def_rt.gateway # etc.
|
|
ip.release()
|
|
----
|
|
|
|
###############################################################################
|
|
|
|
|
|
dropping privileges to non-root user (and restoring):
|
|
https://stackoverflow.com/questions/2699907/dropping-root-permissions-in-python
|
|
https://stackoverflow.com/questions/15705439/drop-root-privileges-for-certain-operations-in-python
|
|
|
|
NOTE: if you want to *remove the ability* to restore back to root privs, use os.setgid(running_gid) and os.setuid(running_uid) instead.
|
|
|
|
reference:
|
|
http://timetobleed.com/5-things-you-dont-know-about-user-ids-that-will-destroy-you/
|
|
https://nanopdf.com/download/setuid-demystified_pdf
|
|
|
|
----
|
|
import os, pwd, grp
|
|
import subprocess
|
|
|
|
my_uid = pwd.getpwuid(os.geteuid()).pw_uid
|
|
my_gid = grp.getgrgid(os.getegid()).gr_gid
|
|
my_grps = os.getgroups()
|
|
try:
|
|
os.remove('/tmp/usertest')
|
|
os.remove('/tmp/parenttest')
|
|
except:
|
|
pass
|
|
if os.getuid() != 0:
|
|
exit('need root')
|
|
running_uid = pwd.getpwnam(uid_name).pw_uid
|
|
running_gid = grp.getgrnam(gid_name).gr_gid
|
|
os.setgroups([])
|
|
os.setegid(running_gid)
|
|
os.seteuid(running_uid)
|
|
old_umask = os.umask(0o022)
|
|
subprocess.run(['touch', '/tmp/usertest'])
|
|
os.seteuid(my_uid)
|
|
os.setegid(my_gid)
|
|
os.setgroups(my_grps)
|
|
os.umask(old_umask)
|
|
subprocess.run(['touch', '/tmp/parenttest'])
|
|
|
|
###############################################################################
|
|
|
|
|
|
Getting remote sshd version
|
|
|
|
stdlib:
|
|
----
|
|
import socket
|
|
|
|
try:
|
|
sock = socket.socket()
|
|
sock.settimeout(10)
|
|
sock.connect(('cylon', 22))
|
|
version = sock.recv(64).decode('utf-8').strip()
|
|
# version is a string like "SSH-2.0-OpenSSH_7.9"
|
|
sock.close()
|
|
except Exception as e:
|
|
# Obviously you can specify multiple exceptions to catch.
|
|
raise RuntimeError(e)
|
|
----
|
|
|
|
paramiko (does not require auth):
|
|
----
|
|
import paramiko
|
|
|
|
t = paramiko.Transport(('cylon', 22))
|
|
t.connect()
|
|
t.remote_version
|
|
----
|