Revision 04ccf5e9

b/daemons/ganeti-masterd
43 43

  
44 44
from ganeti import config
45 45
from ganeti import constants
46
from ganeti import daemon
46 47
from ganeti import mcpu
47 48
from ganeti import opcodes
48 49
from ganeti import jqueue
......
383 384
    self.glm.remove(locking.LEVEL_NODE, name)
384 385

  
385 386

  
386
def ParseOptions():
387
  """Parse the command line options.
388

  
389
  @return: (options, args) as from OptionParser.parse_args()
390

  
391
  """
392
  parser = OptionParser(description="Ganeti master daemon",
393
                        usage="%prog [-f] [-d]",
394
                        version="%%prog (ganeti) %s" %
395
                        constants.RELEASE_VERSION)
396

  
397
  parser.add_option("-f", "--foreground", dest="fork",
398
                    help="Don't detach from the current terminal",
399
                    default=True, action="store_false")
400
  parser.add_option("-d", "--debug", dest="debug",
401
                    help="Enable some debug messages",
402
                    default=False, action="store_true")
403
  parser.add_option("--no-voting", dest="no_voting",
404
                    help="Do not check that the nodes agree on this node"
405
                    " being the master and start the daemon unconditionally",
406
                    default=False, action="store_true")
407
  parser.add_option("--yes-do-it", dest="yes_do_it",
408
                    help="Override interactive check for --no-voting",
409
                    default=False, action="store_true")
410

  
411
  options, args = parser.parse_args()
412
  return options, args
413

  
414

  
415 387
def CheckAgreement():
416 388
  """Check the agreement on who is the master.
417 389

  
......
468 440

  
469 441
  return result
470 442

  
443
def CheckMASTERD(options, args):
444
  """Initial checks whether to run or exit with a failure
471 445

  
472
def main():
473
  """Main function"""
474

  
475
  options, args = ParseOptions()
476
  utils.no_fork = True
477
  daemon_name = constants.MASTERD
478

  
479
  if options.fork:
480
    utils.CloseFDs()
481

  
446
  """
482 447
  rpc.Init()
483 448
  try:
484 449
    ssconf.CheckMaster(options.debug)
......
496 461
    elif not options.no_voting:
497 462
      if not CheckAgreement():
498 463
        return
499

  
500
    dirs = [(constants.RUN_GANETI_DIR, constants.RUN_DIRS_MODE),
501
            (constants.SOCKET_DIR, constants.SOCKET_DIR_MODE),
502
           ]
503
    utils.EnsureDirs(dirs)
504

  
505
    # This is safe to do as the pid file guarantees against
506
    # concurrent execution.
507
    utils.RemoveFile(constants.MASTER_SOCKET)
508

  
509
    master = IOServer(constants.MASTER_SOCKET, ClientRqHandler)
510 464
  finally:
511 465
    rpc.Shutdown()
512 466

  
513
  # become a daemon
514
  if options.fork:
515
    utils.Daemonize(logfile=constants.DAEMONS_LOGFILES[daemon_name])
516 467

  
517
  utils.WritePidFile(daemon_name)
518
  try:
519
    utils.SetupLogging(constants.DAEMONS_LOGFILES[daemon_name],
520
                       debug=options.debug,
521
                       stderr_logging=not options.fork, multithreaded=True)
468
def ExecMASTERD(options, args):
469
  """Main MASTERD function, executed with the pidfile held.
522 470

  
523
    logging.info("Ganeti master daemon startup")
