##// END OF EJS Templates
remove deleted profiles from cluster list
MinRK -
Show More
@@ -1,173 +1,161 b''
1 """Manage IPython.parallel clusters in the notebook.
1 """Manage IPython.parallel clusters in the notebook."""
2 2
3 Authors:
4
5 * Brian Granger
6 """
7
8 #-----------------------------------------------------------------------------
9 # Copyright (C) 2008-2011 The IPython Development Team
10 #
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
13 #-----------------------------------------------------------------------------
14
15 #-----------------------------------------------------------------------------
16 # Imports
17 #-----------------------------------------------------------------------------
3 # Copyright (c) IPython Development Team.
4 # Distributed under the terms of the Modified BSD License.
18 5
19 6 from tornado import web
20 7 from zmq.eventloop import ioloop
21 8
22 9 from IPython.config.configurable import LoggingConfigurable
23 10 from IPython.utils.traitlets import Dict, Instance, CFloat
24 11 from IPython.core.profileapp import list_profiles_in
25 12 from IPython.core.profiledir import ProfileDir
26 13 from IPython.utils import py3compat
27 14 from IPython.utils.path import get_ipython_dir
28 15
29 16
30 #-----------------------------------------------------------------------------
31 # Classes
32 #-----------------------------------------------------------------------------
33
34
35
36
37 17 class ClusterManager(LoggingConfigurable):
38 18
39 19 profiles = Dict()
40 20
41 21 delay = CFloat(1., config=True,
42 22 help="delay (in s) between starting the controller and the engines")
43 23
44 24 loop = Instance('zmq.eventloop.ioloop.IOLoop')
45 25 def _loop_default(self):
46 26 from zmq.eventloop.ioloop import IOLoop
47 27 return IOLoop.instance()
48 28
49 29 def build_launchers(self, profile_dir):
50 30 from IPython.parallel.apps.ipclusterapp import IPClusterStart
51 31
52 32 class DummyIPClusterStart(IPClusterStart):
53 33 """Dummy subclass to skip init steps that conflict with global app.
54 34
55 35 Instantiating and initializing this class should result in fully configured
56 36 launchers, but no other side effects or state.
57 37 """
58 38
59 39 def init_signal(self):
60 40 pass
61 41 def reinit_logging(self):
62 42 pass
63 43
64 44 starter = DummyIPClusterStart(log=self.log)
65 45 starter.initialize(['--profile-dir', profile_dir])
66 46 cl = starter.controller_launcher
67 47 esl = starter.engine_launcher
68 48 n = starter.n
69 49 return cl, esl, n
70 50
71 51 def get_profile_dir(self, name, path):
72 52 p = ProfileDir.find_profile_dir_by_name(path,name=name)
73 53 return p.location
74 54
75 55 def update_profiles(self):
76 56 """List all profiles in the ipython_dir and cwd.
77 57 """
58
59 stale = set(self.profiles)
78 60 for path in [get_ipython_dir(), py3compat.getcwd()]:
79 61 for profile in list_profiles_in(path):
62 if profile in stale:
63 stale.remove(profile)
80 64 pd = self.get_profile_dir(profile, path)
81 65 if profile not in self.profiles:
82 self.log.debug("Adding cluster profile '%s'" % profile)
66 self.log.debug("Adding cluster profile '%s'", profile)
83 67 self.profiles[profile] = {
84 68 'profile': profile,
85 69 'profile_dir': pd,
86 70 'status': 'stopped'
87 71 }
72 for profile in stale:
73 # remove profiles that no longer exist
74 self.log.debug("Profile '%s' no longer exists", profile)
75 self.profiles.pop(stale)
88 76
89 77 def list_profiles(self):
90 78 self.update_profiles()
91 79 # sorted list, but ensure that 'default' always comes first
92 80 default_first = lambda name: name if name != 'default' else ''
93 81 result = [self.profile_info(p) for p in sorted(self.profiles, key=default_first)]
94 82 return result
95 83
96 84 def check_profile(self, profile):
97 85 if profile not in self.profiles:
98 86 raise web.HTTPError(404, u'profile not found')
99 87
100 88 def profile_info(self, profile):
101 89 self.check_profile(profile)
102 90 result = {}
103 91 data = self.profiles.get(profile)
104 92 result['profile'] = profile
105 93 result['profile_dir'] = data['profile_dir']
106 94 result['status'] = data['status']
107 95 if 'n' in data:
108 96 result['n'] = data['n']
109 97 return result
110 98
111 99 def start_cluster(self, profile, n=None):
112 100 """Start a cluster for a given profile."""
113 101 self.check_profile(profile)
114 102 data = self.profiles[profile]
115 103 if data['status'] == 'running':
116 104 raise web.HTTPError(409, u'cluster already running')
117 105 cl, esl, default_n = self.build_launchers(data['profile_dir'])
118 106 n = n if n is not None else default_n
119 107 def clean_data():
120 108 data.pop('controller_launcher',None)
121 109 data.pop('engine_set_launcher',None)
122 110 data.pop('n',None)
123 111 data['status'] = 'stopped'
124 112 def engines_stopped(r):
125 113 self.log.debug('Engines stopped')
126 114 if cl.running:
127 115 cl.stop()
128 116 clean_data()
129 117 esl.on_stop(engines_stopped)
130 118 def controller_stopped(r):
131 119 self.log.debug('Controller stopped')
132 120 if esl.running:
133 121 esl.stop()
134 122 clean_data()
135 123 cl.on_stop(controller_stopped)
136 124
137 125 dc = ioloop.DelayedCallback(lambda: cl.start(), 0, self.loop)
138 126 dc.start()
139 127 dc = ioloop.DelayedCallback(lambda: esl.start(n), 1000*self.delay, self.loop)
140 128 dc.start()
141 129
142 130 self.log.debug('Cluster started')
143 131 data['controller_launcher'] = cl
144 132 data['engine_set_launcher'] = esl
145 133 data['n'] = n
146 134 data['status'] = 'running'
147 135 return self.profile_info(profile)
148 136
149 137 def stop_cluster(self, profile):
150 138 """Stop a cluster for a given profile."""
151 139 self.check_profile(profile)
152 140 data = self.profiles[profile]
153 141 if data['status'] == 'stopped':
154 142 raise web.HTTPError(409, u'cluster not running')
155 143 data = self.profiles[profile]
156 144 cl = data['controller_launcher']
157 145 esl = data['engine_set_launcher']
158 146 if cl.running:
159 147 cl.stop()
160 148 if esl.running:
161 149 esl.stop()
162 150 # Return a temp info dict, the real one is updated in the on_stop
163 151 # logic above.
164 152 result = {
165 153 'profile': data['profile'],
166 154 'profile_dir': data['profile_dir'],
167 155 'status': 'stopped'
168 156 }
169 157 return result
170 158
171 159 def stop_all_clusters(self):
172 160 for p in self.profiles.keys():
173 161 self.stop_cluster(p)
General Comments 0
You need to be logged in to leave comments. Login now