Statistics
| Branch: | Tag: | Revision:

root / daemons / ganeti-confd @ 05f1ebf3

History | View | Annotate | Download (11.5 kB)

1 b84cb9a0 Guido Trotter
#!/usr/bin/python
2 b84cb9a0 Guido Trotter
#
3 b84cb9a0 Guido Trotter
4 b84cb9a0 Guido Trotter
# Copyright (C) 2009, Google Inc.
5 b84cb9a0 Guido Trotter
#
6 b84cb9a0 Guido Trotter
# This program is free software; you can redistribute it and/or modify
7 b84cb9a0 Guido Trotter
# it under the terms of the GNU General Public License as published by
8 b84cb9a0 Guido Trotter
# the Free Software Foundation; either version 2 of the License, or
9 b84cb9a0 Guido Trotter
# (at your option) any later version.
10 b84cb9a0 Guido Trotter
#
11 b84cb9a0 Guido Trotter
# This program is distributed in the hope that it will be useful, but
12 b84cb9a0 Guido Trotter
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 b84cb9a0 Guido Trotter
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 b84cb9a0 Guido Trotter
# General Public License for more details.
15 b84cb9a0 Guido Trotter
#
16 b84cb9a0 Guido Trotter
# You should have received a copy of the GNU General Public License
17 b84cb9a0 Guido Trotter
# along with this program; if not, write to the Free Software
18 b84cb9a0 Guido Trotter
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 b84cb9a0 Guido Trotter
# 02110-1301, USA.
20 b84cb9a0 Guido Trotter
21 b84cb9a0 Guido Trotter
22 b84cb9a0 Guido Trotter
"""Ganeti configuration daemon
23 b84cb9a0 Guido Trotter
24 b84cb9a0 Guido Trotter
Ganeti-confd is a daemon to query master candidates for configuration values.
25 b84cb9a0 Guido Trotter
It uses UDP+HMAC for authentication with a global cluster key.
26 b84cb9a0 Guido Trotter
27 b84cb9a0 Guido Trotter
"""
28 b84cb9a0 Guido Trotter
29 b84cb9a0 Guido Trotter
import os
30 b84cb9a0 Guido Trotter
import sys
31 b84cb9a0 Guido Trotter
import logging
32 b84cb9a0 Guido Trotter
import asyncore
33 b84cb9a0 Guido Trotter
import socket
34 b84cb9a0 Guido Trotter
import pyinotify
35 e2be81cf Guido Trotter
import time
36 b84cb9a0 Guido Trotter
37 b84cb9a0 Guido Trotter
from optparse import OptionParser
38 b84cb9a0 Guido Trotter
39 b84cb9a0 Guido Trotter
from ganeti import constants
40 b84cb9a0 Guido Trotter
from ganeti import errors
41 b84cb9a0 Guido Trotter
from ganeti import daemon
42 b84cb9a0 Guido Trotter
from ganeti import ssconf
43 b84cb9a0 Guido Trotter
from ganeti.asyncnotifier import AsyncNotifier
44 b84cb9a0 Guido Trotter
from ganeti.confd.server import ConfdProcessor
45 b84cb9a0 Guido Trotter
46 b84cb9a0 Guido Trotter
47 b84cb9a0 Guido Trotter
class ConfdAsyncUDPServer(asyncore.dispatcher):
48 b84cb9a0 Guido Trotter
  """The confd udp server, suitable for use with asyncore.
49 b84cb9a0 Guido Trotter
50 b84cb9a0 Guido Trotter
  """
51 b84cb9a0 Guido Trotter
  def __init__(self, bind_address, port, processor):
52 b84cb9a0 Guido Trotter
    """Constructor for ConfdAsyncUDPServer
53 b84cb9a0 Guido Trotter
54 b84cb9a0 Guido Trotter
    @type bind_address: string
55 b84cb9a0 Guido Trotter
    @param bind_address: socket bind address ('' for all)
56 b84cb9a0 Guido Trotter
    @type port: int
57 b84cb9a0 Guido Trotter
    @param port: udp port
58 b84cb9a0 Guido Trotter
    @type processor: L{confd.server.ConfdProcessor}
59 b84cb9a0 Guido Trotter
    @param reader: ConfigReader to use to access the config
60 b84cb9a0 Guido Trotter
61 b84cb9a0 Guido Trotter
    """