471
  """
472
  # This is safe to do as the pid file guarantees against
473
  # concurrent execution.
474
  utils.RemoveFile(constants.MASTER_SOCKET)
524 475

  
476
  master = IOServer(constants.MASTER_SOCKET, ClientRqHandler)
477
  try:
525 478
    rpc.Init()
526 479
    try:
527 480
      # activate ip
......
539 492
    finally:
540 493
      rpc.Shutdown()
541 494
  finally:
542
    utils.RemovePidFile(daemon_name)
543 495
    utils.RemoveFile(constants.MASTER_SOCKET)
544 496

  
545 497

  
498
def main():
499
  """Main function"""
500
  parser = OptionParser(description="Ganeti master daemon",
501
                        usage="%prog [-f] [-d]",
502
                        version="%%prog (ganeti) %s" %
503
                        constants.RELEASE_VERSION)
504
  parser.add_option("--no-voting", dest="no_voting",
505
                    help="Do not check that the nodes agree on this node"
506
                    " being the master and start the daemon unconditionally",
507
                    default=False, action="store_true")
508
  parser.add_option("--yes-do-it", dest="yes_do_it",
509
                    help="Override interactive check for --no-voting",
510
                    default=False, action="store_true")
511
  dirs = [(constants.RUN_GANETI_DIR, constants.RUN_DIRS_MODE),
512
          (constants.SOCKET_DIR, constants.SOCKET_DIR_MODE),
513
         ]
514
  daemon.GenericMain(constants.MASTERD, parser, dirs,
515
                     CheckMASTERD, ExecMASTERD)
516

  
546 517
if __name__ == "__main__":
547 518
  main()
b/daemons/ganeti-noded
732 732
    return backend.ValidateHVParams(hvname, hvparams)
733 733

  
734 734

  
735
def ParseOptions():
736
  """Parse the command line options.
737

  
738
  @return: (options, args) as from OptionParser.parse_args()
735
def CheckNODED(options, args):
736
  """Initial checks whether to run exit with a failure
739 737

  
740 738
  """
741
  parser = OptionParser(description="Ganeti node daemon",
742
                        usage="%prog [-f] [-d] [-b ADDRESS]",
743
                        version="%%prog (ganeti) %s" %
744
                        constants.RELEASE_VERSION)
745

  
746
  parser.add_option("-f", "--foreground", dest="fork",
747
                    help="Don't detach from the current terminal",
748
                    default=True, action="store_false")
749
  parser.add_option("-d", "--debug", dest="debug",
750
                    help="Enable some debug messages",
751
                    default=False, action="store_true")
752
  parser.add_option("-b", "--bind", dest="bind_address",
753
                    help="Bind address",
754
                    default="", metavar="ADDRESS")
755

  
756
  options, args = parser.parse_args()
757
  return options, args
739
  for fname in (constants.SSL_CERT_FILE,):
740
    if not os.path.isfile(fname):
741
      print "config %s not there, will not run." % fname
742
      sys.exit(constants.EXIT_NOTCLUSTER)
758 743

  
759 744

  
760
def main():
761
  """Main function for the node daemon.
745
def ExecNODED(options, args):
746
  """Main NODED function, executed with the pidfile held.
762 747

  
763 748
  """
764 749
  global queue_lock
765
  daemon_name = constants.NODED
766 750

  
767
  options, args = ParseOptions()
751
  # Read SSL certificate
752
  ssl_params = http.HttpSslParams(ssl_key_path=constants.SSL_CERT_FILE,
753
                                  ssl_cert_path=constants.SSL_CERT_FILE)
768 754

  
769
  if options.fork:
770
    utils.CloseFDs()
755
  # Prepare job queue
756
  queue_lock = jstore.InitAndVerifyQueue(must_lock=False)
771 757

  
772
  for fname in (constants.SSL_CERT_FILE,):
773
    if not os.path.isfile(fname):
774
      print "config %s not there, will not run." % fname
775
      sys.exit(constants.EXIT_NOTCLUSTER)
758
  mainloop = daemon.Mainloop()
759
  server = NodeHttpServer(mainloop, options.bind_address, options.port,
760
                          ssl_params=ssl_params, ssl_verify_peer=True)
761
  server.Start()
762
  try:
763
    mainloop.Run()
764
  finally:
765
    server.Stop()
776 766

  
777
  port = utils.GetDaemonPort(constants.NODED)
778 767

  
768
def main():
769
  """Main function for the node daemon.
