460 print('-> instance %s (%s) deleted.' % (appid, confignames)) |
460 print('-> instance %s (%s) deleted.' % (appid, confignames)) |
461 |
461 |
462 |
462 |
463 # instance commands ######################################################## |
463 # instance commands ######################################################## |
464 |
464 |
465 class StartInstanceCommand(InstanceCommandFork): |
|
466 """Start the given instances. If no instance is given, start them all. |
|
467 |
|
468 <instance>... |
|
469 identifiers of the instances to start. If no instance is |
|
470 given, start them all. |
|
471 """ |
|
472 name = 'start' |
|
473 actionverb = 'started' |
|
474 options = ( |
|
475 ("debug", |
|
476 {'short': 'D', 'action': 'store_true', |
|
477 'help': 'start server in debug mode.'}), |
|
478 ("force", |
|
479 {'short': 'f', 'action': 'store_true', |
|
480 'default': False, |
|
481 'help': 'start the instance even if it seems to be already \ |
|
482 running.'}), |
|
483 ('profile', |
|
484 {'short': 'P', 'type': 'string', 'metavar': '<stat file>', |
|
485 'default': None, |
|
486 'help': 'profile code and use the specified file to store stats', |
|
487 }), |
|
488 ('loglevel', |
|
489 {'short': 'l', 'type': 'choice', 'metavar': '<log level>', |
|
490 'default': None, 'choices': ('debug', 'info', 'warning', 'error'), |
|
491 'help': 'debug if -D is set, error otherwise', |
|
492 }), |
|
493 ('param', |
|
494 {'short': 'p', 'type': 'named', 'metavar': 'key1:value1,key2:value2', |
|
495 'default': {}, |
|
496 'help': 'override <key> configuration file option with <value>.', |
|
497 }), |
|
498 ) |
|
499 |
|
500 def start_instance(self, appid): |
|
501 """start the instance's server""" |
|
502 try: |
|
503 import twisted # noqa |
|
504 except ImportError: |
|
505 msg = ( |
|
506 "Twisted is required by the 'start' command\n" |
|
507 "Either install it, or use one of the alternative commands:\n" |
|
508 "- '{ctl} pyramid {appid}'\n" |
|
509 "- '{ctl} wsgi {appid}'\n") |
|
510 raise ExecutionError(msg.format(ctl='cubicweb-ctl', appid=appid)) |
|
511 config = cwcfg.config_for(appid, debugmode=self['debug']) |
|
512 # override config file values with cmdline options |
|
513 config.cmdline_options = self.config.param |
|
514 init_cmdline_log_threshold(config, self['loglevel']) |
|
515 if self['profile']: |
|
516 config.global_set_option('profile', self.config.profile) |
|
517 helper = self.config_helper(config, cmdname='start') |
|
518 pidf = config['pid-file'] |
|
519 if exists(pidf) and not self['force']: |
|
520 msg = "%s seems to be running. Remove %s by hand if necessary or use \ |
|
521 the --force option." |
|
522 raise ExecutionError(msg % (appid, pidf)) |
|
523 if helper.start_server(config) == 1: |
|
524 print('instance %s started' % appid) |
|
525 |
|
526 |
|
527 def init_cmdline_log_threshold(config, loglevel): |
465 def init_cmdline_log_threshold(config, loglevel): |
528 if loglevel is not None: |
466 if loglevel is not None: |
529 config.global_set_option('log-threshold', loglevel.upper()) |
467 config.global_set_option('log-threshold', loglevel.upper()) |
530 config.init_log(config['log-threshold'], force=True) |
468 config.init_log(config['log-threshold'], force=True) |
531 |
|
532 |
|
533 class StopInstanceCommand(InstanceCommand): |
|
534 """Stop the given instances. |
|
535 |
|
536 <instance>... |
|
537 identifiers of the instances to stop. If no instance is |
|
538 given, stop them all. |
|
539 """ |
|
540 name = 'stop' |
|
541 actionverb = 'stopped' |
|
542 |
|
543 def stop_instance(self, appid): |
|
544 """stop the instance's server""" |
|
545 config = cwcfg.config_for(appid) |
|
546 helper = self.config_helper(config, cmdname='stop') |
|
547 helper.poststop() # do this anyway |
|
548 pidf = config['pid-file'] |
|
549 if not exists(pidf): |
|
550 sys.stderr.write("%s doesn't exist.\n" % pidf) |
|
551 return |
|
552 import signal |
|
553 pid = int(open(pidf).read().strip()) |
|
554 try: |
|
555 kill(pid, signal.SIGTERM) |
|
556 except Exception: |
|
557 sys.stderr.write("process %s seems already dead.\n" % pid) |
|
558 else: |
|
559 try: |
|
560 wait_process_end(pid) |
|
561 except ExecutionError as ex: |
|
562 sys.stderr.write('%s\ntrying SIGKILL\n' % ex) |
|
563 try: |
|
564 kill(pid, signal.SIGKILL) |
|
565 except Exception: |
|
566 # probably dead now |
|
567 pass |
|
568 wait_process_end(pid) |
|
569 try: |
|
570 remove(pidf) |
|
571 except OSError: |
|
572 # already removed by twistd |
|
573 pass |
|
574 print('instance %s stopped' % appid) |
|
575 |
|
576 |
|
577 class RestartInstanceCommand(StartInstanceCommand): |
|
578 """Restart the given instances. |
|
579 |
|
580 <instance>... |
|
581 identifiers of the instances to restart. If no instance is |
|
582 given, restart them all. |
|
583 """ |
|
584 name = 'restart' |
|
585 actionverb = 'restarted' |
|
586 |
|
587 def restart_instance(self, appid): |
|
588 StopInstanceCommand(self.logger).stop_instance(appid) |
|
589 self.start_instance(appid) |
|
590 |
|
591 |
|
592 class ReloadConfigurationCommand(RestartInstanceCommand): |
|
593 """Reload the given instances. This command is equivalent to a |
|
594 restart for now. |
|
595 |
|
596 <instance>... |
|
597 identifiers of the instances to reload. If no instance is |
|
598 given, reload them all. |
|
599 """ |
|
600 name = 'reload' |
|
601 |
|
602 def reload_instance(self, appid): |
|
603 self.restart_instance(appid) |
|
604 |
|
605 |
|
606 class StatusCommand(InstanceCommand): |
|
607 """Display status information about the given instances. |
|
608 |
|
609 <instance>... |
|
610 identifiers of the instances to status. If no instance is |
|
611 given, get status information about all registered instances. |
|
612 """ |
|
613 name = 'status' |
|
614 options = () |
|
615 |
|
616 @staticmethod |
|
617 def status_instance(appid): |
|
618 """print running status information for an instance""" |
|
619 status = 0 |
|
620 for mode in cwcfg.possible_configurations(appid): |
|
621 config = cwcfg.config_for(appid, mode) |
|
622 print('[%s-%s]' % (appid, mode), end=' ') |
|
623 try: |
|
624 pidf = config['pid-file'] |
|
625 except KeyError: |
|
626 print('buggy instance, pid file not specified') |
|
627 continue |
|
628 if not exists(pidf): |
|
629 print("doesn't seem to be running") |
|
630 status = 1 |
|
631 continue |
|
632 pid = int(open(pidf).read().strip()) |
|
633 # trick to guess whether or not the process is running |
|
634 try: |
|
635 getpgid(pid) |
|
636 except OSError: |
|
637 print("should be running with pid %s but the process can not be found" % pid) |
|
638 status = 1 |
|
639 continue |
|
640 print("running with pid %s" % (pid)) |
|
641 return status |
|
642 |
469 |
643 |
470 |
644 class UpgradeInstanceCommand(InstanceCommandFork): |
471 class UpgradeInstanceCommand(InstanceCommandFork): |
645 """Upgrade an instance after cubicweb and/or component(s) upgrade. |
472 """Upgrade an instance after cubicweb and/or component(s) upgrade. |
646 |
473 |