diff options
-rw-r--r-- | MANIFEST.in | 1 | ||||
-rw-r--r-- | cobbler.spec | 2 | ||||
-rw-r--r-- | cobbler/action_status.py | 187 | ||||
-rw-r--r-- | cobbler/action_sync.py | 87 | ||||
-rw-r--r-- | setup.py | 4 |
5 files changed, 117 insertions, 164 deletions
diff --git a/MANIFEST.in b/MANIFEST.in index 650b088..445e623 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,6 +1,7 @@ include loaders/COPYING_ELILO include loaders/elilo-3.6-ia64.efi include loaders/menu.c32 +include templates/cobbler.conf include templates/dhcp.template include templates/pxeprofile.template include templates/pxedefault.template diff --git a/cobbler.spec b/cobbler.spec index 08c3742..b50f616 100644 --- a/cobbler.spec +++ b/cobbler.spec @@ -79,7 +79,6 @@ test "x$RPM_BUILD_ROOT" != "x" && rm -rf $RPM_BUILD_ROOT %dir /var/www/cobbler/profiles %dir /var/www/cobbler/systems %dir /var/www/cobbler/links -/var/www/cobbler/watcher.py* %defattr(-,root,root) %dir /tftpboot/pxelinux.cfg %dir /tftpboot/images @@ -105,6 +104,7 @@ test "x$RPM_BUILD_ROOT" != "x" && rm -rf $RPM_BUILD_ROOT /var/lib/cobbler/elilo-3.6-ia64.efi /var/lib/cobbler/menu.c32 /etc/init.d/cobblersyslogd +/etc/httpd/conf.d/cobbler.conf %dir /var/log/cobbler/syslog %doc AUTHORS CHANGELOG NEWS README COPYING diff --git a/cobbler/action_status.py b/cobbler/action_status.py index 09befef..b3e94a2 100644 --- a/cobbler/action_status.py +++ b/cobbler/action_status.py @@ -29,7 +29,72 @@ class BootStatusReport: self.settings = config.settings() self.mode = mode - # ------------------------------------------------------- + # ------------------------------------------------------- + + def scan_apache_logfiles(self): + results = {} + files = [ "/var/log/httpd/access_log" ] + for x in range(1,4): + consider = "/var/log/httpd/access_log.%s" % x + if os.path.exists(consider): + files.append(consider) + for fname in files: + fh = open(fname) + data = fh.readline() + while (data is not None and data != ""): + data = fh.readline() + #print data + tokens = data.split(None) + if len(tokens) < 6: + continue + #print "----" + ip = tokens[0] + stime = tokens[3].replace("[","") + req = tokens[6] + if req.find("/cblr") == -1: + continue + #print "%s,%s,%s,%s" % (tokens,ip,time,req) + ttime = time.strptime(stime,"%d/%b/%Y:%H:%M:%S") + #print ttime + itime = time.mktime(ttime) + if not results.has_key(ip): + results[ip] = {} + #print "ip (%s) time (%s) req (%s)" % (ip,itime,req) + results[ip][itime] = req + + return results + + # ------------------------------------------------------- + + def scan_syslog_logfiles(self): + + # find all of the logged IP addrs + filelist = glob.glob("/var/log/cobbler/syslog/*") + filelist.sort() + results = {} + + for fullname in filelist: + #fname = os.path.basename(fullname) + logfile = open(fullname, "r") + # for each line in the file... + data = logfile.readline() + while(data is not None and data != ""): + data = logfile.readline() + + try: + (epoch, strdate, ip, request) = data.split("\t", 3) + epoch = float(epoch) + except: + continue + + if not results.has_key(ip): + results[ip] = {} + # print "results (%s) (%s) <- %s" % (ip, epoch, request) + results[ip][epoch] = request + + return results + + # ------------------------------------------------------- def run(self): """ @@ -37,91 +102,56 @@ class BootStatusReport: For kickstart trees not in /var/lib/cobbler (or a symlink off of there) tracking will be incomplete. This should be noted in the docs. """ - + + apache_results = self.scan_apache_logfiles() + syslog_results = self.scan_syslog_logfiles() + ips = apache_results.keys() + ips.sort() + ips2 = syslog_results.keys() + ips2.sort() + + ips.extend(ips2) + ip_printed = {} + last_recorded_time = 0 time_collisions = 0 - - # find all of the logged IP addrs - filelist = glob.glob("/var/log/cobbler/syslog/*") - filelist.sort() header = ("Address", "State", "Started", "Last Request", "Seconds", "Log Entries") print "%-20s | %-15s | %-25s | %-25s | %-10s | %-6s" % header - for fullname in filelist: - fname = os.path.basename(fullname) # access times log - fullname2 = "/var/log/cobbler/kicklog/%s" % fname # remote syslog - + + for ip in ips: + if ip_printed.has_key(ip): + continue + ip_printed[ip] = 1 entries = {} # hash of access times and messages - ip = None - - # both types of log files must be intertwingled (TM) - - for openme in [ fullname, fullname2 ]: - - # it's possible syslog never hit the server, that's ok. - if not os.path.exists(openme): - continue - - logfile = open(openme, "r") - data = "..." - - # for each line in the file... - while(data is not None and data != ""): - data = logfile.readline() - - # fields are tab delimited - # (1) seconds since 1970, in decimal - # (2) ASCII date for humans - # (3) IP address of requester - # (4) HTTP request line - - try: - (epoch, strdate, ip, request) = data.split("\t", 3) - except: - continue - - # HTTP request line is essentially space delimited - # (1) method, which should always be GET - # (2) filename, which is relative from server root - # (3) protocol, such as HTTP/1.1 - - # time collision voodoo - # we are storing times in a hash, and this prevents them from colliding - # which would break the filecount and possibly the state check - - logtime = float(epoch) - if int(logtime) == last_recorded_time: - time_collisions = time_collisions + 1 - else: - time_collisions = 0 - logtime = logtime + (0.001 * time_collisions) - - # to make the report generation a bit easier, flag what we think are start/end points - + if apache_results.has_key(ip): + times = apache_results[ip].keys() + for logtime in times: + request = apache_results[ip][logtime] if request.find("?system_done") != -1: - entries[logtime] = "DONE:%s" % request + entries[logtime] = "DONE" elif request.find("?profile_done") != -1: - entries[logtime] = "DONE:%s" % request - elif request.find("methodcomplete") != -1: - entries[logtime] = "DONE:%s" % request - elif request.find("Method =") != -1: - entries[logtime] = "START:%s" % request + entries[logtime] = "DONE" else: entries[logtime] = "1" # don't really care what the filename was - last_recorded_time = int(logtime) - - # FIXME: calculate start times for each IP as defined as earliest file - # requested after each stop time, or the first file requested if no - # stop time. - - logfile.close() + if syslog_results.has_key(ip): + times = syslog_results[ip].keys() + for logtime in times: + request = syslog_results[ip][logtime] + if request.find("methodcomplete") != -1: + entries[logtime] = "DONE" + elif request.find("Method =") != -1: + entries[logtime] = "START" + else: + entries[logtime] = "1" - # print the report line for this IP addr self.generate_report(entries,ip) + # print entries + return True #----------------------------------------- @@ -142,23 +172,27 @@ class BootStatusReport: last_done_time = 0 fcount = 0 + if len(rtimes) == 0: + print "%s: ?" % ip + return + # for each request time the machine has made for rtime in rtimes: rtime = rtime fname = entries[rtime] - if fname.startswith("START:"): + if fname == "START": install_state = "installing" last_start_time = rtime last_request_time = rtime fcount = 0 - elif fname.startswith("DONE"): + elif fname == "DONE": # kickstart finished last_done_time = rtime install_state = "done" else: - install_state = "installing" + install_state = "?" last_request_time = rtime fcount = fcount + 1 @@ -172,7 +206,12 @@ class BootStatusReport: # FIXME: IP to MAC mapping where cobbler knows about it would be nice. display_start = time.asctime(time.localtime(last_start_time)) display_last = time.asctime(time.localtime(last_request_time)) - + + if display_start.find(" 1969") != -1: + display_start = "?" + elapsed_time = "?" + # print the status line for this IP address print "%-20s | %-15s | %-25s | %-25s | %-10s | %-6s" % (ip, install_state, display_start, display_last, elapsed_time, fcount) + diff --git a/cobbler/action_sync.py b/cobbler/action_sync.py index d0efa06..2af7dd1 100644 --- a/cobbler/action_sync.py +++ b/cobbler/action_sync.py @@ -63,7 +63,6 @@ class BootSync: self.clean_trees() self.copy_koan() self.copy_bootloaders() - self.configure_httpd() self.copy_distros() self.validate_kickstarts() self.build_trees() @@ -167,92 +166,6 @@ class BootSync: for x in metadata.keys(): template_data = template_data.replace("$%s" % x, metadata[x]) - def configure_httpd(self): - """ - Create a config file to Apache that will allow access to the - cobbler infrastructure available over TFTP over HTTP also. - """ - - conf_file = "/etc/httpd/conf.d/cobbler.conf" - - if not os.path.exists("/etc/httpd/conf.d"): - print cobbler_msg.lookup("no_httpd") - return - - # now we're going to figure out whether we actually need to write - # the file. If the file exists and contains self.settings.webdir, - # then we don't. and if the file is already there, then we really - # don't have to restart the service either. - - found_webdir = False - found_track_support = False - if os.path.exists(conf_file): - fh = open(conf_file, "r") - data = fh.read() - if data.find(self.settings.webdir) != -1: - found_webdir = True - if data.find("cblr") != -1: - found_track_support = True - fh.close() - - if found_track_support and found_webdir: - # no http reconfig and restart needed - return - - f = self.open_file(conf_file,"w+") - - # the watcher.py script appears a bit flakey in older Apache 2 versions - # so only install the MP hook when we think Apache can handle it - # otherwise the filter could corrupt some binary files (erg!) and the install - # will die almost immediately. You've got to love all the corner cases in systems mgmt - # software, don't you? - - release_info_fh = os.popen("rpm -q --whatprovides redhat-release") - release_info = release_info_fh.read() - release_info_fh.close() - - mod_python_ok = True - - for x in [ "redhat-release-5", "redhat-release-4", "redhat-release-3", "centos-release-4", "centos-release-3" ]: - if release_info.lower().find(x) != -1: - mod_python_ok = False - - if mod_python_ok: - mp_section = """ - AddHandler mod_python .py - PythonOutputFilter watcher WATCHER - AddOutputFilter WATCHER ks.cfg - AddOutputFilter WATCHER .rpm - AddOutputFilter WATCHER .xml - AddOutputFilter WATCHER .py - PythonDebug On - """ - else: - mp_section = "" - - config_data = """ - # - # This configuration file allows 'cobbler' boot info - # to be accessed over HTTP in addition to PXE. - AliasMatch ^/cobbler(/.*)?$ "/cobbler_webdir$1" - AliasMatch ^/cobbler_track(/.*)?$ "/cobbler_webdir$1" - AliasMatch ^/cblr(/.*)?$ "/cobbler_webdir$1" - <Directory "/cobbler_webdir"> - Options Indexes FollowSymLinks - AllowOverride None - Order allow,deny - Allow from all - MPSECTION - </Directory> - """ - # this defaults to /var/www/cobbler if user didn't change it - config_data = config_data.replace("/cobbler_webdir",self.settings.webdir) - config_data = config_data.replace("MPSECTION", mp_section) - self.tee(f, config_data) - self.close_file(f) - - self.service("httpd", "reload") - def clean_trees(self): """ Delete any previously built pxelinux.cfg tree and virt tree info and then create @@ -15,6 +15,7 @@ if __name__ == "__main__": manpath = "share/man/man1/" cobpath = "/var/lib/cobbler/" etcpath = "/etc/cobbler/" + wwwconf = "/etc/httpd/conf.d/" wwwpath = "/var/www/cobbler/" initpath = "/etc/init.d/" logpath = "/var/log/cobbler/" @@ -46,8 +47,7 @@ if __name__ == "__main__": ], scripts = ["scripts/cobbler", "scripts/cobbler_syslogd"], data_files = [ - # (docspath, ['README']), - (wwwpath, ['scripts/watcher.py']), + (wwwconf, ['templates/cobbler.conf']), (cobpath, ['loaders/elilo-3.6-ia64.efi']), (cobpath, ['loaders/menu.c32']), (etcpath, ['kickstarts/kickstart_fc5.ks']), |