770

  
771
  """
772
  parser = OptionParser(description="Ganeti node daemon",
773
                        usage="%prog [-f] [-d] [-p port] [-b ADDRESS]",
774
                        version="%%prog (ganeti) %s" %
775
                        constants.RELEASE_VERSION)
779 776
  dirs = [(val, constants.RUN_DIRS_MODE) for val in constants.SUB_RUN_DIRS]
780 777
  dirs.append((constants.LOG_OS_DIR, 0750))
781 778
  dirs.append((constants.LOCK_DIR, 1777))
782
  utils.EnsureDirs(dirs)
783

  
784
  # become a daemon
785
  if options.fork:
786
    utils.Daemonize(logfile=constants.DAEMONS_LOGFILES[daemon_name])
787

  
788
  utils.WritePidFile(daemon_name)
789
  try:
790
    utils.SetupLogging(logfile=constants.DAEMONS_LOGFILES[daemon_name],
791
                       debug=options.debug,
792
                       stderr_logging=not options.fork)
793
    logging.info("ganeti node daemon startup")
794

  
795
    # Read SSL certificate
796
    ssl_params = http.HttpSslParams(ssl_key_path=constants.SSL_CERT_FILE,
797
                                    ssl_cert_path=constants.SSL_CERT_FILE)
798

  
799
    # Prepare job queue
800
    queue_lock = jstore.InitAndVerifyQueue(must_lock=False)
801

  
802
    mainloop = daemon.Mainloop()
803
    server = NodeHttpServer(mainloop, options.bind_address, port,
804
                            ssl_params=ssl_params, ssl_verify_peer=True)
805
    server.Start()
806
    try:
807
      mainloop.Run()
808
    finally:
809
      server.Stop()
810
  finally:
811
    utils.RemovePidFile(daemon_name)
779
  daemon.GenericMain(constants.NODED, parser, dirs, CheckNODED, ExecNODED)
812 780

  
813 781

  
814 782
if __name__ == '__main__':
b/daemons/ganeti-rapi
177 177
    return result
178 178

  
179 179

  
180
def ParseOptions():
181
  """Parse the command line options.
182

  
183
  @return: (options, args) as from OptionParser.parse_args()
180
def CheckRAPI(options, args):
181
  """Initial checks whether to run or exit with a failure
184 182

  
185 183
  """
186
  parser = optparse.OptionParser(description="Ganeti Remote API",
187
                    usage="%prog [-d]",
188
                    version="%%prog (ganeti) %s" %
189
                                 constants.RAPI_VERSION)
190
  parser.add_option("-d", "--debug", dest="debug",
191
                    help="Enable some debug messages",
192
                    default=False, action="store_true")
193
  parser.add_option("--no-ssl", dest="ssl",
194
                    help="Do not secure HTTP protocol with SSL",
195
                    default=True, action="store_false")
196
  parser.add_option("-K", "--ssl-key", dest="ssl_key",
197
                    help="SSL key",
198
                    default=constants.RAPI_CERT_FILE, type="string")
199
  parser.add_option("-C", "--ssl-cert", dest="ssl_cert",
200
                    help="SSL certificate",
201
                    default=constants.RAPI_CERT_FILE, type="string")
202
  parser.add_option("-f", "--foreground", dest="fork",
203
                    help="Don't detach from the current terminal",
204
                    default=True, action="store_false")
205
  parser.add_option("-b", "--bind", dest="bind_address",
206
                     help="Bind address",
207
                     default="", metavar="ADDRESS")
208

  
209
  options, args = parser.parse_args()
210

  
211 184
  if len(args) != 0:
212
    print >> sys.stderr, "Usage: %s [-d]" % sys.argv[0]
185
    print >> sys.stderr, "Usage: %s [-f] [-d] [-p port] [-b ADDRESS]" % \
186
        sys.argv[0]
213 187
    sys.exit(constants.EXIT_FAILURE)
