Show More
@@ -60,7 +60,7 from IPython.utils.text import EvalFormatter | |||||
60 | from IPython.utils.traitlets import ( |
|
60 | from IPython.utils.traitlets import ( | |
61 | Any, Integer, CFloat, List, Unicode, Dict, Instance, HasTraits, |
|
61 | Any, Integer, CFloat, List, Unicode, Dict, Instance, HasTraits, | |
62 | ) |
|
62 | ) | |
63 | from IPython.utils.path import get_ipython_module_path |
|
63 | from IPython.utils.path import get_ipython_module_path, get_home_dir | |
64 | from IPython.utils.process import find_cmd, pycmd2argv, FindCmdError |
|
64 | from IPython.utils.process import find_cmd, pycmd2argv, FindCmdError | |
65 |
|
65 | |||
66 | from .win32support import forward_read_events |
|
66 | from .win32support import forward_read_events | |
@@ -217,16 +217,12 class BaseLauncher(LoggingConfigurable): | |||||
217 |
|
217 | |||
218 | class ClusterAppMixin(HasTraits): |
|
218 | class ClusterAppMixin(HasTraits): | |
219 | """MixIn for cluster args as traits""" |
|
219 | """MixIn for cluster args as traits""" | |
220 | cluster_args = List([]) |
|
|||
221 | profile_dir=Unicode('') |
|
220 | profile_dir=Unicode('') | |
222 | cluster_id=Unicode('') |
|
221 | cluster_id=Unicode('') | |
223 | def _profile_dir_changed(self, name, old, new): |
|
222 | ||
224 | self.cluster_args = [] |
|
223 | @property | |
225 | if self.profile_dir: |
|
224 | def cluster_args(self): | |
226 | self.cluster_args.extend(['--profile-dir', self.profile_dir]) |
|
225 | return ['--profile-dir', self.profile_dir, '--cluster-id', self.cluster_id] | |
227 | if self.cluster_id: |
|
|||
228 | self.cluster_args.extend(['--cluster-id', self.cluster_id]) |
|
|||
229 | _cluster_id_changed = _profile_dir_changed |
|
|||
230 |
|
226 | |||
231 | class ControllerMixin(ClusterAppMixin): |
|
227 | class ControllerMixin(ClusterAppMixin): | |
232 | controller_cmd = List(ipcontroller_cmd_argv, config=True, |
|
228 | controller_cmd = List(ipcontroller_cmd_argv, config=True, | |
@@ -243,6 +239,7 class EngineMixin(ClusterAppMixin): | |||||
243 | help="command-line arguments to pass to ipengine" |
|
239 | help="command-line arguments to pass to ipengine" | |
244 | ) |
|
240 | ) | |
245 |
|
241 | |||
|
242 | ||||
246 | #----------------------------------------------------------------------------- |
|
243 | #----------------------------------------------------------------------------- | |
247 | # Local process launchers |
|
244 | # Local process launchers | |
248 | #----------------------------------------------------------------------------- |
|
245 | #----------------------------------------------------------------------------- | |
@@ -563,6 +560,8 class SSHLauncher(LocalProcessLauncher): | |||||
563 | help="command for starting ssh") |
|
560 | help="command for starting ssh") | |
564 | ssh_args = List(['-tt'], config=True, |
|
561 | ssh_args = List(['-tt'], config=True, | |
565 | help="args to pass to ssh") |
|
562 | help="args to pass to ssh") | |
|
563 | scp_cmd = List(['scp'], config=True, | |||
|
564 | help="command for sending files") | |||
566 | program = List(['date'], |
|
565 | program = List(['date'], | |
567 | help="Program to launch via ssh") |
|
566 | help="Program to launch via ssh") | |
568 | program_args = List([], |
|
567 | program_args = List([], | |
@@ -573,6 +572,10 class SSHLauncher(LocalProcessLauncher): | |||||
573 | help="username for ssh") |
|
572 | help="username for ssh") | |
574 | location = Unicode('', config=True, |
|
573 | location = Unicode('', config=True, | |
575 | help="user@hostname location for ssh in one setting") |
|
574 | help="user@hostname location for ssh in one setting") | |
|
575 | to_fetch = List([], config=True, | |||
|
576 | help="List of (remote, local) files to fetch after starting") | |||
|
577 | to_send = List([], config=True, | |||
|
578 | help="List of (local, remote) files to send before starting") | |||
576 |
|
579 | |||
577 | def _hostname_changed(self, name, old, new): |
|
580 | def _hostname_changed(self, name, old, new): | |
578 | if self.user: |
|
581 | if self.user: | |
@@ -587,13 +590,56 class SSHLauncher(LocalProcessLauncher): | |||||
587 | return self.ssh_cmd + self.ssh_args + [self.location] + \ |
|
590 | return self.ssh_cmd + self.ssh_args + [self.location] + \ | |
588 | self.program + self.program_args |
|
591 | self.program + self.program_args | |
589 |
|
592 | |||
|
593 | def _send_file(self, local, remote): | |||
|
594 | """send a single file""" | |||
|
595 | remote = "%s:%s" % (self.location, remote) | |||
|
596 | for i in range(10): | |||
|
597 | if not os.path.exists(local): | |||
|
598 | self.log.debug("waiting for %s" % local) | |||
|
599 | time.sleep(1) | |||
|
600 | else: | |||
|
601 | break | |||
|
602 | self.log.info("sending %s to %s", local, remote) | |||
|
603 | check_output(self.scp_cmd + [local, remote]) | |||
|
604 | ||||
|
605 | def send_files(self): | |||
|
606 | """send our files (called before start)""" | |||
|
607 | if not self.to_send: | |||
|
608 | return | |||
|
609 | for local_file, remote_file in self.to_send: | |||
|
610 | self._send_file(local_file, remote_file) | |||
|
611 | ||||
|
612 | def _fetch_file(self, remote, local): | |||
|
613 | """fetch a single file""" | |||
|
614 | full_remote = "%s:%s" % (self.location, remote) | |||
|
615 | self.log.info("fetching %s from %s", local, full_remote) | |||
|
616 | for i in range(10): | |||
|
617 | # wait up to 10s for remote file to exist | |||
|
618 | check = check_output(self.ssh_cmd + self.ssh_args + \ | |||
|
619 | [self.location, 'test -e', remote, "&& echo 'yes' || echo 'no'"]) | |||
|
620 | check = check.strip() | |||
|
621 | if check == 'no': | |||
|
622 | time.sleep(1) | |||
|
623 | elif check == 'yes': | |||
|
624 | break | |||
|
625 | check_output(self.scp_cmd + [full_remote, local]) | |||
|
626 | ||||
|
627 | def fetch_files(self): | |||
|
628 | """fetch remote files (called after start)""" | |||
|
629 | if not self.to_fetch: | |||
|
630 | return | |||
|
631 | for remote_file, local_file in self.to_fetch: | |||
|
632 | self._fetch_file(remote_file, local_file) | |||
|
633 | ||||
590 | def start(self, hostname=None, user=None): |
|
634 | def start(self, hostname=None, user=None): | |
591 | if hostname is not None: |
|
635 | if hostname is not None: | |
592 | self.hostname = hostname |
|
636 | self.hostname = hostname | |
593 | if user is not None: |
|
637 | if user is not None: | |
594 | self.user = user |
|
638 | self.user = user | |
595 |
|
639 | |||
596 | return super(SSHLauncher, self).start() |
|
640 | self.send_files() | |
|
641 | super(SSHLauncher, self).start() | |||
|
642 | self.fetch_files() | |||
597 |
|
643 | |||
598 | def signal(self, sig): |
|
644 | def signal(self, sig): | |
599 | if self.state == 'running': |
|
645 | if self.state == 'running': | |
@@ -601,13 +647,43 class SSHLauncher(LocalProcessLauncher): | |||||
601 | self.process.stdin.write('~.') |
|
647 | self.process.stdin.write('~.') | |
602 | self.process.stdin.flush() |
|
648 | self.process.stdin.flush() | |
603 |
|
649 | |||
|
650 | class SSHClusterLauncher(SSHLauncher): | |||
604 |
|
651 | |||
|
652 | remote_profile_dir = Unicode('', config=True, | |||
|
653 | help="""The remote profile_dir to use. | |||
605 |
|
654 | |||
606 | class SSHControllerLauncher(SSHLauncher, ControllerMixin): |
|
655 | If not specified, use calling profile, stripping out possible leading homedir. | |
|
656 | """) | |||
|
657 | ||||
|
658 | def _remote_profie_dir_default(self): | |||
|
659 | """turns /home/you/.ipython/profile_foo into .ipython/profile_foo | |||
|
660 | """ | |||
|
661 | home = get_home_dir() | |||
|
662 | if not home.endswith('/'): | |||
|
663 | home = home+'/' | |||
|
664 | ||||
|
665 | if self.profile_dir.startswith(home): | |||
|
666 | return self.profile_dir[len(home):] | |||
|
667 | else: | |||
|
668 | return self.profile_dir | |||
|
669 | ||||
|
670 | def _cluster_id_changed(self, name, old, new): | |||
|
671 | if new: | |||
|
672 | raise ValueError("cluster id not supported by SSH launchers") | |||
|
673 | ||||
|
674 | @property | |||
|
675 | def cluster_args(self): | |||
|
676 | return ['--profile-dir', self.remote_profile_dir] | |||
|
677 | ||||
|
678 | class SSHControllerLauncher(SSHClusterLauncher, ControllerMixin): | |||
607 |
|
679 | |||
608 | # alias back to *non-configurable* program[_args] for use in find_args() |
|
680 | # alias back to *non-configurable* program[_args] for use in find_args() | |
609 | # this way all Controller/EngineSetLaunchers have the same form, rather |
|
681 | # this way all Controller/EngineSetLaunchers have the same form, rather | |
610 | # than *some* having `program_args` and others `controller_args` |
|
682 | # than *some* having `program_args` and others `controller_args` | |
|
683 | ||||
|
684 | def _controller_cmd_default(self): | |||
|
685 | return ['ipcontroller'] | |||
|
686 | ||||
611 | @property |
|
687 | @property | |
612 | def program(self): |
|
688 | def program(self): | |
613 | return self.controller_cmd |
|
689 | return self.controller_cmd | |
@@ -616,12 +692,22 class SSHControllerLauncher(SSHLauncher, ControllerMixin): | |||||
616 | def program_args(self): |
|
692 | def program_args(self): | |
617 | return self.cluster_args + self.controller_args |
|
693 | return self.cluster_args + self.controller_args | |
618 |
|
694 | |||
|
695 | def _to_fetch_default(self): | |||
|
696 | return [ | |||
|
697 | (os.path.join(self.remote_profile_dir, 'security', cf), | |||
|
698 | os.path.join(self.profile_dir, 'security', cf),) | |||
|
699 | for cf in ('ipcontroller-client.json', 'ipcontroller-engine.json') | |||
|
700 | ] | |||
619 |
|
701 | |||
620 | class SSHEngineLauncher(SSHLauncher, EngineMixin): |
|
702 | class SSHEngineLauncher(SSHClusterLauncher, EngineMixin): | |
621 |
|
703 | |||
622 | # alias back to *non-configurable* program[_args] for use in find_args() |
|
704 | # alias back to *non-configurable* program[_args] for use in find_args() | |
623 | # this way all Controller/EngineSetLaunchers have the same form, rather |
|
705 | # this way all Controller/EngineSetLaunchers have the same form, rather | |
624 | # than *some* having `program_args` and others `controller_args` |
|
706 | # than *some* having `program_args` and others `controller_args` | |
|
707 | ||||
|
708 | def _engine_cmd_default(self): | |||
|
709 | return ['ipengine'] | |||
|
710 | ||||
625 | @property |
|
711 | @property | |
626 | def program(self): |
|
712 | def program(self): | |
627 | return self.engine_cmd |
|
713 | return self.engine_cmd | |
@@ -630,6 +716,13 class SSHEngineLauncher(SSHLauncher, EngineMixin): | |||||
630 | def program_args(self): |
|
716 | def program_args(self): | |
631 | return self.cluster_args + self.engine_args |
|
717 | return self.cluster_args + self.engine_args | |
632 |
|
718 | |||
|
719 | def _to_send_default(self): | |||
|
720 | return [ | |||
|
721 | (os.path.join(self.profile_dir, 'security', cf), | |||
|
722 | os.path.join(self.remote_profile_dir, 'security', cf)) | |||
|
723 | for cf in ('ipcontroller-client.json', 'ipcontroller-engine.json') | |||
|
724 | ] | |||
|
725 | ||||
633 |
|
726 | |||
634 | class SSHEngineSetLauncher(LocalEngineSetLauncher): |
|
727 | class SSHEngineSetLauncher(LocalEngineSetLauncher): | |
635 | launcher_class = SSHEngineLauncher |
|
728 | launcher_class = SSHEngineLauncher | |
@@ -669,6 +762,9 class SSHEngineSetLauncher(LocalEngineSetLauncher): | |||||
669 | el = self.launcher_class(work_dir=self.work_dir, config=self.config, log=self.log, |
|
762 | el = self.launcher_class(work_dir=self.work_dir, config=self.config, log=self.log, | |
670 | profile_dir=self.profile_dir, cluster_id=self.cluster_id, |
|
763 | profile_dir=self.profile_dir, cluster_id=self.cluster_id, | |
671 | ) |
|
764 | ) | |
|
765 | if i > 0: | |||
|
766 | # only send files for the first engine on each host | |||
|
767 | el.to_send = [] | |||
672 |
|
768 | |||
673 | # Copy the engine args over to each engine launcher. |
|
769 | # Copy the engine args over to each engine launcher. | |
674 | el.engine_cmd = self.engine_cmd |
|
770 | el.engine_cmd = self.engine_cmd | |
@@ -681,6 +777,35 class SSHEngineSetLauncher(LocalEngineSetLauncher): | |||||
681 | return dlist |
|
777 | return dlist | |
682 |
|
778 | |||
683 |
|
779 | |||
|
780 | class SSHProxyEngineSetLauncher(SSHClusterLauncher): | |||
|
781 | """Launcher for calling | |||
|
782 | `ipcluster engines` on a remote machine. | |||
|
783 | ||||
|
784 | Requires that remote profile is already configured. | |||
|
785 | """ | |||
|
786 | ||||
|
787 | n = Integer() | |||
|
788 | ipcluster_cmd = List(['ipcluster'], config=True) | |||
|
789 | ||||
|
790 | @property | |||
|
791 | def program(self): | |||
|
792 | return self.ipcluster_cmd + ['engines'] | |||
|
793 | ||||
|
794 | @property | |||
|
795 | def program_args(self): | |||
|
796 | return ['-n', str(self.n), '--profile-dir', self.remote_profile_dir] | |||
|
797 | ||||
|
798 | def _to_send_default(self): | |||
|
799 | return [ | |||
|
800 | (os.path.join(self.profile_dir, 'security', cf), | |||
|
801 | os.path.join(self.remote_profile_dir, 'security', cf)) | |||
|
802 | for cf in ('ipcontroller-client.json', 'ipcontroller-engine.json') | |||
|
803 | ] | |||
|
804 | ||||
|
805 | def start(self, n): | |||
|
806 | self.n = n | |||
|
807 | super(SSHProxyEngineSetLauncher, self).start() | |||
|
808 | ||||
684 |
|
809 | |||
685 | #----------------------------------------------------------------------------- |
|
810 | #----------------------------------------------------------------------------- | |
686 | # Windows HPC Server 2008 scheduler launchers |
|
811 | # Windows HPC Server 2008 scheduler launchers |
General Comments 0
You need to be logged in to leave comments.
Login now