root/trunk/bcfg2/src/lib/Client/Tools/launchd.py

Revision 4923, 4.2 kB (checked in by solj, 2 months ago)

Pylint formatting fixes for client tool drivers

  • Property svn:keywords set to Revision
Line 
1 '''launchd support for Bcfg2'''
2 __revision__ = '$Revision$'
3
4 import os
5 import Bcfg2.Client.Tools
6
7 class launchd(Bcfg2.Client.Tools.Tool):
8     '''Support for Mac OS X Launchd Services'''
9     __handles__ = [('Service', 'launchd')]
10     __execs__ = ['/bin/launchctl', '/usr/bin/defaults']
11     __name__ = 'launchd'
12     __req__ = {'Service':['name', 'status']}
13
14     '''
15     currently requires the path to the plist to load/unload,
16     and Name is acually a reverse-fqdn (or the label)
17     '''
18     def FindPlist(self, entry):
19         '''Locate plist file that provides given reverse-fqdn name
20         /Library/LaunchAgents          Per-user agents provided by the administrator.
21         /Library/LaunchDaemons         System wide daemons provided by the administrator.
22         /System/Library/LaunchAgents   Mac OS X Per-user agents.
23         /System/Library/LaunchDaemons  Mac OS X System wide daemons.'''
24         plistLocations = ["/Library/LaunchDaemons", "/System/Library/LaunchDaemons"]
25         plistMapping = {}
26         for directory in plistLocations:
27             for daemon in os.listdir(directory):
28                 try:
29                     if daemon.endswith(".plist"):
30                         d = daemon[:(len(daemon)-6)]
31                     else:
32                         d = daemon
33                     plistMapping[self.cmd.run( \
34                         "defaults read %s/%s Label" % (directory, d))[1][0]] = \
35                         "%s/%s"%(directory, daemon)
36                 except KeyError: #perhaps this could be more robust
37                     pass
38         try:
39             return plistMapping[entry.get('name')]
40         except KeyError:
41             return None
42
43
44     def VerifyService(self, entry, _):
45         '''Verify Launchd Service Entry'''
46         try:
47             services = self.cmd.run("/bin/launchctl list")[1]
48         except IndexError:#happens when no services are running (should be never)
49             services = []
50         if entry.get('name') in services:#doesn't check if non-spawning services are Started
51             return entry.get('status') == 'on'
52         else:
53             self.logger.debug("Didn't find service Loaded (launchd running under same user as bcfg)")
54             return entry.get('status') == 'off'
55
56         try: #Perhaps add the "-w" flag to load and unload to modify the file itself!
57             self.cmd.run("/bin/launchctl load -w %s" % self.FindPlist(entry))
58         except IndexError:
59             return 'on'
60         return False
61
62
63     def InstallService(self, entry):
64         '''Enable or Disable launchd Item'''
65         if entry.get('status') == 'on':
66             cmdrc = self.cmd.run("/bin/launchctl load -w %s" % self.FindPlist(entry))[0]
67         else:
68             cmdrc = self.cmd.run("/bin/launchctl unload -w %s" % self.FindPlist(entry))[0]
69         return cmdrc == 0
70
71     def Remove(self, svcs):
72         '''Remove Extra launchd entries'''
73         pass
74        
75
76
77     def FindExtra(self):
78         '''Find Extra launchd Services'''
79         try:
80             allsrv =  self.cmd.run("/bin/launchctl list")[1]
81         except IndexError:
82             allsrv = []
83
84         [allsrv.remove(svc) for svc in [entry.get("name") for entry
85                                         in self.getSupportedEntries()] if svc in allsrv]
86         return [Bcfg2.Client.XML.Element("Service", type='launchd', name=name, status='on') for name in allsrv]
87
88     def BundleUpdated(self, bundle, states):
89         '''Reload launchd plist'''
90         for entry in [entry for entry in bundle if self.handlesEntry(entry)]:
91             if not self.canInstall(entry):
92                 self.logger.error("Insufficient information to restart service %s" % (entry.get('name')))
93             else:
94                 if entry.get('status') == 'on' and self.FindPlist(entry):
95                     self.logger.info("Reloading launchd  service %s" % (entry.get("name")))
96                     #stop?
97                     self.cmd.run("/bin/launchctl unload -w %s" % (self.FindPlist(entry)))#what if it disappeared? how do we stop services that are currently running but the plist disappeared?!
98                     self.cmd.run("/bin/launchctl load -w %s" % (self.FindPlist(entry)))
99                 else:
100                     #only if necessary....
101                     self.cmd.run("/bin/launchctl unload -w %s" % (self.FindPlist(entry)))
102
Note: See TracBrowser for help on using the browser.