##// END OF EJS Templates
Added components to manage jobs/tasks for Win HPC job scheduler.
Brian Granger -
Show More
@@ -0,0 +1,229 b''
1 #!/usr/bin/env python
2 # encoding: utf-8
3 """
4 Job and task components for writing .xml files that the Windows HPC Server
5 2008 can use to start jobs.
6 """
7
8 #-----------------------------------------------------------------------------
9 # Copyright (C) 2008-2009 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 #-----------------------------------------------------------------------------
18
19 from __future__ import with_statement
20
21 import os
22 import re
23
24 from xml.etree import ElementTree as ET
25 from xml.dom import minidom
26
27 from IPython.core.component import Component
28 from IPython.external import Itpl
29 from IPython.utils.traitlets import (
30 Str, Int, List, Unicode, Instance,
31 Enum, Bool
32 )
33
34 #-----------------------------------------------------------------------------
35 # Job and Task Component
36 #-----------------------------------------------------------------------------
37
38
39 def as_str(value):
40 if isinstance(value, str):
41 return value
42 elif isinstance(value, bool):
43 if value:
44 return 'true'
45 else:
46 return 'false'
47 elif isinstance(value, (int, float)):
48 return repr(value)
49 else:
50 return value
51
52
53 def indent(elem, level=0):
54 i = "\n" + level*" "
55 if len(elem):
56 if not elem.text or not elem.text.strip():
57 elem.text = i + " "
58 if not elem.tail or not elem.tail.strip():
59 elem.tail = i
60 for elem in elem:
61 indent(elem, level+1)
62 if not elem.tail or not elem.tail.strip():
63 elem.tail = i
64 else:
65 if level and (not elem.tail or not elem.tail.strip()):
66 elem.tail = i
67
68
69 class WinHPCJob(Component):
70
71 job_id = Str('')
72 job_name = Str('MyJob', config=True)
73 min_cores = Int(1, config=True)
74 max_cores = Int(1, config=True)
75 min_sockets = Int(1, config=True)
76 max_sockets = Int(1, config=True)
77 min_nodes = Int(1, config=True)
78 max_nodes = Int(1, config=True)
79 unit_type = Str("Core", config=True)
80 auto_calculate_min = Bool(True, config=True)
81 auto_calculate_max = Bool(True, config=True)
82 run_until_canceled = Bool(False, config=True)
83 is_exclusive = Bool(False, config=True)
84 username = Str(os.environ.get('USERNAME', ''), config=True)
85 owner = Str('', config=True)
86 job_type = Str('Batch', config=True)
87 priority = Enum(('Lowest','BelowNormal','Normal','AboveNormal','Highest'),
88 default_value='Highest', config=True)
89 requested_nodes = Str('', config=True)
90 project = Str('IPython', config=True)
91 xmlns = Str('http://schemas.microsoft.com/HPCS2008/scheduler/')
92 version = Str("2.000")
93 tasks = List([])
94
95 def _username_changed(self, name, old, new):
96 self.owner = new
97
98 def _write_attr(self, root, attr, key):
99 s = as_str(getattr(self, attr, ''))
100 if s:
101 root.set(key, s)
102
103 def as_element(self):
104 # We have to add _A_ type things to get the right order than
105 # the MSFT XML parser expects.
106 root = ET.Element('Job')
107 self._write_attr(root, 'version', '_A_Version')
108 self._write_attr(root, 'job_name', '_B_Name')
109 self._write_attr(root, 'unit_type', '_C_UnitType')
110 self._write_attr(root, 'min_cores', '_D_MinCores')
111 self._write_attr(root, 'max_cores', '_E_MaxCores')
112 self._write_attr(root, 'min_sockets', '_F_MinSockets')
113 self._write_attr(root, 'max_sockets', '_G_MaxSockets')
114 self._write_attr(root, 'min_nodes', '_H_MinNodes')
115 self._write_attr(root, 'max_nodes', '_I_MaxNodes')
116 self._write_attr(root, 'run_until_canceled', '_J_RunUntilCanceled')
117 self._write_attr(root, 'is_exclusive', '_K_IsExclusive')
118 self._write_attr(root, 'username', '_L_UserName')
119 self._write_attr(root, 'job_type', '_M_JobType')
120 self._write_attr(root, 'priority', '_N_Priority')
121 self._write_attr(root, 'requested_nodes', '_O_RequestedNodes')
122 self._write_attr(root, 'auto_calculate_max', '_P_AutoCalculateMax')
123 self._write_attr(root, 'auto_calculate_min', '_Q_AutoCalculateMin')
124 self._write_attr(root, 'project', '_R_Project')
125 self._write_attr(root, 'owner', '_S_Owner')
126 self._write_attr(root, 'xmlns', '_T_xmlns')
127 dependencies = ET.SubElement(root, "Dependencies")
128 etasks = ET.SubElement(root, "Tasks")
129 for t in self.tasks:
130 etasks.append(t.as_element())
131 return root
132
133 def tostring(self):
134 """Return the string representation of the job description XML."""
135 root = self.as_element()
136 indent(root)
137 txt = ET.tostring(root, encoding="utf-8")
138 # Now remove the tokens used to order the attributes.
139 txt = re.sub(r'_[A-Z]_','',txt)
140 txt = '<?xml version="1.0" encoding="utf-8"?>\n' + txt
141 return txt
142
143 def write(self, filename):
144 """Write the XML job description to a file."""
145 txt = self.tostring()
146 with open(filename, 'w') as f:
147 f.write(txt)
148
149 def add_task(self, task):
150 """Add a task to the job.
151
152 Parameters
153 ----------
154 task : :class:`WinHPCTask`
155 The task object to add.
156 """
157 self.tasks.append(task)
158
159
160 class WinHPCTask(Component):
161
162 task_id = Str('')
163 task_name = Str('')
164 version = Str("2.000")
165 min_cores = Int(1, config=True)
166 max_cores = Int(1, config=True)
167 min_sockets = Int(1, config=True)
168 max_sockets = Int(1, config=True)
169 min_nodes = Int(1, config=True)
170 max_nodes = Int(1, config=True)
171 unit_type = Str("Core", config=True)
172 command_line = Str('', config=True)
173 work_directory = Str('', config=True)
174 is_rerunnaable = Bool(True, config=True)
175 std_out_file_path = Str('', config=True)
176 std_err_file_path = Str('', config=True)
177 is_parametric = Bool(False, config=True)
178 environment_variables = Instance(dict, args=())
179
180 def _write_attr(self, root, attr, key):
181 s = as_str(getattr(self, attr, ''))
182 if s:
183 root.set(key, s)
184
185 def as_element(self):
186 root = ET.Element('Task')
187 self._write_attr(root, 'version', '_A_Version')
188 self._write_attr(root, 'task_name', '_B_Name')
189 self._write_attr(root, 'min_cores', '_C_MinCores')
190 self._write_attr(root, 'max_cores', '_D_MaxCores')
191 self._write_attr(root, 'min_sockets', '_E_MinSockets')
192 self._write_attr(root, 'max_sockets', '_F_MaxSockets')
193 self._write_attr(root, 'min_nodes', '_G_MinNodes')
194 self._write_attr(root, 'max_nodes', '_H_MaxNodes')
195 self._write_attr(root, 'command_line', '_I_CommandLine')
196 self._write_attr(root, 'work_directory', '_J_WorkDirectory')
197 self._write_attr(root, 'is_rerunnaable', '_K_IsRerunnable')
198 self._write_attr(root, 'std_out_file_path', '_L_StdOutFilePath')
199 self._write_attr(root, 'std_err_file_path', '_M_StdErrFilePath')
200 self._write_attr(root, 'is_parametric', '_N_IsParametric')
201 self._write_attr(root, 'unit_type', '_O_UnitType')
202 root.append(self.get_env_vars())
203 return root
204
205 def get_env_vars(self):
206 env_vars = ET.Element('EnvironmentVariables')
207 for k, v in self.environment_variables.items():
208 variable = ET.SubElement(env_vars, "Variable")
209 name = ET.SubElement(variable, "Name")
210 name.text = k
211 value = ET.SubElement(variable, "Value")
212 value.text = v
213 return env_vars
214
215
216 # j = WinHPCJob(None)
217 # j.job_name = 'IPCluster'
218 # j.username = 'GNET\\bgranger'
219 # j.requested_nodes = 'GREEN'
220 #
221 # t = WinHPCTask(None)
222 # t.task_name = 'Controller'
223 # t.command_line = r"\\blue\domainusers$\bgranger\Python\Python25\Scripts\ipcontroller.exe --log-to-file -p default --log-level 10"
224 # t.work_directory = r"\\blue\domainusers$\bgranger\.ipython\cluster_default"
225 # t.std_out_file_path = 'controller-out.txt'
226 # t.std_err_file_path = 'controller-err.txt'
227 # t.environment_variables['PYTHONPATH'] = r"\\blue\domainusers$\bgranger\Python\Python25\Lib\site-packages"
228 # j.add_task(t)
229
General Comments 0
You need to be logged in to leave comments. Login now