├── OO_data_structures.py ├── README.md ├── collapse.log ├── collapse.py ├── command.py ├── find.py ├── grep_generator.py ├── grep_regexp.py ├── keyboard_input.py ├── logging.py ├── ls.py ├── parsing_args.py ├── recursion.py ├── scores.py ├── scores.txt ├── sendmail.py ├── socket.py ├── tail.py └── wc.py /OO_data_structures.py: -------------------------------------------------------------------------------- 1 | class Queue(object): 2 | ''' implements a FIFO queue''' 3 | 4 | def __init__(self): 5 | self.L = [] 6 | 7 | def add(self, element): 8 | self.L.append(element) 9 | 10 | def pop(self): 11 | return self.L.pop(0) 12 | 13 | def size(self): 14 | return len(self.L) 15 | 16 | def show(self): 17 | print self.L 18 | 19 | 20 | q = Queue() 21 | 22 | q.add(1) 23 | q.add(2) 24 | q.add(3) 25 | 26 | q.pop() 27 | q.show() 28 | 29 | 30 | class LinkedList(object): 31 | ''' implements linked list A -> B -> C''' 32 | 33 | def __init__(self): 34 | self.d = {} 35 | 36 | def append(self, element): 37 | last = 0 38 | if len(self.d) > 0: 39 | last = max(self.d.keys()) 40 | self.d[last+1] = element 41 | 42 | def show(self): 43 | keylist = list(self.d.keys()) 44 | keylist.sort() 45 | for k in keylist: 46 | print self.d[k] + " -> ", 47 | 48 | 49 | ll = LinkedList() 50 | 51 | ll.append("To") 52 | ll.append("be") 53 | ll.append("or") 54 | ll.append("not") 55 | ll.append("to") 56 | ll.append("be") 57 | 58 | ll.show() 59 | 60 | # ------------------------------------------------------------ 61 | # Inheritance Example 62 | class aPlayer(object): 63 | ''' Object for players''' 64 | def __init__(self, name="none", skill=0.0): 65 | self.name = name 66 | self.skill = skill 67 | 68 | def summary(self): 69 | print "%s: %.2f" %(str(self.name), float(self.skill)) 70 | 71 | 72 | class aGoalie(aPlayer): 73 | ''' goalie is-a Player ''' 74 | def __init__(self, name, skill=0.0, height=0.0): 75 | super(aGoalie,self).__init__(name, skill) 76 | self.height = height 77 | 78 | 79 | pepe = aPlayer("Pepe") 80 | pepe.summary() 81 | 82 | paco = aPlayer("Paco", 23) 83 | paco.summary() 84 | 85 | luis = aPlayer("Luis", 35.223) 86 | luis.summary() 87 | 88 | neuer = aGoalie("Neuer") 89 | neuer.summary() 90 | 91 | iker = aGoalie("Iker", 3.1, 5.9) 92 | iker.summary() 93 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Python-for-Linux-Sysadmin 2 | 3 | - Aimed at Linux sysadmins with knowledge of Bash or Perl that are learning Python or developers wanting to perform system administration or automate Linux stuff with Python 4 | - Based on Python 2.7 5 | - Examples based on usage of the Python modules that are most useful for sysadmin work 6 | 7 | ## Basic Modules 8 | 9 | - Interacting with the Operating System: [os](https://docs.python.org/2/library/os.html) 10 | - Interactign with the Interpreter (gettign args for ex) [sys](https://docs.python.org/2/library/sys.html) 11 | - Executing Linux commands: [subprocess](https://docs.python.org/2/library/subprocess.html) 12 | - High Level File Operations [shutil](https://docs.python.org/2/library/shutil.html) 13 | - Command line options [argparse](https://docs.python.org/2/library/argparse.html) 14 | - Config file parser [ConfigParser](https://docs.python.org/2/library/configparser.html) 15 | - Logging [logging](https://docs.python.org/2/library/logging.html) 16 | - Network connections [socket](https://docs.python.org/2/library/socket.html) 17 | 18 | ## Other Modules 19 | 20 | - Send mail with [smtplib](https://docs.python.org/2/library/smtplib.html) 21 | - Filename pattern matching with [fnmatch] (https://docs.python.org/2/library/fnmatch.html) 22 | - datetime 23 | - itertools 24 | - paramiko 25 | - daemon 26 | - filecmp 27 | - glob 28 | - csv 29 | - requests 30 | -------------------------------------------------------------------------------- /collapse.log: -------------------------------------------------------------------------------- 1 | Jan 20 03:25:08 fakehost logrotate: ALERT exited abnormally with [1] 2 | Jan 20 03:25:09 fakehost run-parts(/etc/cron.daily)[20447]: finished logrotate 3 | Jan 20 03:26:21 fakehost anacron[28969]: Job 'cron.daily' terminated 4 | Jan 20 03:26:22 fakehost anacron[28969]: Normal exit (1 job run) 5 | Jan 20 03:30:01 fakehost CROND[31462]: (root) CMD (/usr/lib64/sa/sa1 1 1) 6 | Jan 20 03:30:01 fakehost CROND[31461]: (root) CMD (/var/system/bin/sys-cmd -F > /dev/null 2>&1) 7 | Jan 20 05:03:03 fakehost ntpd[3705]: synchronized to time.faux.biz, stratum 2 8 | Jan 20 05:20:01 fakehost rsyslogd: [origin software="rsyslogd" swVersion="5.8.10" x-pid="20438" x-info="http://www.rsyslog.com"] start 9 | Jan 20 05:22:04 fakehost cs3[31163]: Q: ".../bin/rsync -LD ": symlink has no referent: "/var/syscmds/fakehost/runit_scripts/etc/runit/service/superImportantService/run"#012Q: ".../bin/rsync -LD ": rsync error: some files/attrs were not transferred (see previous errors) (code 23) at main.c(1039) [sender=3.0.6] 10 | Jan 20 05:22:04 fakehost cs3[31163]: I: Last 2 quoted lines were generated by "/usr/local/bin/rsync -LD --recursive --delete --password-file=/var/syscmds/modules/rsync_password /var/syscmds/fakehost syscmds@fakehost::syscmds_rsync" 11 | Jan 20 05:22:08 fakehost cs3[31163]: Q: ".../sbin/sv restart": ok: run: /export/service/cool-service: (pid 32323) 0s 12 | Jan 20 05:22:08 fakehost cs3[31163]: I: Last 1 quoted lines were generated by "/sbin/sv restart /export/service/cool-service" 13 | Jan 20 05:22:09 fakehost cs3[31163]: R: cs3: The cool service on fakehost does not appear to be communicating with the cool service leader. Automating a restart of the cool service in attempt to resolve the communication problem. 14 | Jan 20 05:22:37 fakehost ACCT_ADD: WARNING: Manifest /var/syscmds/inputs/config-general/doit.txt has been processed already 15 | -------------------------------------------------------------------------------- /collapse.py: -------------------------------------------------------------------------------- 1 | # Read a log file with contents like collapse.log file: 2 | # Jan 20 03:25:08 message 3 | # and print out the minute and number of messages in that minute, for ex: 4 | # Jan 20 03:25 2 5 | # ... 6 | 7 | 8 | def collapse(afile): 9 | with open(afile) as fd: 10 | last_minute = "xxxxxxxxxxx" 11 | freq = 0 12 | for line in fd: 13 | minute = line[:12] #Jan 20 03:25 14 | if minute == last_minute: 15 | freq += 1 16 | else: 17 | print minute, freq 18 | freq = 0 19 | last_minute = minute 20 | print minute, freq # last minute not printed above 21 | 22 | 23 | collapse('collapse.log') 24 | -------------------------------------------------------------------------------- /command.py: -------------------------------------------------------------------------------- 1 | import shlex, subprocess 2 | 3 | 4 | def execute(command): 5 | ''' Executes external command ''' 6 | # shlex.split tokenizes command into a list 7 | args = shlex.split(command) 8 | res = subprocess.Popen(args, stdout = subprocess.PIPE) 9 | print res.stdout.read().strip() 10 | 11 | execute('ls -l') 12 | -------------------------------------------------------------------------------- /find.py: -------------------------------------------------------------------------------- 1 | import os 2 | import fnmatch 3 | 4 | def findall(topdir, pattern): 5 | ''' simple implementation of the find Bash utility ''' 6 | for path, dirs, files in os.walk(topdir): 7 | for filename in files: 8 | if fnmatch.fnmatch(filename, pattern): 9 | yield os.path.join(path, filename) 10 | 11 | 12 | for f in findall(".", "*.py"): 13 | print f 14 | -------------------------------------------------------------------------------- /grep_generator.py: -------------------------------------------------------------------------------- 1 | def grep(afile, astring): 2 | ''' function implementing grep-like , with generator ''' 3 | with open(afile) as fd: 4 | for line in fd: 5 | if astring in line: 6 | yield str(line).strip() 7 | 8 | g = grep("scores.txt", "john") 9 | 10 | print g.next() # first result 11 | print g.next() # second result 12 | 13 | print next(g, '- no more results -') # better, no StopIteration exception but returns default value 14 | -------------------------------------------------------------------------------- /grep_regexp.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | def grep(afile, asearch): 4 | ''' find asearch in afile ''' 5 | reobj = re.compile(asearch) 6 | matches = 0 7 | with open(afile) as fd: 8 | for line in fd: 9 | if reobj.search(line): 10 | matches += 1 11 | print line.strip() 12 | 13 | print '----' 14 | print "%d matches found" % matches 15 | 16 | 17 | grep("scores.txt","john") 18 | -------------------------------------------------------------------------------- /keyboard_input.py: -------------------------------------------------------------------------------- 1 | # Guessing age game 2 | 3 | import sys 4 | 5 | maxage = 120 6 | guess = 50 7 | message = "Are you younger(y), older(o) or exactly {myguess} years old? " 8 | while True: 9 | answer = raw_input(message.format(myguess=guess)) 10 | if answer.lower() == 'x': 11 | print "You look good" 12 | sys.exit(0) 13 | if guess == maxage - 1: 14 | print "Nah, dont' believe you!" 15 | sys.exit(0) 16 | if answer.lower() == 'o': 17 | guess = (maxage+guess)//2 18 | elif answer.lower() == 'y': 19 | guess = guess//2 20 | else: 21 | print "Please answser y,o or x" 22 | -------------------------------------------------------------------------------- /logging.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | applog = logging.getLogger() 4 | #applog.setLevel(logging.INFO) 5 | applog.addHandler(logging.FileHandler('app.log')) 6 | 7 | applog.info('info message') 8 | applog.critical('critical message') 9 | -------------------------------------------------------------------------------- /ls.py: -------------------------------------------------------------------------------- 1 | import os 2 | from sys import argv 3 | 4 | path = "." 5 | if len(argv) >= 2: 6 | path = argv[1] 7 | 8 | for i in os.listdir(path): 9 | print i, 10 | -------------------------------------------------------------------------------- /parsing_args.py: -------------------------------------------------------------------------------- 1 | # optparse deprecated in 2.7 2 | import optparse 3 | 4 | p = optparse.OptionParser() 5 | p.add_option("-i", "--inputfile", action="store", type="string", dest="infile") 6 | opt, args = p.parse_args() 7 | 8 | print "in file: ", opt.infile 9 | 10 | 11 | # use argparse instead in 2.7 12 | import argparse 13 | 14 | parser = argparse.ArgumentParser() 15 | parser.add_argument("-i", action="store", dest="infile") # type string is default 16 | args = parser.parse_args() 17 | 18 | print "in file: ", args.infile 19 | -------------------------------------------------------------------------------- /recursion.py: -------------------------------------------------------------------------------- 1 | # simple recursion examples 2 | 3 | def fact1(n): 4 | ''' Computes the factorial of a positive integer''' 5 | if n < 2: return 1 6 | return n * fact1(n-1) 7 | 8 | # storing previous smaller results in this dict 9 | # bigger results are computed but not used afterwards 10 | saved = {} 11 | def fact2(n): 12 | ''' Factorial using (some) memoization ''' 13 | if n < 2: return 1 14 | if n not in saved: 15 | saved[n] = n * fact2(n-1) 16 | return saved[n] 17 | 18 | 19 | def fibo1(n): 20 | ''' Computes whole Fibonacci secuence up to a positive integer, no recursion''' 21 | L = [1,1] 22 | if n<= 2: return L 23 | for i in range(n-2): 24 | L.append(L[-1] + L[-2]) 25 | return L 26 | 27 | def fibo2(n): 28 | ''' Nth fibonacci element using recursion''' 29 | return n if n < 2 else fibo2(n - 1) + fibo2(n -2) 30 | 31 | 32 | print fact1(6) 33 | print fact2(6) 34 | print fact2(8) 35 | from math import factorial 36 | print factorial(6) 37 | 38 | 39 | print fibo1(10) 40 | print fibo2(10) 41 | -------------------------------------------------------------------------------- /scores.py: -------------------------------------------------------------------------------- 1 | # Find stats (max, average) from a scores.txt files of the form: 2 | # student_name score 3 | # student_name score 4 | # where student_name can be repeated and score is a numerical value 5 | 6 | # Solution: 7 | # 1. read file, get values in dictionary of lists like: 8 | # grades = { "joe": [2, 4.5], 9 | # "mary": [0.3, 3.4, 6.7], 10 | # "tom": [3] 11 | # } 12 | 13 | 14 | grades = {} 15 | with open("scores.txt") as fd: 16 | for line in fd: 17 | line.strip() 18 | student, score = line.split() 19 | score = float(score) 20 | print student, score 21 | if not grades.get(student): 22 | grades[student] = [score] 23 | else: 24 | grades[student].extend([score]) 25 | 26 | 27 | print "Grades: ", grades 28 | 29 | # 2. calculate stats 30 | L = [] 31 | max_value = 0.0 32 | for k, vlist in grades.items(): 33 | # find max score, student with max score 34 | if max(vlist) > max_value: 35 | max_value = max(vlist) 36 | max_student = k 37 | # get all scores in a list 38 | L.extend(vlist) 39 | 40 | # average 41 | ave = sum(L) / len(L) 42 | 43 | print "Max score: %.2f" %max_value 44 | print "Max student: %s" %max_student 45 | print "Average score: %.2f" %ave 46 | 47 | -------------------------------------------------------------------------------- /scores.txt: -------------------------------------------------------------------------------- 1 | john 4.5 2 | mary 3.1 3 | luis 0.5 4 | mark 0 5 | john 2.2 6 | luis 3.7 7 | carl 6 8 | -------------------------------------------------------------------------------- /sendmail.py: -------------------------------------------------------------------------------- 1 | # --- Simple emaling script --- 2 | # usage: sendmail.py subject body 3 | 4 | # parameters: 5 | sender = 'postgres@localhost' 6 | receivers = ['monitor@example.com', ] 7 | server = 'smtp.example.com' 8 | 9 | # ------------------------------ 10 | 11 | import smtplib 12 | from email.mime.text import MIMEText 13 | from smtplib import SMTPException 14 | import sys 15 | import subprocess 16 | 17 | if len(sys.argv) != 3: 18 | print "Usage: sendmail.py subject body" 19 | sys.exit() 20 | 21 | subject = str(sys.argv[1]) 22 | body = str(sys.argv[2]) 23 | 24 | msg = MIMEText(body) 25 | msg['Subject'] = subject 26 | msg['From'] = sender 27 | msg['To'] = ", ".join(receivers) 28 | 29 | try: 30 | smtpObj = smtplib.SMTP(server) 31 | smtpObj.sendmail(sender, receivers, msg.as_string()) 32 | subprocess.call(["logger", "sendmail.py successfully sent email"]) 33 | except SMTPException as e: 34 | subprocess.call(["logger", "ERROR: sendmail.py SMTPException: %s" % e.strerror]) 35 | 36 | -------------------------------------------------------------------------------- /socket.py: -------------------------------------------------------------------------------- 1 | import socket 2 | 3 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 4 | address = '127.0.0.1' 5 | port = 80 6 | 7 | try: 8 | s.connect((address, port)) 9 | except Exception, e: 10 | print('ERROR connecting to %s:%d :%s' % (address, port, e)) 11 | -------------------------------------------------------------------------------- /tail.py: -------------------------------------------------------------------------------- 1 | def tail(afile, last=10): 2 | ''' implements tail-like function (for chars, not lines) ''' 3 | offset = last 4 | with open(afile) as fd: 5 | fd.seek(0, 2) 6 | len = fd.tell() 7 | if last > len: 8 | offset = len 9 | fd.seek(offset*(-1), 2) 10 | tail = fd.read(last) 11 | print str(tail) 12 | 13 | tail('scores.txt') 14 | tail('scores.txt', 5) 15 | -------------------------------------------------------------------------------- /wc.py: -------------------------------------------------------------------------------- 1 | def wc(afile): 2 | ''' implements word count ''' 3 | with open(afile) as fd: 4 | all = fd.read() 5 | chars = len(all) 6 | lines = len(all.split('\n')) # os.linesep 7 | wordlist = all.split(None) 8 | words = len(wordlist) 9 | return lines, words, chars 10 | 11 | print wc('scores.txt') 12 | --------------------------------------------------------------------------------