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 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
617 help="don't run as a background daemon") | 619 help="don't run as a background daemon") |
618 parser.add_option("-k", "--stop", dest="stop", default=False, | 620 parser.add_option("-k", "--stop", dest="stop", default=False, |
619 action="store_true", | 621 action="store_true", |
620 help="stop the daemon currently running") | 622 help="stop the daemon currently running") |
621 parser.add_option("-p", "--new-pin", dest="new_pin", default=False, | 623 parser.add_option("-p", "--new-pin", dest="new_pin", default=False, |
622 action="store_true", | 624 action="store_true", |
623 help="set new PIN before starting the host") | 625 help="set new PIN before starting the host") |
624 parser.add_option("", "--check-running", dest="check_running", default=False, | 626 parser.add_option("", "--check-running", dest="check_running", default=False, |
625 action="store_true", | 627 action="store_true", |
626 help="return 0 if the daemon is running, or 1 otherwise") | 628 help="return 0 if the daemon is running, or 1 otherwise") |
627 parser.add_option("", "--explicit-config", dest="explicit_config", | 629 parser.add_option("", "--silent", dest="silent", default=False, |
628 help="explicitly specify content of the config") | 630 action="store_true", |
| 631 help="Start the host without trying to configure it.") |
629 (options, args) = parser.parse_args() | 632 (options, args) = parser.parse_args() |
630 | 633 |
631 host_hash = hashlib.md5(socket.gethostname()).hexdigest() | 634 host_hash = hashlib.md5(socket.gethostname()).hexdigest() |
632 pid_filename = os.path.join(CONFIG_DIR, "host#%s.pid" % host_hash) | 635 pid_filename = os.path.join(CONFIG_DIR, "host#%s.pid" % host_hash) |
633 | 636 |
634 if options.check_running: | 637 if options.check_running: |
635 running, pid = PidFile(pid_filename).check() | 638 running, pid = PidFile(pid_filename).check() |
636 return 0 if (running and pid != 0) else 1 | 639 return 0 if (running and pid != 0) else 1 |
637 | 640 |
638 if options.stop: | 641 if options.stop: |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
680 | 683 |
681 atexit.register(cleanup) | 684 atexit.register(cleanup) |
682 | 685 |
683 for s in [signal.SIGHUP, signal.SIGINT, signal.SIGTERM, signal.SIGUSR1]: | 686 for s in [signal.SIGHUP, signal.SIGINT, signal.SIGTERM, signal.SIGUSR1]: |
684 signal.signal(s, signal_handler) | 687 signal.signal(s, signal_handler) |
685 | 688 |
686 # Ensure full path to config directory exists. | 689 # Ensure full path to config directory exists. |
687 if not os.path.exists(CONFIG_DIR): | 690 if not os.path.exists(CONFIG_DIR): |
688 os.makedirs(CONFIG_DIR, mode=0700) | 691 os.makedirs(CONFIG_DIR, mode=0700) |
689 | 692 |
690 if options.explicit_config: | 693 host_config_file = os.path.join(CONFIG_DIR, "host#%s.json" % host_hash) |
691 for file_name in ["auth.json", "host#%s.json" % host_hash]: | |
692 settings_file = open(os.path.join(CONFIG_DIR, file_name), 'w') | |
693 settings_file.write(options.explicit_config) | |
694 settings_file.close() | |
695 | 694 |
696 # TODO(sergeyu): Move auth parameters to the host config. | 695 # --silent option is specified when we are started from WebApp UI. Don't use |
697 auth = Authentication(os.path.join(CONFIG_DIR, "auth.json")) | 696 # separate auth file in that case. |
698 need_auth_tokens = not auth.load_config() | 697 # TODO(sergeyu): Always use host config for auth parameters. |
| 698 if options.silent: |
| 699 auth_config_file = host_config_file |
| 700 else: |
| 701 auth_config_file = os.path.join(CONFIG_DIR, "auth.json") |
699 | 702 |
700 host = Host(os.path.join(CONFIG_DIR, "host#%s.json" % host_hash), auth) | 703 auth = Authentication(auth_config_file) |
701 register_host = not host.load_config() | 704 auth_config_loaded = auth.load_config() |
702 | 705 |
703 # Outside the loop so user doesn't get asked twice. | 706 host = Host(host_config_file, auth) |
704 if register_host: | 707 host_config_loaded = host.load_config() |
705 host.ask_pin() | |
706 elif options.new_pin or not host.is_pin_set(): | |
707 host.ask_pin() | |
708 host.save_config() | |
709 running, pid = PidFile(pid_filename).check() | |
710 if running and pid != 0: | |
711 os.kill(pid, signal.SIGUSR1) | |
712 print "The running instance has been updated with the new PIN." | |
713 return 0 | |
714 | 708 |
715 if not options.explicit_config: | 709 if options.silent: |
| 710 if not host_config_loaded or not auth_config_loaded: |
| 711 logging.error("Failed to load host configuration.") |
| 712 return 1 |
| 713 else: |
| 714 need_auth_tokens = not auth_config_loaded |
| 715 need_register_host = not host_config_loaded |
| 716 # Outside the loop so user doesn't get asked twice. |
| 717 if need_register_host: |
| 718 host.ask_pin() |
| 719 elif options.new_pin or not host.is_pin_set(): |
| 720 host.ask_pin() |
| 721 host.save_config() |
| 722 running, pid = PidFile(pid_filename).check() |
| 723 if running and pid != 0: |
| 724 os.kill(pid, signal.SIGUSR1) |
| 725 print "The running instance has been updated with the new PIN." |
| 726 return 0 |
| 727 |
716 # The loop is to deal with the case of registering a new Host with | 728 # The loop is to deal with the case of registering a new Host with |
717 # previously-saved auth tokens (from a previous run of this script), which | 729 # previously-saved auth tokens (from a previous run of this script), which |
718 # may require re-prompting for username & password. | 730 # may require re-prompting for username & password. |
719 while True: | 731 while True: |
720 try: | 732 try: |
721 if need_auth_tokens: | 733 if need_auth_tokens: |
722 auth.generate_tokens() | 734 auth.generate_tokens() |
723 auth.save_config() | 735 auth.save_config() |
724 need_auth_tokens = False | 736 need_auth_tokens = False |
725 except Exception: | 737 except Exception: |
726 logging.error("Authentication failed") | 738 logging.error("Authentication failed") |
727 return 1 | 739 return 1 |
728 | 740 |
729 try: | 741 try: |
730 if register_host: | 742 if need_register_host: |
731 host.register() | 743 host.register() |
732 host.save_config() | 744 host.save_config() |
733 except urllib2.HTTPError, err: | 745 except urllib2.HTTPError, err: |
734 if err.getcode() == 401: | 746 if err.getcode() == 401: |
735 # Authentication failed - re-prompt for username & password. | 747 # Authentication failed - re-prompt for username & password. |
736 need_auth_tokens = True | 748 need_auth_tokens = True |
737 continue | 749 continue |
738 else: | 750 else: |
739 # Not an authentication error. | 751 # Not an authentication error. |
740 logging.error("Directory returned error: " + str(err)) | 752 logging.error("Directory returned error: " + str(err)) |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
835 logging.info("Host process terminated") | 847 logging.info("Host process terminated") |
836 desktop.host_proc = None | 848 desktop.host_proc = None |
837 | 849 |
838 # These exit-codes must match the ones used by the host. | 850 # These exit-codes must match the ones used by the host. |
839 # See remoting/host/constants.h. | 851 # See remoting/host/constants.h. |
840 # Delete the host or auth configuration depending on the returned error | 852 # Delete the host or auth configuration depending on the returned error |
841 # code, so the next time this script is run, a new configuration | 853 # code, so the next time this script is run, a new configuration |
842 # will be created and registered. | 854 # will be created and registered. |
843 if os.WEXITSTATUS(status) == 2: | 855 if os.WEXITSTATUS(status) == 2: |
844 logging.info("Host configuration is invalid - exiting.") | 856 logging.info("Host configuration is invalid - exiting.") |
845 os.remove(auth.config_file) | 857 try: |
846 os.remove(host.config_file) | 858 os.remove(host.config_file) |
| 859 os.remove(auth.config_file) |
| 860 except: |
| 861 pass |
847 return 0 | 862 return 0 |
848 elif os.WEXITSTATUS(status) == 3: | 863 elif os.WEXITSTATUS(status) == 3: |
849 logging.info("Host ID has been deleted - exiting.") | 864 logging.info("Host ID has been deleted - exiting.") |
850 os.remove(host.config_file) | 865 try: |
| 866 os.remove(host.config_file) |
| 867 except: |
| 868 pass |
851 return 0 | 869 return 0 |
852 elif os.WEXITSTATUS(status) == 4: | 870 elif os.WEXITSTATUS(status) == 4: |
853 logging.info("OAuth credentials are invalid - exiting.") | 871 logging.info("OAuth credentials are invalid - exiting.") |
854 os.remove(auth.config_file) | 872 try: |
| 873 os.remove(auth.config_file) |
| 874 except: |
| 875 pass |
855 return 0 | 876 return 0 |
856 | 877 |
857 if __name__ == "__main__": | 878 if __name__ == "__main__": |
858 logging.basicConfig(level=logging.DEBUG) | 879 logging.basicConfig(level=logging.DEBUG) |
859 sys.exit(main()) | 880 sys.exit(main()) |
OLD | NEW |