62 b84cb9a0 Guido Trotter
    asyncore.dispatcher.__init__(self)
63 b84cb9a0 Guido Trotter
    self.bind_address = bind_address
64 b84cb9a0 Guido Trotter
    self.port = port
65 b84cb9a0 Guido Trotter
    self.processor = processor
66 b84cb9a0 Guido Trotter
    self.create_socket(socket.AF_INET, socket.SOCK_DGRAM)
67 b84cb9a0 Guido Trotter
    self.bind((bind_address, port))
68 b84cb9a0 Guido Trotter
    logging.debug("listening on ('%s':%d)" % (bind_address, port))
69 b84cb9a0 Guido Trotter
70 b84cb9a0 Guido Trotter
  # this method is overriding an asyncore.dispatcher method
71 b84cb9a0 Guido Trotter
  def handle_connect(self):
72 b84cb9a0 Guido Trotter
    # Python thinks that the first udp message from a source qualifies as a
73 b84cb9a0 Guido Trotter
    # "connect" and further ones are part of the same connection. We beg to
74 b84cb9a0 Guido Trotter
    # differ and treat all messages equally.
75 b84cb9a0 Guido Trotter
    pass
76 b84cb9a0 Guido Trotter
77 b84cb9a0 Guido Trotter
  # this method is overriding an asyncore.dispatcher method
78 b84cb9a0 Guido Trotter
  def handle_read(self):
79 b84cb9a0 Guido Trotter
    try:
80 b84cb9a0 Guido Trotter
      payload_in, address = self.recvfrom(4096)
81 b84cb9a0 Guido Trotter
      ip, port = address
82 b84cb9a0 Guido Trotter
      payload_out =  self.processor.ExecQuery(payload_in, ip, port)
83 b84cb9a0 Guido Trotter
      if payload_out is not None:
84 b84cb9a0 Guido Trotter
        self.sendto(payload_out, 0, (ip, port))
85 b84cb9a0 Guido Trotter
    except:
86 b84cb9a0 Guido Trotter
      # we need to catch any exception here, log it, but proceed, because even
87 b84cb9a0 Guido Trotter
      # if we failed handling a single request, we still want the confd to
88 b84cb9a0 Guido Trotter
      # continue working.
89 b84cb9a0 Guido Trotter
      logging.error("Unexpected exception", exc_info=True)
90 b84cb9a0 Guido Trotter
91 b84cb9a0 Guido Trotter
  # this method is overriding an asyncore.dispatcher method
92 b84cb9a0 Guido Trotter
  def writable(self):
93 b84cb9a0 Guido Trotter
    # No need to check if we can write to the UDP socket
94 b84cb9a0 Guido Trotter
    return False
95 b84cb9a0 Guido Trotter
96 b84cb9a0 Guido Trotter
97 b84cb9a0 Guido Trotter
class ConfdInotifyEventHandler(pyinotify.ProcessEvent):
98 b84cb9a0 Guido Trotter
99 4afe249b Guido Trotter
  def __init__(self, watch_manager, callback,
100 b84cb9a0 Guido Trotter
               file=constants.CLUSTER_CONF_FILE):
101 b84cb9a0 Guido Trotter
    """Constructor for ConfdInotifyEventHandler
102 b84cb9a0 Guido Trotter
103 b84cb9a0 Guido Trotter
    @type watch_manager: L{pyinotify.WatchManager}
104 b84cb9a0 Guido Trotter
    @param watch_manager: ganeti-confd inotify watch manager
105 4afe249b Guido Trotter
    @type callback: function accepting a boolean
106 4afe249b Guido Trotter
    @param callback: function to call when an inotify event happens
107 b84cb9a0 Guido Trotter
    @type file: string
108 b84cb9a0 Guido Trotter
    @param file: config file to watch
109 b84cb9a0 Guido Trotter
110 b84cb9a0 Guido Trotter
    """
111 b84cb9a0 Guido Trotter
    # no need to call the parent's constructor
112 b84cb9a0 Guido Trotter
    self.watch_manager = watch_manager
113 4afe249b Guido Trotter
    self.callback = callback
114 b84cb9a0 Guido Trotter
    self.mask = pyinotify.EventsCodes.IN_IGNORED | \
115 b84cb9a0 Guido Trotter
                pyinotify.EventsCodes.IN_MODIFY
116 b84cb9a0 Guido Trotter
    self.file = file
