Initial commit
commit
aaa3b1a6ec
@ -0,0 +1,122 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import os, sys, pwd, glob, setuplib, subprocess
|
||||
|
||||
def get_uid_gid():
|
||||
try:
|
||||
target_user = pwd.getpwnam("pylsa")
|
||||
except KeyError, e:
|
||||
raise Exception("The PyLSA installation appears to have been corrupted.")
|
||||
|
||||
return (target_user[2], target_user[3])
|
||||
|
||||
def switch_user():
|
||||
target_uid, target_gid = get_uid_gid()
|
||||
|
||||
os.setgid(target_gid)
|
||||
os.setuid(target_uid)
|
||||
|
||||
def install(as_root=False):
|
||||
try:
|
||||
target_uid, target_gid = get_uid_gid()
|
||||
except Exception, e:
|
||||
target_uid, target_gid = (-1, -1)
|
||||
|
||||
if as_root == True:
|
||||
target_path = "/home/pylsa/.pylsa"
|
||||
else:
|
||||
target_path = os.path.expanduser("~/.pylsa")
|
||||
|
||||
setuplib.create_directory(target_path, True, target_uid, target_gid)
|
||||
setuplib.copy_file("src/daemon.py", "%s/daemon.py" % target_path, False, target_uid, target_gid)
|
||||
setuplib.copy_file("pylsa.conf", "%s/pylsa.conf" % target_path, True, target_uid, target_gid)
|
||||
subprocess.call(["tar", "-xzf", "psutil-0.6.1.tar.gz"])
|
||||
os.chdir("psutil-0.6.1")
|
||||
|
||||
stfu = open("/dev/null", "w")
|
||||
if subprocess.call(["python", "setup.py", "build"], stdout=stfu, stderr=stfu) != 0:
|
||||
sys.stderr.write("An error occurred during compilation.\n")
|
||||
exit(1)
|
||||
|
||||
try:
|
||||
build_dir = glob.glob("build/lib.*")[0]
|
||||
except IndexError, e:
|
||||
sys.stderr.write("Compilation appears to have failed, exiting...\n")
|
||||
exit(1)
|
||||
|
||||
setuplib.copy_directory(build_dir, "%s/lib" % target_path, False, target_uid, target_gid)
|
||||
|
||||
def add_user(uname):
|
||||
# Lock /etc/passwd and /etc/group so we can safely add a user.
|
||||
open("/etc/passwd.lock", "w").close()
|
||||
open("/etc/group.lock", "w").close()
|
||||
|
||||
# Find highest non-reserved UID in the user list
|
||||
passwd = open("/etc/passwd", "r+")
|
||||
highest_uid = 1000
|
||||
|
||||
for line in passwd:
|
||||
username, password, uid, gid, name, homedir, shell = line.split(":")
|
||||
|
||||
if username == uname:
|
||||
return True
|
||||
|
||||
if int(uid) < 32000 and int(uid) > highest_uid:
|
||||
highest_uid = int(uid)
|
||||
|
||||
new_uid = highest_uid + 1
|
||||
|
||||
# Find highest non-reserved GID in the group list - we will assume same restrictions as for UID
|
||||
grp = open("/etc/group", "r+")
|
||||
highest_gid = 1000
|
||||
|
||||
for line in grp:
|
||||
groupname, password, gid, users = line.split(":")
|
||||
|
||||
if groupname == uname:
|
||||
return True
|
||||
|
||||
if int(gid) < 32000 and int(gid) > highest_gid:
|
||||
highest_gid = int(gid)
|
||||
|
||||
new_gid = highest_gid + 1
|
||||
|
||||
# Append new user and group
|
||||
passwd.seek(0, 2)
|
||||
grp.seek(0, 2)
|
||||
|
||||
setuplib.create_directory("/home/%s" % uname, True, new_uid, new_gid, "u+rwx g+rx")
|
||||
passwd.write("%s::%d:%d::/home/cvm:/bin/false\n" % (uname, new_uid, new_gid))
|
||||
grp.write("%s::%d:\n" % (uname, new_gid))
|
||||
|
||||
# We're done with /etc/passwd and /etc/group
|
||||
passwd.close()
|
||||
grp.close()
|
||||
|
||||
# Remove the locks on /etc/passwd and /etc/group
|
||||
os.remove("/etc/passwd.lock")
|
||||
os.remove("/etc/group.lock")
|
||||
|
||||
return True
|
||||
|
||||
if os.getuid() == 0:
|
||||
# Script is run as root
|
||||
if os.path.isdir("/home/pylsa/.pylsa"):
|
||||
# Already installed, run as pylsa user
|
||||
switch_user()
|
||||
exit(subprocess.call(["python", "/home/pylsa/.pylsa/daemon.py"]))
|
||||
else:
|
||||
# Not installed yet, install as pylsa user then run
|
||||
add_user("pylsa")
|
||||
install(True)
|
||||
switch_user()
|
||||
exit(subprocess.call(["python", "/home/pylsa/.pylsa/daemon.py"]))
|
||||
else:
|
||||
# Script is run as unprivileged user
|
||||
if os.path.isdir(os.path.expanduser("~/.pylsa")):
|
||||
# Already installed
|
||||
exit(subprocess.call(["python", os.path.expanduser("~/.pylsa/daemon.py")]))
|
||||
else:
|
||||
# Not installed yet
|
||||
install(False)
|
||||
exit(subprocess.call(["python", os.path.expanduser("~/.pylsa/daemon.py")]))
|
Binary file not shown.
@ -0,0 +1 @@
|
||||
|
@ -0,0 +1,148 @@
|
||||
import stat, os, shutil, urllib, subprocess
|
||||
from itertools import dropwhile
|
||||
|
||||
def create_directory(path, ignore_failure=True, uid=-1, gid=-1, modes=""):
|
||||
try:
|
||||
os.makedirs(path)
|
||||
except OSError, e:
|
||||
if ignore_failure:
|
||||
pass
|
||||
else:
|
||||
raise
|
||||
|
||||
if uid != -1 or gid != -1:
|
||||
os.chown(path, uid, gid)
|
||||
|
||||
if modes != "":
|
||||
set_modes(path, modes)
|
||||
|
||||
def copy_file(source, destination, ignore_failure=True, uid=-1, gid=-1, modes=""):
|
||||
if ignore_failure == False:
|
||||
if os.path.exists(destination):
|
||||
raise Exception("Destination path already exists.")
|
||||
|
||||
try:
|
||||
shutil.copy(source, destination)
|
||||
except IOError, e:
|
||||
if ignore_failure:
|
||||
pass
|
||||
else:
|
||||
raise
|
||||
|
||||
if uid != -1 or gid != -1:
|
||||
os.chown(destination, uid, gid)
|
||||
|
||||
if modes != "":
|
||||
set_modes(destination, modes)
|
||||
|
||||
def copy_directory(source, destination, ignore_failure=True, uid=-1, gid=-1, modes=""):
|
||||
if ignore_failure == False:
|
||||
if os.path.exists(destination):
|
||||
raise Exception("Destination path already exists.")
|
||||
|
||||
try:
|
||||
shutil.copytree(source, destination)
|
||||
except IOError, e:
|
||||
if ignore_failure:
|
||||
pass
|
||||
else:
|
||||
raise
|
||||
|
||||
if uid != -1 or gid != -1:
|
||||
os.chown(destination, uid, gid)
|
||||
|
||||
if modes != "":
|
||||
set_modes(destination, modes)
|
||||
|
||||
def create_file(path, contents="", uid=-1, gid=-1, modes=""):
|
||||
f = open(path, "w")
|
||||
|
||||
if contents != "":
|
||||
f.write(contents)
|
||||
|
||||
f.close()
|
||||
|
||||
if uid != -1 or gid != -1:
|
||||
os.chown(path, uid, gid)
|
||||
|
||||
if modes != "":
|
||||
set_modes(path, modes)
|
||||
|
||||
def set_modes(path, modes):
|
||||
mode_map = {
|
||||
"u": {
|
||||
"r": stat.S_IRUSR,
|
||||
"w": stat.S_IWUSR,
|
||||
"x": stat.S_IXUSR
|
||||
},
|
||||
"g": {
|
||||
"r": stat.S_IRGRP,
|
||||
"w": stat.S_IWGRP,
|
||||
"x": stat.S_IXGRP
|
||||
},
|
||||
"o": {
|
||||
"r": stat.S_IROTH,
|
||||
"w": stat.S_IWOTH,
|
||||
"x": stat.S_IXOTH
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
chunks = modes.split(" ")
|
||||
mode = 0
|
||||
|
||||
for chunk in chunks:
|
||||
usertype, changes = chunk.split("+")
|
||||
|
||||
if usertype in mode_map:
|
||||
for change in list(changes):
|
||||
if change in mode_map[usertype]:
|
||||
mode = mode | mode_map[usertype][change]
|
||||
else:
|
||||
raise Exception("Unknown permission in modes specification.")
|
||||
elif usertype == "a":
|
||||
for change in list(changes):
|
||||
for i in mode_map:
|
||||
if change in mode_map[i]:
|
||||
mode = mode | mode_map[i][change]
|
||||
else:
|
||||
raise Exception("Unknown user type in modes specification.")
|
||||
|
||||
os.chmod(path, mode)
|
||||
|
||||
def download_file(name, mirrors):
|
||||
try:
|
||||
file_mirrors = mirrors[name]
|
||||
except KeyError, e:
|
||||
raise Exception("No such file exists in the mirror list.")
|
||||
|
||||
for url in file_mirrors:
|
||||
try:
|
||||
urllib.urlretrieve(url, name)
|
||||
except:
|
||||
continue
|
||||
else:
|
||||
return name
|
||||
|
||||
raise Exception("No functional mirrors found for this file.")
|
||||
|
||||
def install_rpm(path):
|
||||
stfu = open("/dev/null", "wb")
|
||||
|
||||
result = subprocess.call(["yum", "--nogpgcheck", "install", "-y", path], stdout=stfu, stderr=stfu)
|
||||
|
||||
stfu.close()
|
||||
|
||||
if result != 0:
|
||||
raise Exception("Failed to install package.")
|
||||
|
||||
def install_remote_rpm(name, mirrors):
|
||||
download_file(name, mirrors)
|
||||
install_rpm(name)
|
||||
|
||||
def rindex(lst, item):
|
||||
# http://stackoverflow.com/a/6892096/1332715
|
||||
try:
|
||||
return dropwhile(lambda x: lst[x].strip() != item, reversed(xrange(len(lst)))).next()
|
||||
except StopIteration:
|
||||
raise ValueError, "rindex(lst, item): item not in list"
|
@ -0,0 +1,135 @@
|
||||
import sys, os, json
|
||||
from datetime import datetime
|
||||
|
||||
# We need to set both the Python module path and system environment path, to make sure that the daemon
|
||||
# can find both the psutil library and its compiled libraries.
|
||||
sys.path.insert(0, "%s/lib" % os.path.split(os.path.realpath(__file__))[0])
|
||||
os.environ['PATH'] = "%s/lib:%s" % (os.path.split(os.path.realpath(__file__))[0], os.environ['PATH'])
|
||||
|
||||
import psutil
|
||||
|
||||
import urlparse
|
||||
import SocketServer, SimpleHTTPServer
|
||||
|
||||
bind_ip = ""
|
||||
port = 8081
|
||||
|
||||
def generate_stats(get_processes):
|
||||
listed_filesystems = ["ext2", "ext3", "ext4", "reiserfs", "removable", "fixed", "simfs"]
|
||||
|
||||
mem = psutil.virtual_memory()
|
||||
swap = psutil.swap_memory()
|
||||
disks = {}
|
||||
|
||||
for disk in psutil.disk_partitions(True):
|
||||
if disk.fstype in listed_filesystems:
|
||||
usage = psutil.disk_usage(disk.mountpoint)
|
||||
|
||||
disks[disk.mountpoint] = {
|
||||
"device": disk.device,
|
||||
"options": disk.opts,
|
||||
"filesystem": disk.fstype,
|
||||
"total": usage.total,
|
||||
"free": usage.free
|
||||
}
|
||||
|
||||
return_data = {
|
||||
"uptime": (datetime.now() - datetime.fromtimestamp(psutil.BOOT_TIME)).total_seconds(),
|
||||
"memory": {
|
||||
"total": mem.total,
|
||||
"available": mem.available,
|
||||
"used": mem.used,
|
||||
"unused": mem.free
|
||||
},
|
||||
"swap": {
|
||||
"total": swap.total,
|
||||
"used": swap.used,
|
||||
"unused": swap.free,
|
||||
"in": swap.sin,
|
||||
"out": swap.sout
|
||||
},
|
||||
"disk": disks,
|
||||
"cpu": psutil.cpu_percent(percpu=True)
|
||||
}
|
||||
|
||||
if get_processes:
|
||||
processes = []
|
||||
|
||||
for proc in psutil.process_iter():
|
||||
try:
|
||||
cwd = proc.getcwd()
|
||||
except psutil.AccessDenied, e:
|
||||
cwd = None
|
||||
|
||||
processes.append({
|
||||
"pid": proc.pid,
|
||||
"parent": proc.ppid,
|
||||
"name": proc.name,
|
||||
"command": proc.cmdline,
|
||||
"user": proc.username,
|
||||
"status": str(proc.status), # If we don't explicitly use str() here, json module will get confused
|
||||
"cwd": cwd,
|
||||
"cpu": proc.get_cpu_percent(interval=0.1),
|
||||
"rss": proc.get_memory_info()[0]
|
||||
})
|
||||
|
||||
return_data['process'] = processes
|
||||
|
||||
return return_data
|
||||
|
||||
class StatsHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
||||
def do_GET(self):
|
||||
req = urlparse.urlparse(self.path)
|
||||
get_params = urlparse.parse_qs(req.query)
|
||||
path = req.path
|
||||
|
||||
try:
|
||||
get_processes = (get_params['processes'][0] == "1")
|
||||
except:
|
||||
get_processes = False
|
||||
|
||||
if path=='/':
|
||||
self.send_response(200)
|
||||
self.send_header('Content-type','text/json')
|
||||
self.end_headers()
|
||||
self.wfile.write(json.dumps(generate_stats(get_processes)))
|
||||
return
|
||||
else:
|
||||
self.send_response(404)
|
||||
self.send_header('Content-type','text/plain')
|
||||
self.end_headers()
|
||||
self.wfile.write("404 Not Found")
|
||||
return
|
||||
|
||||
#### Hacky way to daemonize the whole thing
|
||||
|
||||
# Fork away
|
||||
if os.fork(): exit(0)
|
||||
os.umask(0)
|
||||
os.setsid()
|
||||
if os.fork(): exit(0)
|
||||
|
||||
# Write PID to file
|
||||
outfile = open("pylsa.pid", "w")
|
||||
outfile.write('%i' % os.getpid())
|
||||
outfile.close()
|
||||
|
||||
# Bind the server
|
||||
httpd = SocketServer.ThreadingTCPServer((bind_ip, port), StatsHandler, False)
|
||||
httpd.allow_reuse_address = True
|
||||
httpd.server_bind()
|
||||
httpd.server_activate()
|
||||
|
||||
# If all went well, we'll redirect streams to silence them
|
||||
sys.stdout.flush()
|
||||
sys.stderr.flush()
|
||||
si = file('/dev/null', 'r')
|
||||
so = file('/dev/null', 'a+')
|
||||
se = file('/dev/null', 'a+', 0)
|
||||
os.dup2(si.fileno(), sys.stdin.fileno())
|
||||
os.dup2(so.fileno(), sys.stdout.fileno())
|
||||
os.dup2(se.fileno(), sys.stderr.fileno())
|
||||
|
||||
# Done!
|
||||
print 'Port=',port
|
||||
httpd.serve_forever()
|
Loading…
Reference in New Issue