214 188

  
215
  if options.ssl and not (options.ssl_cert and options.ssl_key):
216
    print >> sys.stderr, ("For secure mode please provide "
217
                          "--ssl-key and --ssl-cert arguments")
218
    sys.exit(constants.EXIT_FAILURE)
189
  if options.ssl:
190
    if not (options.ssl_cert and options.ssl_key):
191
      print >> sys.stderr, ("For secure mode please provide "
192
                            "--ssl-key and --ssl-cert arguments")
193
      sys.exit(constants.EXIT_FAILURE)
194
    for fname in (options.ssl_cert, options.ssl_key):
195
      if not os.path.isfile(fname):
196
        print >> sys.stderr, "config %s not there, will not run." % fname
197
        sys.exit(constants.EXIT_FAILURE)
219 198

  
220
  return options, args
199
  ssconf.CheckMaster(options.debug)
221 200

  
222 201

  
223
def main():
224
  """Main function.
202
def ExecRAPI(options, args):
203
  """Main RAPI function, executed with the pidfile held.
225 204

  
226 205
  """
227
  options, args = ParseOptions()
228
  daemon_name = constants.RAPI
229

  
230
  if options.fork:
231
    utils.CloseFDs()
232

  
206
  # Read SSL certificate
233 207
  if options.ssl:
234
    # Read SSL certificate
235
    try:
236
      ssl_params = http.HttpSslParams(ssl_key_path=options.ssl_key,
237
                                      ssl_cert_path=options.ssl_cert)
238
    except Exception, err:
239
      sys.stderr.write("Can't load the SSL certificate/key: %s\n" % (err,))
240
      sys.exit(constants.EXIT_FAILURE)
208
    ssl_params = http.HttpSslParams(ssl_key_path=options.ssl_key,
209
                                    ssl_cert_path=options.ssl_cert)
241 210
  else:
242 211
    ssl_params = None
243 212

  
244
  ssconf.CheckMaster(options.debug)
245
  port = utils.GetDaemonPort(constants.RAPI)
213
  mainloop = daemon.Mainloop()
214
  server = RemoteApiHttpServer(mainloop, options.bind_address, options.port,
215
                               ssl_params=ssl_params, ssl_verify_peer=False,
216
                               request_executor_class=JsonErrorRequestExecutor)
217
  server.Start()
218
  try:
219
    mainloop.Run()
220
  finally:
221
    server.Stop()
246 222

  
247
  if options.fork:
248
    utils.Daemonize(logfile=constants.DAEMONS_LOGFILES[daemon_name])
249 223

  
250
  utils.SetupLogging(constants.DAEMONS_LOGFILES[daemon_name], debug=options.debug,
251
                     stderr_logging=not options.fork)
224
def main():
225
  """Main function.
252 226

  
253
  utils.WritePidFile(daemon_name)
254
  try:
255
    mainloop = daemon.Mainloop()
256
    server = RemoteApiHttpServer(mainloop, options.bind_address, port,
257
                                 ssl_params=ssl_params, ssl_verify_peer=False,
258
                                 request_executor_class=
259
                                 JsonErrorRequestExecutor)
260
    server.Start()
261
    try:
262
      mainloop.Run()
263
    finally:
264
      server.Stop()
265
  finally:
266
    utils.RemovePidFile(daemon_name)