117 46c9b31d Guido Trotter
    self.watch_handle = None
118 46c9b31d Guido Trotter
    self.enable()
119 b84cb9a0 Guido Trotter
120 46c9b31d Guido Trotter
  def enable(self):
121 46c9b31d Guido Trotter
    """Watch the given file
122 b84cb9a0 Guido Trotter
123 b84cb9a0 Guido Trotter
    """
124 46c9b31d Guido Trotter
    if self.watch_handle is None:
125 46c9b31d Guido Trotter
      result = self.watch_manager.add_watch(self.file, self.mask)
126 46c9b31d Guido Trotter
      if not self.file in result or result[self.file] <= 0:
127 ef4ca33b Guido Trotter
        raise errors.InotifyError("Could not add inotify watcher")
128 46c9b31d Guido Trotter
      else:
129 46c9b31d Guido Trotter
        self.watch_handle = result[self.file]
130 46c9b31d Guido Trotter
131 46c9b31d Guido Trotter
  def disable(self):
132 46c9b31d Guido Trotter
    """Stop watching the given file
133 46c9b31d Guido Trotter
134 46c9b31d Guido Trotter
    """
135 46c9b31d Guido Trotter
    if self.watch_handle is not None:
136 46c9b31d Guido Trotter
      result = self.watch_manager.rm_watch(self.watch_handle)
137 46c9b31d Guido Trotter
      if result[self.watch_handle]:
138 46c9b31d Guido Trotter
        self.watch_handle = None
139 b84cb9a0 Guido Trotter
140 b84cb9a0 Guido Trotter
  def process_IN_IGNORED(self, event):
141 b84cb9a0 Guido Trotter
    # Due to the fact that we monitor just for the cluster config file (rather
142 b84cb9a0 Guido Trotter
    # than for the whole data dir) when the file is replaced with another one
143 b84cb9a0 Guido Trotter
    # (which is what happens normally in ganeti) we're going to receive an
144 b84cb9a0 Guido Trotter
    # IN_IGNORED event from inotify, because of the file removal (which is
145 b84cb9a0 Guido Trotter
    # contextual with the replacement). In such a case we need to create
146 b84cb9a0 Guido Trotter
    # another watcher for the "new" file.
147 b84cb9a0 Guido Trotter
    logging.debug("Received 'ignored' inotify event for %s" % event.path)
148 46c9b31d Guido Trotter
    self.watch_handle = None
149 b84cb9a0 Guido Trotter
150 b84cb9a0 Guido Trotter
    try:
151 b84cb9a0 Guido Trotter
      # Since the kernel believes the file we were interested in is gone, it's
152 b84cb9a0 Guido Trotter
      # not going to notify us of any other events, until we set up, here, the
153 b84cb9a0 Guido Trotter
      # new watch. This is not a race condition, though, since we're anyway
154 b84cb9a0 Guido Trotter
      # going to realod the file after setting up the new watch.
155 4afe249b Guido Trotter
      self.callback(False)
156 b84cb9a0 Guido Trotter
    except errors.ConfdFatalError, err:
157 b84cb9a0 Guido Trotter
      logging.critical("Critical error, shutting down: %s" % err)
158 b84cb9a0 Guido Trotter
      sys.exit(constants.EXIT_FAILURE)
159 b84cb9a0 Guido Trotter
    except:
160 b84cb9a0 Guido Trotter
      # we need to catch any exception here, log it, but proceed, because even
161 b84cb9a0 Guido Trotter
      # if we failed handling a single request, we still want the confd to
162 b84cb9a0 Guido Trotter
      # continue working.
163 b84cb9a0 Guido Trotter
      logging.error("Unexpected exception", exc_info=True)
164 b84cb9a0 Guido Trotter
165 b84cb9a0 Guido Trotter
  def process_IN_MODIFY(self, event):
166 b84cb9a0 Guido Trotter
    # This gets called when the config file is modified. Note that this doesn't
167 b84cb9a0 Guido Trotter
    # usually happen in Ganeti, as the config file is normally replaced by a
168 b84cb9a0 Guido Trotter
    # new one, at filesystem level, rather than actually modified (see
169 b84cb9a0 Guido Trotter
    # utils.WriteFile)
170 b84cb9a0 Guido Trotter
    logging.debug("Received 'modify' inotify event for %s" % event.path)
171 b84cb9a0 Guido Trotter
172 b84cb9a0 Guido Trotter
    try:
