---
 cobbler/remote.py |  131 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 131 insertions(+), 0 deletions(-)

diff --git a/cobbler/remote.py b/cobbler/remote.py
index e4155d4..5af1218 100644
--- a/cobbler/remote.py
+++ b/cobbler/remote.py
@@ -27,10 +27,14 @@ import sys
 import socket
 import time
 import os
+import md5
+import base64
 import SimpleXMLRPCServer
 import xmlrpclib
 import random
+import stat
 import base64
+import fcntl
 import string
 import traceback
 import glob
@@ -320,6 +324,133 @@ class CobblerXMLRPCInterface:
         
systems.add(obj,save=True,with_triggers=False,with_sync=False,quick_pxe_update=True)
         return True
 
+    def upload_log_data(self, sys_name, file, size, md5sum, offset, data, 
token=None,**rest):
+        """
+        This is a feature used by the pxe_just_once support, see manpage.
+        Sets system named "name" to no-longer PXE.  Disabled by default as
+        this requires public API access and is technically a read-write 
operation.
+        """
+        self._log("upload_log_data (file: '%s', size: %s, offset: %s)" % 
(file, size, offset), token=token, name=sys_name)
+
+        # FIXME: Check if enabled in self.api.settings()
+        #if not self.api.settings().pxe_just_once:
+        if False:
+            # feature disabled!
+            return False
+
+        # Find matching system record
+        systems = self.api.systems()
+        obj = systems.find(name=sys_name)
+        if obj == None:
+            # system not found!
+            self._log("upload_log_data - system '%s' not found" % sys_name, 
token=token, name=sys_name)
+            return False
+
+        return self.__upload_file(sys_name, file, size, md5sum, offset, data)
+
+    def __upload_file(self, sys_name, file, size, md5sum, offset, data):
+        '''
+        system: the name of the system
+        name: the name of the file
+        size: size of contents (bytes)
+        md5: md5sum (hex digest) of contents
+        data: base64 encoded file contents
+        offset: the offset of the chunk
+         files can be uploaded in chunks, if so the md5 and size describe
+         the chunk rather than the whole file. the offset indicates where
+         the chunk belongs
+         the special offset -1 is used to indicate the final chunk'''
+        contents = base64.decodestring(data)
+        del data
+        if offset != -1:
+            if size is not None:
+                if size != len(contents): return False
+            if md5sum is not None:
+                if md5sum != md5.new(contents).hexdigest():
+                    return False
+
+        #XXX - have an incoming dir and move after upload complete
+        # SECURITY - ensure path remains under uploadpath
+        tt = string.maketrans("/","+")
+        fn = string.translate(file, tt)
+        if fn.startswith('..'):
+            raise CX(_("invalid filename used: %s") % fn)
+
+        # FIXME ... get the base dir from cobbler settings()
+        udir = "/var/log/cobbler/anamon/%s" % sys_name
+        if not os.path.isdir(udir):
+            os.makedirs(udir)
+
+        fn = "%s/%s" % (udir, fn)
+        try:
+            st = os.lstat(fn)
+        except OSError, e:
+            if e.errno == errno.ENOENT:
+                pass
+            else:
+                raise
+        else:
+            if not stat.S_ISREG(st.st_mode):
+                raise CX(_("destination not a file: %s") % fn)
+            elif offset == 0:
+                #first chunk, so file should not exist yet
+                if not fn.endswith('.log'):
+                    # but we allow .log files to be uploaded multiple times to 
support
+                    # realtime log-file viewing
+                    raise CX(_("file already exists: %s") % fn)
+
+        fd = os.open(fn, os.O_RDWR | os.O_CREAT, 0666)
+        # log_error("fd=%r" %fd)
+        try:
+            if offset == 0 or (offset == -1 and size == len(contents)):
+                #truncate file
+                fcntl.lockf(fd, fcntl.LOCK_EX|fcntl.LOCK_NB)
+                try:
+                    os.ftruncate(fd, 0)
+                    # log_error("truncating fd %r to 0" %fd)
+                finally:
+                    fcntl.lockf(fd, fcntl.LOCK_UN)
+            if offset == -1:
+                os.lseek(fd,0,2)
+            else:
+                os.lseek(fd,offset,0)
+            #write contents
+            fcntl.lockf(fd, fcntl.LOCK_EX|fcntl.LOCK_NB, len(contents), 0, 2)
+            try:
+                os.write(fd, contents)
+                # log_error("wrote contents")
+            finally:
+                fcntl.lockf(fd, fcntl.LOCK_UN, len(contents), 0, 2)
+            if offset == -1:
+                if size is not None:
+                    #truncate file
+                    fcntl.lockf(fd, fcntl.LOCK_EX|fcntl.LOCK_NB)
+                    try:
+                        os.ftruncate(fd, size)
+                        # log_error("truncating fd %r to size %r" % (fd,size))
+                    finally:
+                        fcntl.lockf(fd, fcntl.LOCK_UN)
+                if md5sum is not None:
+                    #check final md5sum
+                    sum = md5.new()
+                    fcntl.lockf(fd, fcntl.LOCK_SH|fcntl.LOCK_NB)
+                    try:
+                        # log_error("checking md5sum")
+                        os.lseek(fd,0,0)
+                        while True:
+                            block = os.read(fd, 819200)
+                            if not block: break
+                            sum.update(block)
+                        if md5sum != sum.hexdigest():
+                            # log_error("md5sum did not match")
+                            #os.close(fd)
+                            return False
+                    finally:
+                        fcntl.lockf(fd, fcntl.LOCK_UN)
+        finally:
+            os.close(fd)
+        return True
+
     def run_install_triggers(self,mode,objtype,name,ip,token=None,**rest):
 
         """
-- 
1.6.0.4

_______________________________________________
cobbler mailing list
[email protected]
https://fedorahosted.org/mailman/listinfo/cobbler

Reply via email to