227
  """
228
  parser = optparse.OptionParser(description="Ganeti Remote API",
229
                    usage="%prog [-f] [-d] [-p port] [-b ADDRESS]",
230
                    version="%%prog (ganeti) %s" % constants.RAPI_VERSION)
231
  parser.add_option("--no-ssl", dest="ssl",
232
                    help="Do not secure HTTP protocol with SSL",
233
                    default=True, action="store_false")
234
  parser.add_option("-K", "--ssl-key", dest="ssl_key",
235
                    help="SSL key",
236
                    default=constants.RAPI_CERT_FILE, type="string")
237
  parser.add_option("-C", "--ssl-cert", dest="ssl_cert",
238
                    help="SSL certificate",
239
                    default=constants.RAPI_CERT_FILE, type="string")
240

  
241
  dirs = [(val, constants.RUN_DIRS_MODE) for val in constants.SUB_RUN_DIRS]
242
  dirs.append((constants.LOG_OS_DIR, 0750))
243
  daemon.GenericMain(constants.RAPI, parser, dirs, CheckRAPI, ExecRAPI)
267 244

  
268 245

  
269 246
if __name__ == '__main__':
b/lib/constants.py
115 115
RAPI = "ganeti-rapi"
116 116
MASTERD = "ganeti-masterd"
117 117

  
118
MULTITHREADED_DAEMONS = frozenset([MASTERD])
119

  
118 120
DAEMONS_PORTS = {
119 121
  # daemon-name: ("proto", "default-port")
120 122
  NODED: ("tcp", 1811),
b/lib/daemon.py
26 26
import signal
27 27
import errno
28 28
import time
29
import logging
29 30

  
30 31
from ganeti import utils
32
from ganeti import constants
31 33

  
32 34

  
33 35
class Timer(object):
......
297 299

  
298 300
    """
299 301
    self._timer_remove.append(timer_id)
302

  
303

  
304
def GenericMain(daemon_name, optionparser, dirs, check_fn, exec_fn):
305
  """Shared main function for daemons.
306

  
307
  @type daemon_name: string
308
  @param daemon_name: daemon name
309
  @type optionparser: L{optparse.OptionParser}
310
  @param optionparser: initialized optionparser with daemon-specific options
311
                       (common -f -d options will be handled by this module)
312
  @type options: object @param options: OptionParser result, should contain at
313
                 least the fork and the debug options
314
  @type dirs: list of strings
315
  @param dirs: list of directories that must exist for this daemon to work
316
  @type check_fn: function which accepts (options, args)
317
  @param check_fn: function that checks start conditions and exits if they're
318
                   not met
319
  @type exec_fn: function which accepts (options, args)
320
  @param exec_fn: function that's executed with the daemon's pid file held, and
321
                  runs the daemon itself.
322

  
323
  """
324
  optionparser.add_option("-f", "--foreground", dest="fork",
325
                          help="Don't detach from the current terminal",
326
                          default=True, action="store_false")
327
  optionparser.add_option("-d", "--debug", dest="debug",
328
                          help="Enable some debug messages",
329
                          default=False, action="store_true")
330
  if daemon_name in constants.DAEMONS_PORTS:
331
    # for networked daemons we also allow choosing the bind port and address.
332
    # by default we use the port provided by utils.GetDaemonPort, and bind to
333
    # 0.0.0.0 (which is represented by and empty bind address.
334
    port = utils.GetDaemonPort(daemon_name)
335
    optionparser.add_option("-p", "--port", dest="port",
336
                            help="Network port (%s default)." % port,
337
                            default=port, type="int")
338
    optionparser.add_option("-b", "--bind", dest="bind_address",
339
                            help="Bind address",
340
                            default="", metavar="ADDRESS")
341

  
342
  multithread = utils.no_fork = daemon_name in constants.MULTITHREADED_DAEMONS
343

  
344
  options, args = optionparser.parse_args()
345

  
346
  check_fn(options, args)
347
  utils.EnsureDirs(dirs)
348

  
349
  if options.fork:
350
    utils.CloseFDs()
351
    utils.Daemonize(logfile=constants.DAEMONS_LOGFILES[daemon_name])
352

  
353
  utils.WritePidFile(daemon_name)
354
  try:
355
    utils.SetupLogging(logfile=constants.DAEMONS_LOGFILES[daemon_name],
356
                       debug=options.debug,
357
                       stderr_logging=not options.fork,
358
                       multithreaded=multithread)
359
    logging.info("%s daemon startup" % daemon_name)
360
    exec_fn(options, args)
361
  finally:
362
    utils.RemovePidFile(daemon_name)
363

  

Also available in: Unified diff