173 4afe249b Guido Trotter
      self.callback(True)
174 b84cb9a0 Guido Trotter
    except errors.ConfdFatalError, err:
175 b84cb9a0 Guido Trotter
      logging.critical("Critical error, shutting down: %s" % err)
176 b84cb9a0 Guido Trotter
      sys.exit(constants.EXIT_FAILURE)
177 b84cb9a0 Guido Trotter
    except:
178 b84cb9a0 Guido Trotter
      # we need to catch any exception here, log it, but proceed, because even
179 b84cb9a0 Guido Trotter
      # if we failed handling a single request, we still want the confd to
180 b84cb9a0 Guido Trotter
      # continue working.
181 b84cb9a0 Guido Trotter
      logging.error("Unexpected exception", exc_info=True)
182 b84cb9a0 Guido Trotter
183 b84cb9a0 Guido Trotter
  def process_default(self, event):
184 b84cb9a0 Guido Trotter
    logging.error("Received unhandled inotify event: %s" % event)
185 b84cb9a0 Guido Trotter
186 b84cb9a0 Guido Trotter
187 562bee4d Guido Trotter
class ConfdConfigurationReloader(object):
188 562bee4d Guido Trotter
  """Logic to control when to reload the ganeti configuration
189 562bee4d Guido Trotter
190 562bee4d Guido Trotter
  This class is able to alter between inotify and polling, to rate-limit the
191 562bee4d Guido Trotter
  number of reloads. When using inotify it also supports a fallback timed
192 562bee4d Guido Trotter
  check, to verify that the reload hasn't failed.
193 562bee4d Guido Trotter
194 562bee4d Guido Trotter
  """
195 05f1ebf3 Guido Trotter
  def __init__(self, processor, mainloop):
196 562bee4d Guido Trotter
    """Constructor for ConfdConfigurationReloader
197 562bee4d Guido Trotter
198 05f1ebf3 Guido Trotter
    @type processor: L{confd.server.ConfdProcessor}
199 05f1ebf3 Guido Trotter
    @param processor: ganeti-confd ConfdProcessor
200 e2be81cf Guido Trotter
    @type mainloop: L{daemon.Mainloop}
201 e2be81cf Guido Trotter
    @param mainloop: ganeti-confd mainloop
202 562bee4d Guido Trotter
203 562bee4d Guido Trotter
    """
204 05f1ebf3 Guido Trotter
    self.processor = processor
205 e2be81cf Guido Trotter
    self.mainloop = mainloop
206 e2be81cf Guido Trotter
207 e2be81cf Guido Trotter
    self.polling = False
208 e2be81cf Guido Trotter
    self.last_notification = 0
209 562bee4d Guido Trotter
210 562bee4d Guido Trotter
    # Asyncronous inotify handler for config changes
211 562bee4d Guido Trotter
    self.wm = pyinotify.WatchManager()
212 4afe249b Guido Trotter
    self.inotify_handler = ConfdInotifyEventHandler(self.wm, self.OnInotify)
213 4afe249b Guido Trotter
    self.notifier = AsyncNotifier(self.wm, self.inotify_handler)
214 4afe249b Guido Trotter
215 e2be81cf Guido Trotter
    self.timer_handle = None
216 e2be81cf Guido Trotter
    self._EnableTimer()
217 e2be81cf Guido Trotter
218 4afe249b Guido Trotter
  def OnInotify(self, notifier_enabled):
219 4afe249b Guido Trotter
    """Receive an inotify notification.
220 4afe249b Guido Trotter
221 4afe249b Guido Trotter
    @type notifier_enabled: boolean
222 4afe249b Guido Trotter
    @param notifier_enabled: whether the notifier is still enabled
223 4afe249b Guido Trotter
224 4afe249b Guido Trotter
    """
225 e2be81cf Guido Trotter
    current_time = time.time()
226 e2be81cf Guido Trotter
    time_delta = current_time - self.last_notification
227 e2be81cf Guido Trotter
    self.last_notification = current_time
228 e2be81cf Guido Trotter
229 e2be81cf Guido Trotter
    if time_delta < constants.CONFD_CONFIG_RELOAD_RATELIMIT:
230 e2be81cf Guido Trotter
      logging.debug("Moving from inotify mode to polling mode")
231 e2be81cf Guido Trotter
      self.polling = True
