OLD | NEW |
---|---|
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 # Virtual Me2Me implementation. This script runs and manages the processes | 6 # Virtual Me2Me implementation. This script runs and manages the processes |
7 # required for a Virtual Me2Me desktop, which are: X server, X desktop | 7 # required for a Virtual Me2Me desktop, which are: X server, X desktop |
8 # session, and Host process. | 8 # session, and Host process. |
9 # This script is intended to run continuously as a background daemon | 9 # This script is intended to run continuously as a background daemon |
10 # process, running under an ordinary (non-root) user account. | 10 # process, running under an ordinary (non-root) user account. |
(...skipping 365 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
376 self.session_proc = subprocess.Popen(XSESSION_COMMAND, | 376 self.session_proc = subprocess.Popen(XSESSION_COMMAND, |
377 stdin=open(os.devnull, "r"), | 377 stdin=open(os.devnull, "r"), |
378 cwd=HOME_DIR, | 378 cwd=HOME_DIR, |
379 env=self.child_env) | 379 env=self.child_env) |
380 if not self.session_proc.pid: | 380 if not self.session_proc.pid: |
381 raise Exception("Could not start X session") | 381 raise Exception("Could not start X session") |
382 | 382 |
383 def launch_host(self, host): | 383 def launch_host(self, host): |
384 # Start remoting host | 384 # Start remoting host |
385 args = [locate_executable(REMOTING_COMMAND), | 385 args = [locate_executable(REMOTING_COMMAND), |
386 "--host_config=%s" % (host.config_file), | 386 "--host_config=%s" % (host.config_file)] |
387 "--auth_config=%s" % (host.auth.config_file)] | 387 if host.auth.config_file != host.config_file: |
388 args.append("--auth_config=%s" % (host.auth.config_file)) | |
388 self.host_proc = subprocess.Popen(args, env=self.child_env) | 389 self.host_proc = subprocess.Popen(args, env=self.child_env) |
390 logging.info(args) | |
389 if not self.host_proc.pid: | 391 if not self.host_proc.pid: |
390 raise Exception("Could not start remoting host") | 392 raise Exception("Could not start remoting host") |
391 | 393 |
392 | 394 |
393 class PidFile: | 395 class PidFile: |
394 """Class to allow creating and deleting a file which holds the PID of the | 396 """Class to allow creating and deleting a file which holds the PID of the |
395 running process. This is used to detect if a process is already running, and | 397 running process. This is used to detect if a process is already running, and |
396 inform the user of the PID. On process termination, the PID file is | 398 inform the user of the PID. On process termination, the PID file is |
397 deleted. | 399 deleted. |
398 | 400 |
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
616 help="don't run as a background daemon") | 618 help="don't run as a background daemon") |
617 parser.add_option("-k", "--stop", dest="stop", default=False, | 619 parser.add_option("-k", "--stop", dest="stop", default=False, |
618 action="store_true", | 620 action="store_true", |
619 help="stop the daemon currently running") | 621 help="stop the daemon currently running") |
620 parser.add_option("-p", "--new-pin", dest="new_pin", default=False, | 622 parser.add_option("-p", "--new-pin", dest="new_pin", default=False, |
621 action="store_true", | 623 action="store_true", |
622 help="set new PIN before starting the host") | 624 help="set new PIN before starting the host") |
623 parser.add_option("", "--check-running", dest="check_running", default=False, | 625 parser.add_option("", "--check-running", dest="check_running", default=False, |
624 action="store_true", | 626 action="store_true", |
625 help="return 0 if the daemon is running, or 1 otherwise") | 627 help="return 0 if the daemon is running, or 1 otherwise") |
626 parser.add_option("", "--explicit-config", dest="explicit_config", | 628 parser.add_option("", "--silent", dest="silent", default=False, |
627 help="explicitly specify content of the config") | 629 action="store_true", |
630 help="Start the host without trying to configure it.") | |
628 (options, args) = parser.parse_args() | 631 (options, args) = parser.parse_args() |
629 | 632 |
630 host_hash = hashlib.md5(socket.gethostname()).hexdigest() | 633 host_hash = hashlib.md5(socket.gethostname()).hexdigest() |
631 pid_filename = os.path.join(CONFIG_DIR, "host#%s.pid" % host_hash) | 634 pid_filename = os.path.join(CONFIG_DIR, "host#%s.pid" % host_hash) |
632 | 635 |
633 if options.check_running: | 636 if options.check_running: |
634 running, pid = PidFile(pid_filename).check() | 637 running, pid = PidFile(pid_filename).check() |
635 return 0 if (running and pid != 0) else 1 | 638 return 0 if (running and pid != 0) else 1 |
636 | 639 |
637 if options.stop: | 640 if options.stop: |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
679 | 682 |
680 atexit.register(cleanup) | 683 atexit.register(cleanup) |
681 | 684 |
682 for s in [signal.SIGHUP, signal.SIGINT, signal.SIGTERM, signal.SIGUSR1]: | 685 for s in [signal.SIGHUP, signal.SIGINT, signal.SIGTERM, signal.SIGUSR1]: |
683 signal.signal(s, signal_handler) | 686 signal.signal(s, signal_handler) |
684 | 687 |
685 # Ensure full path to config directory exists. | 688 # Ensure full path to config directory exists. |
686 if not os.path.exists(CONFIG_DIR): | 689 if not os.path.exists(CONFIG_DIR): |
687 os.makedirs(CONFIG_DIR, mode=0700) | 690 os.makedirs(CONFIG_DIR, mode=0700) |
688 | 691 |
689 if options.explicit_config: | 692 host_config_file = os.path.join(CONFIG_DIR, "host#%s.json" % host_hash) |
690 for file_name in ["auth.json", "host#%s.json" % host_hash]: | |
691 settings_file = open(os.path.join(CONFIG_DIR, file_name), 'w') | |
692 settings_file.write(options.explicit_config) | |
693 settings_file.close() | |
694 | 693 |
695 # TODO(sergeyu): Move auth parameters to the host config. | 694 # --silent option is specified when we are started from WebApp UI. Don't use |
696 auth = Authentication(os.path.join(CONFIG_DIR, "auth.json")) | 695 # separate auth file in that case. |
697 need_auth_tokens = not auth.load_config() | 696 # TODO(sergeyu): Always use host config for auth parameters. |
697 if options.silent: | |
698 auth_config_file = host_config_file | |
699 else: | |
700 auth_config_file = os.path.join(CONFIG_DIR, "auth.json") | |
698 | 701 |
Lambros
2012/08/01 18:30:57
Good TODO. As it is now, the script will use a di
Sergey Ulanov
2012/08/01 20:20:54
I'll do it in my next CL for this code. Problem is
| |
699 host = Host(os.path.join(CONFIG_DIR, "host#%s.json" % host_hash), auth) | 702 auth = Authentication(auth_config_file) |
700 register_host = not host.load_config() | 703 auth_config_loaded = auth.load_config() |
701 | 704 |
702 # Outside the loop so user doesn't get asked twice. | 705 host = Host(host_config_file, auth) |
703 if register_host: | 706 host_config_loaded = host.load_config() |
704 host.ask_pin() | |
705 elif options.new_pin or not host.is_pin_set(): | |
706 host.ask_pin() | |
707 host.save_config() | |
708 running, pid = PidFile(pid_filename).check() | |
709 if running and pid != 0: | |
710 os.kill(pid, signal.SIGUSR1) | |
711 print "The running instance has been updated with the new PIN." | |
712 return 0 | |
713 | 707 |
714 if not options.explicit_config: | 708 if options.silent: |
709 if not host_config_loaded or not auth_config_loaded: | |
710 logging.error("Failed to load host configuration.") | |
711 return 1 | |
712 else: | |
713 need_auth_tokens = not auth_config_loaded | |
714 need_register_host = not host_config_loaded | |
715 # Outside the loop so user doesn't get asked twice. | |
716 if need_register_host: | |
717 host.ask_pin() | |
718 elif options.new_pin or not host.is_pin_set(): | |
719 host.ask_pin() | |
720 host.save_config() | |
721 running, pid = PidFile(pid_filename).check() | |
722 if running and pid != 0: | |
723 os.kill(pid, signal.SIGUSR1) | |
724 print "The running instance has been updated with the new PIN." | |
725 return 0 | |
726 | |
715 # The loop is to deal with the case of registering a new Host with | 727 # The loop is to deal with the case of registering a new Host with |
716 # previously-saved auth tokens (from a previous run of this script), which | 728 # previously-saved auth tokens (from a previous run of this script), which |
717 # may require re-prompting for username & password. | 729 # may require re-prompting for username & password. |
718 while True: | 730 while True: |
719 try: | 731 try: |
720 if need_auth_tokens: | 732 if need_auth_tokens: |
721 auth.generate_tokens() | 733 auth.generate_tokens() |
722 auth.save_config() | 734 auth.save_config() |
723 need_auth_tokens = False | 735 need_auth_tokens = False |
724 except Exception: | 736 except Exception: |
725 logging.error("Authentication failed") | 737 logging.error("Authentication failed") |
726 return 1 | 738 return 1 |
727 | 739 |
728 try: | 740 try: |
729 if register_host: | 741 if need_register_host: |
730 host.register() | 742 host.register() |
731 host.save_config() | 743 host.save_config() |
732 except urllib2.HTTPError, err: | 744 except urllib2.HTTPError, err: |
733 if err.getcode() == 401: | 745 if err.getcode() == 401: |
734 # Authentication failed - re-prompt for username & password. | 746 # Authentication failed - re-prompt for username & password. |
735 need_auth_tokens = True | 747 need_auth_tokens = True |
736 continue | 748 continue |
737 else: | 749 else: |
738 # Not an authentication error. | 750 # Not an authentication error. |
739 logging.error("Directory returned error: " + str(err)) | 751 logging.error("Directory returned error: " + str(err)) |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
834 logging.info("Host process terminated") | 846 logging.info("Host process terminated") |
835 desktop.host_proc = None | 847 desktop.host_proc = None |
836 | 848 |
837 # These exit-codes must match the ones used by the host. | 849 # These exit-codes must match the ones used by the host. |
838 # See remoting/host/constants.h. | 850 # See remoting/host/constants.h. |
839 # Delete the host or auth configuration depending on the returned error | 851 # Delete the host or auth configuration depending on the returned error |
840 # code, so the next time this script is run, a new configuration | 852 # code, so the next time this script is run, a new configuration |
841 # will be created and registered. | 853 # will be created and registered. |
842 if os.WEXITSTATUS(status) == 2: | 854 if os.WEXITSTATUS(status) == 2: |
843 logging.info("Host configuration is invalid - exiting.") | 855 logging.info("Host configuration is invalid - exiting.") |
844 os.remove(auth.config_file) | 856 try: |
845 os.remove(host.config_file) | 857 os.remove(host.config_file) |
858 os.remove(auth.config_file) | |
859 except: | |
860 pass | |
846 return 0 | 861 return 0 |
847 elif os.WEXITSTATUS(status) == 3: | 862 elif os.WEXITSTATUS(status) == 3: |
848 logging.info("Host ID has been deleted - exiting.") | 863 logging.info("Host ID has been deleted - exiting.") |
849 os.remove(host.config_file) | 864 try: |
865 os.remove(host.config_file) | |
866 except: | |
867 pass | |
850 return 0 | 868 return 0 |
851 elif os.WEXITSTATUS(status) == 4: | 869 elif os.WEXITSTATUS(status) == 4: |
852 logging.info("OAuth credentials are invalid - exiting.") | 870 logging.info("OAuth credentials are invalid - exiting.") |
853 os.remove(auth.config_file) | 871 try: |
872 os.remove(auth.config_file) | |
873 except: | |
874 pass | |
854 return 0 | 875 return 0 |
855 | 876 |
856 if __name__ == "__main__": | 877 if __name__ == "__main__": |
857 logging.basicConfig(level=logging.DEBUG) | 878 logging.basicConfig(level=logging.DEBUG) |
858 sys.exit(main()) | 879 sys.exit(main()) |
OLD | NEW |