renamed files used at runtime (see post-install script in specfile)
authorThierry Parmentelat <thierry.parmentelat@sophia.inria.fr>
Tue, 1 Jun 2010 07:46:28 +0000 (07:46 +0000)
committerThierry Parmentelat <thierry.parmentelat@sophia.inria.fr>
Tue, 1 Jun 2010 07:46:28 +0000 (07:46 +0000)
curlwrapper now uses pycurl
needs testing

15 files changed:
Makefile
NodeManager.spec
api.py
api_calls.py
bwmon.py
curlwrapper.py
database.py
forward_api_calls.c
logger.py
logrotate/nodemanager [moved from logrotate/nm with 78% similarity]
nm.py
plcapi.py
sliver_vs.py
ticket.py
tools.py

index 4b130d5..f5996ee 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -34,7 +34,7 @@ clean:
 
 ##########
 tags:
-       find . '(' -name '*.py' -o -name '*.c' -o -name '*.spec' ')' | xargs etags 
+       (find . '(' -name '*.py' -o -name '*.c' -o -name '*.spec' ')' ; ls initscripts/*) | xargs etags 
 
 .PHONY: tags
 
index 8711e79..d58342c 100644 (file)
@@ -41,9 +41,6 @@ Requires: util-vserver-python > 0.3-16
 # Signed tickets
 Requires: gnupg
 
-# Contact API server
-Requires: curl
-
 # Uses function decorators
 Requires: python >= 2.4
 
@@ -73,9 +70,33 @@ mkdir -p $RPM_BUILD_ROOT/%{_initrddir}/
 rsync -av initscripts/ $RPM_BUILD_ROOT/%{_initrddir}/
 chmod 755 $RPM_BUILD_ROOT/%{_initrddir}/*
 
-install -D -m 644 logrotate/nm $RPM_BUILD_ROOT/%{_sysconfdir}/logrotate.d/nm
+install -d -m 755 $RPM_BUILD_ROOT/var/lib/nodemanager
+
+install -D -m 644 logrotate/nodemanager $RPM_BUILD_ROOT/%{_sysconfdir}/logrotate.d/nodemanager
 
+##########
 %post
+# tmp - handle file renamings; old names are from 2.0-8
+renamings="
+/var/lib/misc/bwmon.dat@/var/lib/nodemanager/bwmon.dat
+/root/sliver_mgr_db.pickle@/var/lib/nodemanager/nodemanager.pickle
+/var/log/getslivers.txt@/var/lib/nodemanager/getslivers.txt
+/var/log/nm@/var/log/nodemanager
+/var/log/nm.daemon@/var/log/nodemanager.daemon
+/var/run/nm.pid@/var/run/nodemanager.pid
+/tmp/sliver_mgr.api@/tmp/nodemanager.api
+/etc/logrotate.d/nm@/etc/logrotate.d/nodemanager
+"
+for renaming in $renamings; do
+  old=$(echo $renaming | cut -d@ -f1)
+  new=$(echo $renaming | cut -d@ -f2)
+  newdir=$(dirname $new)
+  if [ -e "$old" -a ! -e "$new" ] ; then
+      mkdir -p $newdir
+      mv -f $old $new
+  fi
+done
+#
 chkconfig --add conf_files
 chkconfig conf_files on
 chkconfig --add nm
@@ -87,7 +108,7 @@ if [ "$PL_BOOTCD" != "1" ] ; then
        service fuse-pl restart
 fi
 
-
+##########
 %preun
 # 0 = erase, 1 = upgrade
 if [ $1 -eq 0 ] ; then
@@ -107,7 +128,8 @@ rm -rf $RPM_BUILD_ROOT
 %{_datadir}/NodeManager/
 %{_bindir}/forward_api_calls
 %{_initrddir}/
-%{_sysconfdir}/logrotate.d/nm
+%{_sysconfdir}/logrotate.d/nodemanager
+/var/lib/
 
 %changelog
 * Fri May 14 2010 Talip Baris Metin <Talip-Baris.Metin@sophia.inria.fr> - NodeManager-2.0-8
diff --git a/api.py b/api.py
index ef279b8..a6cae30 100644 (file)
--- a/api.py
+++ b/api.py
@@ -39,7 +39,7 @@ except:
     logger.log("api:  Warning: admin slice prefix set to %s" %(PLC_SLICE_PREFIX), 2)
 
 API_SERVER_PORT = 812
-UNIX_ADDR = '/tmp/sliver_mgr.api'
+UNIX_ADDR = '/tmp/nodemanager.api'
 
 class APIRequestHandler(SimpleXMLRPCServer.SimpleXMLRPCRequestHandler):
     # overriding _dispatch to achieve this effect is officially deprecated,
@@ -68,12 +68,15 @@ class APIRequestHandler(SimpleXMLRPCServer.SimpleXMLRPCRequestHandler):
             ucred = self.request.getsockopt(socket.SOL_SOCKET, SO_PEERCRED, sizeof_struct_ucred)
             xid = struct.unpack('3i', ucred)[1]
             caller_name = pwd.getpwuid(xid)[0]
-            # Special case the genicw
+            # Special case : the sfa component manager
             if caller_name == PLC_SLICE_PREFIX+"_sfacm":
                 try: result = method(*args)
                 except Exception, err: raise xmlrpclib.Fault(104, 'Error in call: %s' %err)
             # Anyone can call these functions
-            elif method_name not in ('Help', 'Ticket', 'GetXIDs', 'GetSSHKeys'):
+            elif method_name in ('Help', 'Ticket', 'GetXIDs', 'GetSSHKeys'):
+                try: result = method(*args)
+                except Exception, err: raise xmlrpclib.Fault(104, 'Error in call: %s' %err)
+            else: # Execute anonymous call. 
                 # Authenticate the caller if not in the above fncts.
                 if method_name == "GetRecord":
                     target_name = caller_name
@@ -83,7 +86,7 @@ class APIRequestHandler(SimpleXMLRPCServer.SimpleXMLRPCRequestHandler):
                 # Gather target slice's object.
                 target_rec = database.db.get(target_name)
 
-                # only work on slivers or self.  Sannity check.
+                # only work on slivers or self. Sanity check.
                 if not (target_rec and target_rec['type'].startswith('sliver.')): 
                     raise xmlrpclib.Fault(102, \
                         'Invalid argument: the first argument must be a sliver name.')
@@ -94,9 +97,6 @@ class APIRequestHandler(SimpleXMLRPCServer.SimpleXMLRPCRequestHandler):
                     except Exception, err: raise xmlrpclib.Fault(104, 'Error in call: %s' %err)
                 else:
                     raise xmlrpclib.Fault(108, '%s: Permission denied.' % caller_name)
-            else: # Execute anonymous call. 
-                try: result = method(*args)
-                except Exception, err: raise xmlrpclib.Fault(104, 'Error in call: %s' %err)
             if result == None: result = 1
             return result
 
index 5b99a08..1e350c7 100644 (file)
@@ -33,8 +33,8 @@ import logger
 
 # TODO: These try/excepts are a hack to allow doc/DocBookLocal.py to 
 # import this file in order to extract the documentation from each 
-# exported function.  A better approach will involve more extensive code
-# splitting, I think.
+# exported function. 
+# A better approach will involve more extensive code splitting, I think.
 try: import database
 except: import logger as database
 try: import sliver_vs
@@ -100,7 +100,10 @@ def export_to_docbook(**kwargs):
 @export_to_api(0)
 def Help():
     """Get a list of functions currently supported by the Node Manager API"""
-    return ''.join([method.__doc__ + '\n' for method in api_method_dict.itervalues()])
+    names=api_method_dict.keys()
+    names.sort()
+    return ''.join(['**** ' + api_method_dict[name].__name__ + '\n' + api_method_dict[name].__doc__ + '\n' 
+                    for name in names])
 
 @export_to_docbook(roles=['self'], 
                    accepts=[Parameter(str, 'A ticket returned from GetSliceTicket()')], 
@@ -112,8 +115,7 @@ def Ticket(ticket):
     actions are performed on a delegated slice (such as creation),
     a controller slice must deliver a valid slice ticket to NM. 
     
-    This ticket is the value retured by PLC's GetSliceTicket() API call,
-    """
+    This ticket is the value retured by PLC's GetSliceTicket() API call."""
     try:
         data = ticket_module.verify(ticket)
         name = data['slivers'][0]['name']
@@ -129,8 +131,7 @@ def Ticket(ticket):
                    returns=Parameter(int, '1 if successful'))
 @export_to_api(1)
 def AdminTicket(ticket):
-    """Admin interface to create slivers based on ticket returned by GetSlivers().
-    """
+    """Admin interface to create slivers based on ticket returned by GetSlivers()."""
     try:
         data, = xmlrpclib.loads(ticket)[0]
         name = data['slivers'][0]['name']
@@ -257,17 +258,20 @@ def GetLoans(sliver_name):
     rec = sliver_name
     return rec.get('_loans', [])[:]
 
-def validate_loans(obj):
-    """Check that <obj> is a valid loan specification."""
-    def validate_loan(obj): return (type(obj)==list or type(obj)==tuple) and len(obj)==3 and type(obj[0])==str and type(obj[1])==str and obj[1] in database.LOANABLE_RESOURCES and type(obj[2])==int and obj[2]>=0
-    return type(obj)==list and False not in map(validate_loan, obj)
+def validate_loans(loans):
+    """Check that <obj> is a list of valid loan specifications."""
+    def validate_loan(loan): 
+        return (type(loan)==list or type(loan)==tuple) and len(loan)==3 \
+            and type(loan[0])==str and type(loan[1])==str and loan[1] in database.LOANABLE_RESOURCES and type(loan[2])==int and loan[2]>=0
+    return type(loans)==list and False not in [validate_loan(load) for loan in loans]
+
 
 @export_to_docbook(roles=['nm-controller', 'self'], 
-                accepts=[ Parameter(str, 'A sliver/slice name.'),
-                          [Mixed(Parameter(str, 'recipient slice name'),
-                           Parameter(str, 'resource name'),
-                           Parameter(int, 'resource amount'))] ],
-                returns=Parameter(int, '1 if successful'))
+                   accepts=[ Parameter(str, 'A sliver/slice name.'),
+                             [Mixed(Parameter(str, 'recipient slice name'),
+                                    Parameter(str, 'resource name'),
+                                    Parameter(int, 'resource amount'))], ],
+                   returns=Parameter(int, '1 if successful'))
 @export_to_api(2)
 def SetLoans(sliver_name, loans):
     """Overwrite the list of loans made by the specified sliver.
@@ -276,15 +280,15 @@ def SetLoans(sliver_name, loans):
     RSpec is handed out, but it will silently discard those loans that would
     put it over capacity.  This behavior may be replaced with error semantics
     in the future.  As well, there is currently no asynchronous notification
-    of loss of resources.
-    """
+    of loss of resources."""
     rec = sliver_name
-    if not validate_loans(loans): raise xmlrpclib.Fault(102, 'Invalid argument: the second argument must be a well-formed loan specification')
+    if not validate_loans(loans): 
+        raise xmlrpclib.Fault(102, 'Invalid argument: the second argument must be a well-formed loan specification')
     rec['_loans'] = loans
     database.db.sync()
 
 @export_to_docbook(roles=['nm-controller', 'self'], 
-                         returns=Parameter(dict, 'Record dictionary'))
+                   returns=Parameter(dict, 'Record dictionary'))
 @export_to_api(0)
 def GetRecord(sliver_name):
     """Return sliver record"""
index dad2a86..1d7081a 100644 (file)
--- a/bwmon.py
+++ b/bwmon.py
@@ -41,7 +41,7 @@ DEBUG = False
 # Set ENABLE to False to setup buckets, but not limit.
 ENABLE = True
 
-datafile = "/var/lib/misc/bwmon.dat"
+datafile = "/var/lib/nodemanager/bwmon.dat"
 
 try:
     sys.path.append("/etc/planetlab")
index 81c9c14..da5810c 100644 (file)
@@ -1,39 +1,64 @@
-# $Id$
-# $URL$
-
-from subprocess import PIPE, Popen
-from select import select
-# raise xmplrpclib.ProtocolError
-import xmlrpclib
-import signal
 import os
+import xmlrpclib
+import urllib
+import pycurl
+from cStringIO import StringIO
+
 import logger
 
-class Sopen(Popen):
-    def kill(self, signal = signal.SIGTERM):
-        os.kill(self.pid, signal)
+# a pycurl-based replacement for the previous version that relied on forking curl
 
 def retrieve(url, cacert=None, postdata=None, timeout=90):
-#    options = ('/usr/bin/curl', '--fail', '--silent')
-    options = ('/usr/bin/curl', '--fail', )
-    if cacert: options += ('--cacert', cacert)
-    if postdata: options += ('--data', '@-')
+    curl= pycurl.Curl()
+    curl.setopt(pycurl.URL,url)
+
+    # reproduce --fail from the previous version
+    curl.setopt(pycurl.FAILONERROR,1)
+    # don't want curl sending any signals
+    curl.setopt(pycurl.NOSIGNAL, 1)
+
+    # do not follow location when attempting to download a file
+    # curl.setopt(pycurl.FOLLOWLOCATION, 0)
+
+    # store result on the fly 
+    buffer=StringIO()
+    curl.setopt(pycurl.WRITEFUNCTION,buffer.write)
+           
+    # set timeout
     if timeout: 
-        options += ('--max-time', str(timeout))
-        options += ('--connect-timeout', str(timeout))
-    p = Sopen(options + (url,), stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True)
-    if postdata: p.stdin.write(postdata)
-    p.stdin.close()
-    sout, sin, serr = select([p.stdout,p.stderr],[],[], timeout)
-    if len(sout) == 0 and len(sin) == 0 and len(serr) == 0: 
-        logger.verbose("curlwrapper: timed out after %s" % timeout)
-        p.kill(signal.SIGKILL) 
-    data = p.stdout.read()
-    err = p.stderr.read()
-    rc = p.wait()
-    if rc != 0: 
-        # when this triggers, the error sometimes doesn't get printed
-        logger.log ("curlwrapper: retrieve, got stderr <%s>"%err)
-        raise xmlrpclib.ProtocolError(url, rc, err, postdata)
-    else: 
-        return data
+        curl.setopt(pycurl.CONNECTTIMEOUT, timeout)
+        curl.setopt(pycurl.TIMEOUT, timeout)
+
+    # set cacert
+    if cacert: 
+        curl.setopt(pycurl.CAINFO, cacert)
+        curl.setopt(pycurl.SSL_VERIFYPEER, 2)
+    else:
+        curl.setopt(pycurl.SSL_VERIFYPEER, 0)
+
+    # set postdata
+    if postdata:
+        if isinstance(postdata,dict):
+            postfields = urllib.urlencode(postdata)
+        else:
+           postfields=postdata
+        curl.setopt(pycurl.POSTFIELDS, postfields)
+
+    # go
+    try:
+        curl.perform()
+
+        errcode = curl.getinfo(pycurl.HTTP_CODE)
+        curl.close()
+
+        # check the code, return 1 if successfull
+       if errcode == 60:
+           raise xmlrpclib.ProtocolError (url,errcode, "SSL certificate validation failed", postdata)
+        elif errcode != 200:
+            raise xmlrpclib.ProtocolError (url,errcode, "http error %d"%errcode, postdata)
+
+    except pycurl.error, err:
+        errno, errstr = err
+        raise xmlrpclib.ProtocolError(url, errno, "curl error %d: '%s'\n" %(errno,errstr),postdata )
+
+    return buffer.getvalue()
index ab40824..c35042a 100644 (file)
@@ -26,10 +26,17 @@ import bwmon
 
 # We enforce minimum allocations to keep the clueless from hosing their slivers.
 # Disallow disk loans because there's currently no way to punish slivers over quota.
-MINIMUM_ALLOCATION = {'cpu_pct': 0, 'cpu_share': 1, 'net_min_rate': 0, 'net_max_rate': 8, 'net_i2_min_rate': 0, 'net_i2_max_rate': 8, 'net_share': 1}
+MINIMUM_ALLOCATION = {'cpu_pct': 0, 
+                      'cpu_share': 1, 
+                      'net_min_rate': 0, 
+                      'net_max_rate': 8, 
+                      'net_i2_min_rate': 0, 
+                      'net_i2_max_rate': 8, 
+                      'net_share': 1,
+                      }
 LOANABLE_RESOURCES = MINIMUM_ALLOCATION.keys()
 
-DB_FILE = '/root/sliver_mgr_db.pickle'
+DB_FILE = '/var/lib/nodemanager/nodemanager.pickle'
 
 
 # database object and associated lock
@@ -57,7 +64,13 @@ class Database(dict):
         self._min_timestamp = 0
 
     def _compute_effective_rspecs(self):
-        """Calculate the effects of loans and store the result in field _rspec.  At the moment, we allow slivers to loan only those resources that they have received directly from PLC.  In order to do the accounting, we store three different rspecs: field 'rspec', which is the resources given by PLC; field '_rspec', which is the actual amount of resources the sliver has after all loans; and variable resid_rspec, which is the amount of resources the sliver has after giving out loans but not receiving any."""
+        """Calculate the effects of loans and store the result in field _rspec. 
+At the moment, we allow slivers to loan only those resources that they have received directly from PLC.
+In order to do the accounting, we store three different rspecs: 
+ * field 'rspec', which is the resources given by PLC; 
+ * field '_rspec', which is the actual amount of resources the sliver has after all loans; 
+ * and variable resid_rspec, which is the amount of resources the sliver 
+   has after giving out loans but not receiving any."""
         slivers = {}
         for name, rec in self.iteritems():
             if 'rspec' in rec:
@@ -66,14 +79,17 @@ class Database(dict):
         for rec in slivers.itervalues():
             eff_rspec = rec['_rspec']
             resid_rspec = rec['rspec'].copy()
-            for target, resname, amt in rec.get('_loans', []):
-                if target in slivers and amt <= resid_rspec[resname] - MINIMUM_ALLOCATION[resname]:
-                    eff_rspec[resname] -= amt
-                    resid_rspec[resname] -= amt
-                    slivers[target]['_rspec'][resname] += amt
+            for target, resource_name, amount in rec.get('_loans', []):
+                if target in slivers and amount <= resid_rspec[resource_name] - MINIMUM_ALLOCATION[resource_name]:
+                    eff_rspec[resource_name] -= amount
+                    resid_rspec[resource_name] -= amount
+                    slivers[target]['_rspec'][resource_name] += amount
 
     def deliver_record(self, rec):
-        """A record is simply a dictionary with 'name' and 'timestamp' keys.  We keep some persistent private data in the records under keys that start with '_'; thus record updates should not displace such keys."""
+        """A record is simply a dictionary with 'name' and 'timestamp'
+keys. We keep some persistent private data in the records under keys
+that start with '_'; thus record updates should not displace such
+keys."""
         if rec['timestamp'] < self._min_timestamp: return
         name = rec['name']
         old_rec = self.get(name)
@@ -84,13 +100,18 @@ class Database(dict):
             old_rec.update(rec)
 
     def set_min_timestamp(self, ts):
-        """The ._min_timestamp member is the timestamp on the last comprehensive update.  We use it to determine if a record is stale.  This method should be called whenever new GetSlivers() data comes in."""
+        """The ._min_timestamp member is the timestamp on the last comprehensive update.  
+We use it to determine if a record is stale.  
+This method should be called whenever new GetSlivers() data comes in."""
         self._min_timestamp = ts
         for name, rec in self.items():
             if rec['timestamp'] < ts: del self[name]
 
     def sync(self):
-        """Synchronize reality with the database contents.  This method does a lot of things, and it's currently called after every single batch of database changes (a GetSlivers(), a loan, a record).  It may be necessary in the future to do something smarter."""
+        """Synchronize reality with the database contents.  This
+method does a lot of things, and it's currently called after every
+single batch of database changes (a GetSlivers(), a loan, a record).
+It may be necessary in the future to do something smarter."""
 
         # delete expired records
         now = time.time()
@@ -137,7 +158,9 @@ class Database(dict):
 
 
 def start():
-    """The database dumper daemon.  When it starts up, it populates the database with the last dumped database.  It proceeds to handle dump requests forever."""
+    """The database dumper daemon.
+When it starts up, it populates the database with the last dumped database.
+It proceeds to handle dump requests forever."""
     def run():
         global dump_requested
         while True:
index 330bd3e..98fc01d 100644 (file)
@@ -18,7 +18,7 @@
  */
 
 static const int TIMEOUT_SECS = 120;
-const char *API_addr = "/tmp/sliver_mgr.api";
+const char *API_addr = "/tmp/nodemanager.api";
 
 static const char *Header =
   "POST / HTTP/1.0\r\n"
index c4f6ce6..b56c0e1 100644 (file)
--- a/logger.py
+++ b/logger.py
@@ -9,8 +9,8 @@ import traceback
 import subprocess
 import select
 
-LOG_FILE = '/var/log/nm'
-LOG_SLIVERS = '/var/log/getslivers.txt'
+LOG_FILE    = '/var/log/nodemanager'
+LOG_SLIVERS = '/var/lib/nodemanager/getslivers.txt'
 
 # Thierry - trying to debug this for 4.2
 # basically define 3 levels
similarity index 78%
rename from logrotate/nm
rename to logrotate/nodemanager
index c685711..0ff3627 100644 (file)
@@ -1,4 +1,4 @@
-/var/log/nm {
+/var/log/nodemanager {
     copytruncate
     compress
     daily
diff --git a/nm.py b/nm.py
index f421769..30ee0b7 100755 (executable)
--- a/nm.py
+++ b/nm.py
@@ -188,10 +188,12 @@ def run():
         logger.log("nm: Checking Auth.")
         while plc.check_authentication() != True:
             try:
+#                import pdb
+#               pdb.set_trace()
                 plc.update_session()
                 logger.log("nm: Authentication Failure. Retrying")
-            except:
-                logger.log("nm: Retry Failed. Waiting")
+            except Exception,e:
+                logger.log("nm: Retry Failed. (%r); Waiting.."%e)
             time.sleep(iperiod)
         logger.log("nm: Authentication Succeeded!")
 
index 6ed3cac..ca411df 100644 (file)
--- a/plcapi.py
+++ b/plcapi.py
@@ -20,7 +20,7 @@ class PLCAPI:
     session => SessionAuth
 
     To authenticate using the Boot Manager authentication method, or
-    the new session-based method.
+    the new session-based method, respectively.
     """
 
     def __init__(self, uri, cacert, auth, timeout = 90, **kwds):
index 4186225..878579d 100644 (file)
@@ -57,7 +57,7 @@ class Sliver_VS(accounts.Account, vserver.VServer):
         logger.verbose ('sliver_vs: %s init'%name)
         try:
             logger.log("sliver_vs: %s: first chance..."%name)
-            vserver.VServer.__init__(self, name,logfile='/var/log/nm')
+            vserver.VServer.__init__(self, name,logfile='/var/log/nodemanager')
         except Exception, err:
             if not isinstance(err, vserver.NoSuchVServer):
                 # Probably a bad vserver or vserver configuration file
@@ -66,7 +66,7 @@ class Sliver_VS(accounts.Account, vserver.VServer):
                 self.destroy(name)
             self.create(name, rec['vref'])
             logger.log("sliver_vs: %s: second chance..."%name)
-            vserver.VServer.__init__(self, name,logfile='/var/log/nm')
+            vserver.VServer.__init__(self, name,logfile='/var/log/nodemanager')
 
         self.keys = ''
         self.rspec = {}
index 0292cfb..aa24b88 100644 (file)
--- a/ticket.py
+++ b/ticket.py
@@ -12,6 +12,10 @@ from xmlrpclib import dumps, loads
 
 GPG = '/usr/bin/gpg'
 
+def _popen_gpg(*args):
+    """Return a Popen object to GPG."""
+    return Popen((GPG, '--batch', '--no-tty') + args, 
+                 stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True)
 
 def sign(data):
     """Return <data> signed with the default GPG key."""
@@ -33,11 +37,9 @@ def verify(signed_msg):
     msg = p.stdout.read()
     p.stdout.close()
     p.stderr.close()
-    if p.wait(): return None  # verification failed
+    if p.wait(): 
+        return None  # verification failed
     else:
         data, = loads(msg)[0]
         return data
 
-def _popen_gpg(*args):
-    """Return a Popen object to GPG."""
-    return Popen((GPG, '--batch', '--no-tty') + args, stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True)
index 80685de..07946bf 100644 (file)
--- a/tools.py
+++ b/tools.py
@@ -13,7 +13,7 @@ import subprocess
 
 import logger
 
-PID_FILE = '/var/run/nm.pid'
+PID_FILE = '/var/run/nodemanager.pid'
 
 ####################
 def get_default_if():
@@ -64,7 +64,7 @@ def daemon():
     devnull = os.open(os.devnull, os.O_RDWR)
     os.dup2(devnull, 0)
     # xxx fixme - this is just to make sure that nothing gets stupidly lost - should use devnull
-    crashlog = os.open('/var/log/nm.daemon', os.O_RDWR | os.O_APPEND | os.O_CREAT, 0644)
+    crashlog = os.open('/var/log/nodemanager.daemon', os.O_RDWR | os.O_APPEND | os.O_CREAT, 0644)
     os.dup2(crashlog, 1)
     os.dup2(crashlog, 2)