232 e2be81cf Guido Trotter
      if notifier_enabled:
233 176d3122 Guido Trotter
        self.inotify_handler.disable()
234 e2be81cf Guido Trotter
235 e2be81cf Guido Trotter
    if not self.polling and not notifier_enabled:
236 ef4ca33b Guido Trotter
      try:
237 ef4ca33b Guido Trotter
        self.inotify_handler.enable()
238 ef4ca33b Guido Trotter
      except errors.InotifyError:
239 ef4ca33b Guido Trotter
        raise errors.ConfdFatalError(err)
240 4afe249b Guido Trotter
241 4afe249b Guido Trotter
    try:
242 05f1ebf3 Guido Trotter
      reloaded = self.processor.reader.Reload()
243 4afe249b Guido Trotter
      if reloaded:
244 4afe249b Guido Trotter
        logging.info("Reloaded ganeti config")
245 4afe249b Guido Trotter
      else:
246 4afe249b Guido Trotter
        logging.debug("Skipped double config reload")
247 4afe249b Guido Trotter
    except errors.ConfigurationError:
248 4afe249b Guido Trotter
      # transform a ConfigurationError in a fatal error, that will cause confd
249 4afe249b Guido Trotter
      # to quit.
250 4afe249b Guido Trotter
      raise errors.ConfdFatalError(err)
251 4afe249b Guido Trotter
252 e2be81cf Guido Trotter
    # Reset the timer. If we're polling it will go to the polling rate, if
253 e2be81cf Guido Trotter
    # we're not it will delay it again to its base safe timeout.
254 e2be81cf Guido Trotter
    self._DisableTimer()
255 e2be81cf Guido Trotter
    self._EnableTimer()
256 e2be81cf Guido Trotter
257 e2be81cf Guido Trotter
  def _DisableTimer(self):
258 e2be81cf Guido Trotter
    if self.timer_handle is not None:
259 e2be81cf Guido Trotter
      self.mainloop.scheduler.cancel(self.timer_handle)
260 e2be81cf Guido Trotter
      self.timer_handle = None
261 e2be81cf Guido Trotter
262 e2be81cf Guido Trotter
  def _EnableTimer(self):
263 e2be81cf Guido Trotter
    if self.polling:
264 e2be81cf Guido Trotter
      timeout = constants.CONFD_CONFIG_RELOAD_RATELIMIT
265 e2be81cf Guido Trotter
    else:
266 e2be81cf Guido Trotter
      timeout = constants.CONFD_CONFIG_RELOAD_TIMEOUT
267 e2be81cf Guido Trotter
268 e2be81cf Guido Trotter
    if self.timer_handle is None:
269 e2be81cf Guido Trotter
      self.timer_handle = self.mainloop.scheduler.enter(
270 e2be81cf Guido Trotter
        timeout, 1, self.OnTimer, [])
271 e2be81cf Guido Trotter
272 e2be81cf Guido Trotter
  def OnTimer(self):
273 e2be81cf Guido Trotter
    """Function called when the timer fires
274 e2be81cf Guido Trotter
275 e2be81cf Guido Trotter
    """
276 e2be81cf Guido Trotter
    self.timer_handle = None
277 e2be81cf Guido Trotter
    try:
278 05f1ebf3 Guido Trotter
      reloaded = self.processor.reader.Reload()
279 e2be81cf Guido Trotter
    except errors.ConfigurationError:
280 e2be81cf Guido Trotter
      # transform a ConfigurationError in a fatal error, that will cause confd
281 e2be81cf Guido Trotter
      # to quit.
282 e2be81cf Guido Trotter
      raise errors.ConfdFatalError(err)
283 e2be81cf Guido Trotter
284 e2be81cf Guido Trotter
    if self.polling and reloaded:
285 e2be81cf Guido Trotter
      logging.info("Reloaded ganeti config")
286 e2be81cf Guido Trotter
    elif reloaded:
287 e2be81cf Guido Trotter
      # We have reloaded the config files, but received no inotify event.  If
288 e2be81cf Guido Trotter
      # an event is pending though, we just happen to have timed out before
289 e2be81cf Guido Trotter
      # receiving it, so this is not a problem, and we shouldn't alert
290 e2be81cf Guido Trotter
      if not self.notifier.check_events():
291 e2be81cf Guido Trotter
        logging.warning("Config file reload at timeout (inotify failure)")
292 e2be81cf Guido Trotter
    elif self.polling:
293 e2be81cf Guido Trotter
      # We're polling, but we haven't reloaded the config:
294 e2be81cf Guido Trotter
      # Going back to inotify mode
295 e2be81cf Guido Trotter
      logging.debug("Moving from polling mode to inotify mode")
296 e2be81cf Guido Trotter
      self.polling = False
297 e2be81cf Guido Trotter
      self.inotify_handler.enable()
298 e2be81cf Guido Trotter
    else:
299 e2be81cf Guido Trotter
      logging.debug("Performed configuration check")
300 e2be81cf Guido Trotter
301 e2be81cf Guido Trotter
    self._EnableTimer()
302 562bee4d Guido Trotter
303 562bee4d Guido Trotter
304 6c948699 Michael Hanselmann
def CheckConfd(options, args):
305 6c948699 Michael Hanselmann
  """Initial checks whether to run exit with a failure.
306 b84cb9a0 Guido Trotter
307 b84cb9a0 Guido Trotter
  """
308 b84cb9a0 Guido Trotter
  # TODO: collapse HMAC daemons handling in daemons GenericMain, when we'll
309 b84cb9a0 Guido Trotter
  # have more than one.
310 b84cb9a0 Guido Trotter
  if not os.path.isfile(constants.HMAC_CLUSTER_KEY):
311 b84cb9a0 Guido Trotter
    print >> sys.stderr, "Need HMAC key %s to run" % constants.HMAC_CLUSTER_KEY
312 b84cb9a0 Guido Trotter
    sys.exit(constants.EXIT_FAILURE)
313 b84cb9a0 Guido Trotter
314 b84cb9a0 Guido Trotter
  ssconf.CheckMasterCandidate(options.debug)
315 b84cb9a0 Guido Trotter
316 b84cb9a0 Guido Trotter
317 6c948699 Michael Hanselmann
def ExecConfd(options, args):
318 6c948699 Michael Hanselmann
  """Main confd function, executed with PID file held
319 b84cb9a0 Guido Trotter
320 b84cb9a0 Guido Trotter
  """
321 f91c7223 Guido Trotter
  mainloop = daemon.Mainloop()
322 f91c7223 Guido Trotter
323 b84cb9a0 Guido Trotter
  # Asyncronous confd UDP server
324 05f1ebf3 Guido Trotter
  processor = ConfdProcessor()
325 b84cb9a0 Guido Trotter
  server = ConfdAsyncUDPServer(options.bind_address, options.port, processor)
326 b84cb9a0 Guido Trotter
327 562bee4d Guido Trotter
  # Configuration reloader
328 05f1ebf3 Guido Trotter
  reloader = ConfdConfigurationReloader(processor, mainloop)
329 f91c7223 Guido Trotter
330 f91c7223 Guido Trotter
  mainloop.Run()
331 b84cb9a0 Guido Trotter
332 b84cb9a0 Guido Trotter
333 b84cb9a0 Guido Trotter
def main():
334 b84cb9a0 Guido Trotter
  """Main function for the confd daemon.
335 b84cb9a0 Guido Trotter
336 b84cb9a0 Guido Trotter
  """
337 b84cb9a0 Guido Trotter
  parser = OptionParser(description="Ganeti configuration daemon",
338 b84cb9a0 Guido Trotter
                        usage="%prog [-f] [-d] [-b ADDRESS]",
339 b84cb9a0 Guido Trotter
                        version="%%prog (ganeti) %s" %
340 b84cb9a0 Guido Trotter
                        constants.RELEASE_VERSION)
341 b84cb9a0 Guido Trotter
342 b84cb9a0 Guido Trotter
  dirs = [(val, constants.RUN_DIRS_MODE) for val in constants.SUB_RUN_DIRS]
343 b84cb9a0 Guido Trotter
  dirs.append((constants.LOG_OS_DIR, 0750))
344 b84cb9a0 Guido Trotter
  dirs.append((constants.LOCK_DIR, 1777))
345 6c948699 Michael Hanselmann
  daemon.GenericMain(constants.CONFD, parser, dirs, CheckConfd, ExecConfd)
346 b84cb9a0 Guido Trotter
347 b84cb9a0 Guido Trotter
348 6c948699 Michael Hanselmann
if __name__ == "__main__":
349 b84cb9a0 Guido Trotter
  main()