sierra-research 1.3.6__py3-none-any.whl → 1.5.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (254) hide show
  1. sierra/__init__.py +3 -3
  2. sierra/core/__init__.py +3 -3
  3. sierra/core/batchroot.py +223 -0
  4. sierra/core/cmdline.py +681 -1057
  5. sierra/core/compare.py +11 -0
  6. sierra/core/config.py +96 -88
  7. sierra/core/engine.py +306 -0
  8. sierra/core/execenv.py +380 -0
  9. sierra/core/expdef.py +11 -0
  10. sierra/core/experiment/__init__.py +1 -0
  11. sierra/core/experiment/bindings.py +150 -101
  12. sierra/core/experiment/definition.py +414 -245
  13. sierra/core/experiment/spec.py +83 -85
  14. sierra/core/exproot.py +44 -0
  15. sierra/core/generators/__init__.py +10 -0
  16. sierra/core/generators/experiment.py +528 -0
  17. sierra/core/generators/generator_factory.py +138 -137
  18. sierra/core/graphs/__init__.py +23 -0
  19. sierra/core/graphs/bcbridge.py +94 -0
  20. sierra/core/graphs/heatmap.py +245 -324
  21. sierra/core/graphs/pathset.py +27 -0
  22. sierra/core/graphs/schema.py +77 -0
  23. sierra/core/graphs/stacked_line.py +341 -0
  24. sierra/core/graphs/summary_line.py +506 -0
  25. sierra/core/logging.py +3 -2
  26. sierra/core/models/__init__.py +3 -1
  27. sierra/core/models/info.py +19 -0
  28. sierra/core/models/interface.py +52 -122
  29. sierra/core/pipeline/__init__.py +2 -5
  30. sierra/core/pipeline/pipeline.py +228 -126
  31. sierra/core/pipeline/stage1/__init__.py +10 -0
  32. sierra/core/pipeline/stage1/pipeline_stage1.py +45 -31
  33. sierra/core/pipeline/stage2/__init__.py +10 -0
  34. sierra/core/pipeline/stage2/pipeline_stage2.py +8 -11
  35. sierra/core/pipeline/stage2/runner.py +401 -0
  36. sierra/core/pipeline/stage3/__init__.py +12 -0
  37. sierra/core/pipeline/stage3/gather.py +321 -0
  38. sierra/core/pipeline/stage3/pipeline_stage3.py +37 -84
  39. sierra/core/pipeline/stage4/__init__.py +12 -2
  40. sierra/core/pipeline/stage4/pipeline_stage4.py +36 -354
  41. sierra/core/pipeline/stage5/__init__.py +12 -0
  42. sierra/core/pipeline/stage5/pipeline_stage5.py +33 -208
  43. sierra/core/pipeline/yaml.py +48 -0
  44. sierra/core/plugin.py +529 -62
  45. sierra/core/proc.py +11 -0
  46. sierra/core/prod.py +11 -0
  47. sierra/core/ros1/__init__.py +5 -1
  48. sierra/core/ros1/callbacks.py +22 -21
  49. sierra/core/ros1/cmdline.py +59 -88
  50. sierra/core/ros1/generators.py +159 -175
  51. sierra/core/ros1/variables/__init__.py +3 -0
  52. sierra/core/ros1/variables/exp_setup.py +122 -116
  53. sierra/core/startup.py +106 -76
  54. sierra/core/stat_kernels.py +4 -5
  55. sierra/core/storage.py +13 -32
  56. sierra/core/trampoline.py +30 -0
  57. sierra/core/types.py +116 -71
  58. sierra/core/utils.py +103 -106
  59. sierra/core/variables/__init__.py +1 -1
  60. sierra/core/variables/base_variable.py +12 -17
  61. sierra/core/variables/batch_criteria.py +387 -481
  62. sierra/core/variables/builtin.py +135 -0
  63. sierra/core/variables/exp_setup.py +19 -39
  64. sierra/core/variables/population_size.py +72 -76
  65. sierra/core/variables/variable_density.py +44 -68
  66. sierra/core/vector.py +1 -1
  67. sierra/main.py +256 -88
  68. sierra/plugins/__init__.py +119 -0
  69. sierra/plugins/compare/__init__.py +14 -0
  70. sierra/plugins/compare/graphs/__init__.py +19 -0
  71. sierra/plugins/compare/graphs/cmdline.py +120 -0
  72. sierra/plugins/compare/graphs/comparator.py +291 -0
  73. sierra/plugins/compare/graphs/inter_controller.py +531 -0
  74. sierra/plugins/compare/graphs/inter_scenario.py +297 -0
  75. sierra/plugins/compare/graphs/namecalc.py +53 -0
  76. sierra/plugins/compare/graphs/outputroot.py +73 -0
  77. sierra/plugins/compare/graphs/plugin.py +147 -0
  78. sierra/plugins/compare/graphs/preprocess.py +172 -0
  79. sierra/plugins/compare/graphs/schema.py +37 -0
  80. sierra/plugins/engine/__init__.py +14 -0
  81. sierra/plugins/engine/argos/__init__.py +18 -0
  82. sierra/plugins/{platform → engine}/argos/cmdline.py +144 -151
  83. sierra/plugins/{platform/argos/variables → engine/argos/generators}/__init__.py +5 -0
  84. sierra/plugins/engine/argos/generators/engine.py +394 -0
  85. sierra/plugins/engine/argos/plugin.py +393 -0
  86. sierra/plugins/{platform/argos/generators → engine/argos/variables}/__init__.py +5 -0
  87. sierra/plugins/engine/argos/variables/arena_shape.py +183 -0
  88. sierra/plugins/engine/argos/variables/cameras.py +240 -0
  89. sierra/plugins/engine/argos/variables/constant_density.py +112 -0
  90. sierra/plugins/engine/argos/variables/exp_setup.py +82 -0
  91. sierra/plugins/{platform → engine}/argos/variables/physics_engines.py +83 -87
  92. sierra/plugins/engine/argos/variables/population_constant_density.py +178 -0
  93. sierra/plugins/engine/argos/variables/population_size.py +115 -0
  94. sierra/plugins/engine/argos/variables/population_variable_density.py +123 -0
  95. sierra/plugins/engine/argos/variables/rendering.py +108 -0
  96. sierra/plugins/engine/ros1gazebo/__init__.py +18 -0
  97. sierra/plugins/engine/ros1gazebo/cmdline.py +175 -0
  98. sierra/plugins/{platform/ros1robot → engine/ros1gazebo}/generators/__init__.py +5 -0
  99. sierra/plugins/engine/ros1gazebo/generators/engine.py +125 -0
  100. sierra/plugins/engine/ros1gazebo/plugin.py +404 -0
  101. sierra/plugins/engine/ros1gazebo/variables/__init__.py +15 -0
  102. sierra/plugins/engine/ros1gazebo/variables/population_size.py +214 -0
  103. sierra/plugins/engine/ros1robot/__init__.py +18 -0
  104. sierra/plugins/engine/ros1robot/cmdline.py +159 -0
  105. sierra/plugins/{platform/ros1gazebo → engine/ros1robot}/generators/__init__.py +4 -0
  106. sierra/plugins/engine/ros1robot/generators/engine.py +95 -0
  107. sierra/plugins/engine/ros1robot/plugin.py +410 -0
  108. sierra/plugins/{hpc/local → engine/ros1robot/variables}/__init__.py +5 -0
  109. sierra/plugins/engine/ros1robot/variables/population_size.py +146 -0
  110. sierra/plugins/execenv/__init__.py +11 -0
  111. sierra/plugins/execenv/hpc/__init__.py +18 -0
  112. sierra/plugins/execenv/hpc/adhoc/__init__.py +18 -0
  113. sierra/plugins/execenv/hpc/adhoc/cmdline.py +30 -0
  114. sierra/plugins/execenv/hpc/adhoc/plugin.py +131 -0
  115. sierra/plugins/execenv/hpc/cmdline.py +137 -0
  116. sierra/plugins/execenv/hpc/local/__init__.py +18 -0
  117. sierra/plugins/execenv/hpc/local/cmdline.py +31 -0
  118. sierra/plugins/execenv/hpc/local/plugin.py +145 -0
  119. sierra/plugins/execenv/hpc/pbs/__init__.py +18 -0
  120. sierra/plugins/execenv/hpc/pbs/cmdline.py +30 -0
  121. sierra/plugins/execenv/hpc/pbs/plugin.py +121 -0
  122. sierra/plugins/execenv/hpc/slurm/__init__.py +18 -0
  123. sierra/plugins/execenv/hpc/slurm/cmdline.py +30 -0
  124. sierra/plugins/execenv/hpc/slurm/plugin.py +133 -0
  125. sierra/plugins/execenv/prefectserver/__init__.py +18 -0
  126. sierra/plugins/execenv/prefectserver/cmdline.py +66 -0
  127. sierra/plugins/execenv/prefectserver/dockerremote/__init__.py +18 -0
  128. sierra/plugins/execenv/prefectserver/dockerremote/cmdline.py +66 -0
  129. sierra/plugins/execenv/prefectserver/dockerremote/plugin.py +132 -0
  130. sierra/plugins/execenv/prefectserver/flow.py +66 -0
  131. sierra/plugins/execenv/prefectserver/local/__init__.py +18 -0
  132. sierra/plugins/execenv/prefectserver/local/cmdline.py +29 -0
  133. sierra/plugins/execenv/prefectserver/local/plugin.py +133 -0
  134. sierra/plugins/{hpc/adhoc → execenv/robot}/__init__.py +1 -0
  135. sierra/plugins/execenv/robot/turtlebot3/__init__.py +18 -0
  136. sierra/plugins/execenv/robot/turtlebot3/plugin.py +204 -0
  137. sierra/plugins/expdef/__init__.py +14 -0
  138. sierra/plugins/expdef/json/__init__.py +14 -0
  139. sierra/plugins/expdef/json/plugin.py +504 -0
  140. sierra/plugins/expdef/xml/__init__.py +14 -0
  141. sierra/plugins/expdef/xml/plugin.py +386 -0
  142. sierra/{core/hpc → plugins/proc}/__init__.py +1 -1
  143. sierra/plugins/proc/collate/__init__.py +15 -0
  144. sierra/plugins/proc/collate/cmdline.py +47 -0
  145. sierra/plugins/proc/collate/plugin.py +271 -0
  146. sierra/plugins/proc/compress/__init__.py +18 -0
  147. sierra/plugins/proc/compress/cmdline.py +47 -0
  148. sierra/plugins/proc/compress/plugin.py +123 -0
  149. sierra/plugins/proc/decompress/__init__.py +18 -0
  150. sierra/plugins/proc/decompress/plugin.py +96 -0
  151. sierra/plugins/proc/imagize/__init__.py +15 -0
  152. sierra/plugins/proc/imagize/cmdline.py +49 -0
  153. sierra/plugins/proc/imagize/plugin.py +270 -0
  154. sierra/plugins/proc/modelrunner/__init__.py +16 -0
  155. sierra/plugins/proc/modelrunner/plugin.py +250 -0
  156. sierra/plugins/proc/statistics/__init__.py +15 -0
  157. sierra/plugins/proc/statistics/cmdline.py +64 -0
  158. sierra/plugins/proc/statistics/plugin.py +390 -0
  159. sierra/plugins/{hpc → prod}/__init__.py +1 -0
  160. sierra/plugins/prod/graphs/__init__.py +18 -0
  161. sierra/plugins/prod/graphs/cmdline.py +269 -0
  162. sierra/plugins/prod/graphs/collate.py +279 -0
  163. sierra/plugins/prod/graphs/inter/__init__.py +13 -0
  164. sierra/plugins/prod/graphs/inter/generate.py +83 -0
  165. sierra/plugins/prod/graphs/inter/heatmap.py +86 -0
  166. sierra/plugins/prod/graphs/inter/line.py +134 -0
  167. sierra/plugins/prod/graphs/intra/__init__.py +15 -0
  168. sierra/plugins/prod/graphs/intra/generate.py +202 -0
  169. sierra/plugins/prod/graphs/intra/heatmap.py +74 -0
  170. sierra/plugins/prod/graphs/intra/line.py +114 -0
  171. sierra/plugins/prod/graphs/plugin.py +103 -0
  172. sierra/plugins/prod/graphs/targets.py +63 -0
  173. sierra/plugins/prod/render/__init__.py +18 -0
  174. sierra/plugins/prod/render/cmdline.py +72 -0
  175. sierra/plugins/prod/render/plugin.py +282 -0
  176. sierra/plugins/storage/__init__.py +5 -0
  177. sierra/plugins/storage/arrow/__init__.py +18 -0
  178. sierra/plugins/storage/arrow/plugin.py +38 -0
  179. sierra/plugins/storage/csv/__init__.py +9 -0
  180. sierra/plugins/storage/csv/plugin.py +12 -5
  181. sierra/version.py +3 -2
  182. sierra_research-1.5.0.dist-info/METADATA +238 -0
  183. sierra_research-1.5.0.dist-info/RECORD +186 -0
  184. {sierra_research-1.3.6.dist-info → sierra_research-1.5.0.dist-info}/WHEEL +1 -2
  185. sierra/core/experiment/xml.py +0 -454
  186. sierra/core/generators/controller_generator_parser.py +0 -34
  187. sierra/core/generators/exp_creator.py +0 -351
  188. sierra/core/generators/exp_generators.py +0 -142
  189. sierra/core/graphs/scatterplot2D.py +0 -109
  190. sierra/core/graphs/stacked_line_graph.py +0 -249
  191. sierra/core/graphs/stacked_surface_graph.py +0 -220
  192. sierra/core/graphs/summary_line_graph.py +0 -369
  193. sierra/core/hpc/cmdline.py +0 -142
  194. sierra/core/models/graphs.py +0 -87
  195. sierra/core/pipeline/stage2/exp_runner.py +0 -286
  196. sierra/core/pipeline/stage3/imagizer.py +0 -149
  197. sierra/core/pipeline/stage3/run_collator.py +0 -317
  198. sierra/core/pipeline/stage3/statistics_calculator.py +0 -478
  199. sierra/core/pipeline/stage4/graph_collator.py +0 -319
  200. sierra/core/pipeline/stage4/inter_exp_graph_generator.py +0 -240
  201. sierra/core/pipeline/stage4/intra_exp_graph_generator.py +0 -317
  202. sierra/core/pipeline/stage4/model_runner.py +0 -168
  203. sierra/core/pipeline/stage4/rendering.py +0 -283
  204. sierra/core/pipeline/stage4/yaml_config_loader.py +0 -103
  205. sierra/core/pipeline/stage5/inter_scenario_comparator.py +0 -328
  206. sierra/core/pipeline/stage5/intra_scenario_comparator.py +0 -989
  207. sierra/core/platform.py +0 -493
  208. sierra/core/plugin_manager.py +0 -369
  209. sierra/core/root_dirpath_generator.py +0 -241
  210. sierra/plugins/hpc/adhoc/plugin.py +0 -125
  211. sierra/plugins/hpc/local/plugin.py +0 -81
  212. sierra/plugins/hpc/pbs/__init__.py +0 -9
  213. sierra/plugins/hpc/pbs/plugin.py +0 -126
  214. sierra/plugins/hpc/slurm/__init__.py +0 -9
  215. sierra/plugins/hpc/slurm/plugin.py +0 -130
  216. sierra/plugins/platform/__init__.py +0 -9
  217. sierra/plugins/platform/argos/__init__.py +0 -9
  218. sierra/plugins/platform/argos/generators/platform_generators.py +0 -383
  219. sierra/plugins/platform/argos/plugin.py +0 -337
  220. sierra/plugins/platform/argos/variables/arena_shape.py +0 -145
  221. sierra/plugins/platform/argos/variables/cameras.py +0 -243
  222. sierra/plugins/platform/argos/variables/constant_density.py +0 -136
  223. sierra/plugins/platform/argos/variables/exp_setup.py +0 -113
  224. sierra/plugins/platform/argos/variables/population_constant_density.py +0 -175
  225. sierra/plugins/platform/argos/variables/population_size.py +0 -102
  226. sierra/plugins/platform/argos/variables/population_variable_density.py +0 -132
  227. sierra/plugins/platform/argos/variables/rendering.py +0 -104
  228. sierra/plugins/platform/ros1gazebo/__init__.py +0 -9
  229. sierra/plugins/platform/ros1gazebo/cmdline.py +0 -213
  230. sierra/plugins/platform/ros1gazebo/generators/platform_generators.py +0 -137
  231. sierra/plugins/platform/ros1gazebo/plugin.py +0 -335
  232. sierra/plugins/platform/ros1gazebo/variables/__init__.py +0 -10
  233. sierra/plugins/platform/ros1gazebo/variables/population_size.py +0 -204
  234. sierra/plugins/platform/ros1robot/__init__.py +0 -9
  235. sierra/plugins/platform/ros1robot/cmdline.py +0 -175
  236. sierra/plugins/platform/ros1robot/generators/platform_generators.py +0 -112
  237. sierra/plugins/platform/ros1robot/plugin.py +0 -373
  238. sierra/plugins/platform/ros1robot/variables/__init__.py +0 -10
  239. sierra/plugins/platform/ros1robot/variables/population_size.py +0 -146
  240. sierra/plugins/robot/__init__.py +0 -9
  241. sierra/plugins/robot/turtlebot3/__init__.py +0 -9
  242. sierra/plugins/robot/turtlebot3/plugin.py +0 -194
  243. sierra_research-1.3.6.data/data/share/man/man1/sierra-cli.1 +0 -2349
  244. sierra_research-1.3.6.data/data/share/man/man7/sierra-examples.7 +0 -488
  245. sierra_research-1.3.6.data/data/share/man/man7/sierra-exec-envs.7 +0 -331
  246. sierra_research-1.3.6.data/data/share/man/man7/sierra-glossary.7 +0 -285
  247. sierra_research-1.3.6.data/data/share/man/man7/sierra-platforms.7 +0 -358
  248. sierra_research-1.3.6.data/data/share/man/man7/sierra-usage.7 +0 -725
  249. sierra_research-1.3.6.data/data/share/man/man7/sierra.7 +0 -78
  250. sierra_research-1.3.6.dist-info/METADATA +0 -500
  251. sierra_research-1.3.6.dist-info/RECORD +0 -133
  252. sierra_research-1.3.6.dist-info/top_level.txt +0 -1
  253. {sierra_research-1.3.6.dist-info → sierra_research-1.5.0.dist-info}/entry_points.txt +0 -0
  254. {sierra_research-1.3.6.dist-info → sierra_research-1.5.0.dist-info/licenses}/LICENSE +0 -0
sierra/core/platform.py DELETED
@@ -1,493 +0,0 @@
1
- # Copyright 2021 John Harwell, All rights reserved.
2
- #
3
- # SPDX-License-Identifier: MIT
4
- """Terminal interface for pltaform plugins.
5
-
6
- Classes for generating the commands to run :term:`experiments <Batch
7
- Experiment>` on multiple :term:`platforms <Platform>` using multiple execution
8
- methods.
9
-
10
- """
11
-
12
- # Core packages
13
- import os
14
- import typing as tp
15
- import subprocess
16
- import shutil
17
- import argparse
18
- import socket
19
- import logging
20
- import pwd
21
- import re
22
- import pathlib
23
-
24
- # 3rd party packages
25
- import implements
26
- import netifaces
27
-
28
- # Project packages
29
- import sierra.core.plugin_manager as pm
30
- from sierra.core import config, types, utils
31
- from sierra.core.experiment import bindings
32
- import sierra.core.variables.batch_criteria as bc
33
-
34
-
35
- class CmdlineParserGenerator():
36
- """
37
- Dispatcher to generate additional platform-dependent cmdline arguments.
38
- """
39
-
40
- def __init__(self, platform: str) -> None:
41
- module = pm.pipeline.get_plugin_module(platform)
42
- self.platform = module.CmdlineParserGenerator()
43
-
44
- def __call__(self) -> argparse.ArgumentParser:
45
- return self.platform()
46
-
47
-
48
- @implements.implements(bindings.IExpRunShellCmdsGenerator)
49
- class ExpRunShellCmdsGenerator():
50
- """Dispatcher for shell cmd generation for an :term:`Experimental Run`.
51
-
52
- Dispatches generation to the selected platform and execution environment.
53
- Called during stage 1 to add shell commands which should be run immediately
54
- before and after the shell command to actually execute a single
55
- :term:`Experimental Run` to the commands file to be fed to whatever the tool
56
- a given execution environment environment uses to run cmds (e.g., GNU
57
- parallel).
58
-
59
- """
60
-
61
- def __init__(self,
62
- cmdopts: types.Cmdopts,
63
- criteria: bc.BatchCriteria,
64
- n_robots: int,
65
- exp_num: int) -> None:
66
- self.cmdopts = cmdopts
67
- self.criteria = criteria
68
- module = pm.pipeline.get_plugin_module(self.cmdopts['platform'])
69
-
70
- if hasattr(module, 'ExpRunShellCmdsGenerator'):
71
- self.platform = module.ExpRunShellCmdsGenerator(self.cmdopts,
72
- self.criteria,
73
- n_robots,
74
- exp_num)
75
- else:
76
- self.platform = None
77
-
78
- module = pm.pipeline.get_plugin_module(self.cmdopts['exec_env'])
79
- if hasattr(module, 'ExpRunShellCmdsGenerator'):
80
- self.env = module.ExpRunShellCmdsGenerator(self.cmdopts,
81
- self.criteria,
82
- n_robots,
83
- exp_num)
84
- else:
85
- self.env = None
86
-
87
- def pre_run_cmds(self,
88
- host: str,
89
- input_fpath: pathlib.Path,
90
- run_num: int) -> tp.List[types.ShellCmdSpec]:
91
- cmds = []
92
- if self.platform:
93
- cmds.extend(self.platform.pre_run_cmds(host, input_fpath, run_num))
94
-
95
- if self.env:
96
- cmds.extend(self.env.pre_run_cmds(host, input_fpath, run_num))
97
-
98
- return cmds
99
-
100
- def exec_run_cmds(self,
101
- host: str,
102
- input_fpath: pathlib.Path,
103
- run_num: int) -> tp.List[types.ShellCmdSpec]:
104
- cmds = []
105
-
106
- if self.platform:
107
- cmds.extend(self.platform.exec_run_cmds(host, input_fpath, run_num))
108
-
109
- if self.env:
110
- cmds.extend(self.env.exec_run_cmds(host, input_fpath, run_num))
111
-
112
- return cmds
113
-
114
- def post_run_cmds(self, host: str) -> tp.List[types.ShellCmdSpec]:
115
- cmds = []
116
-
117
- if self.platform:
118
- cmds.extend(self.platform.post_run_cmds(host))
119
-
120
- if self.env:
121
- cmds.extend(self.env.post_run_cmds(host))
122
-
123
- return cmds
124
-
125
-
126
- @implements.implements(bindings.IExpShellCmdsGenerator)
127
- class ExpShellCmdsGenerator():
128
- """Dispatcher for shell cmd generation for an :term:`Experiment`.
129
-
130
- Dispatches generation to the selected platform and execution environment.
131
- Called during stage 2 to run shell commands immediately before running a
132
- given :term:`Experiment`, to run shell commands to actually run the
133
- experiment, and to run shell commands immediately after the experiment
134
- finishes.
135
-
136
- """
137
-
138
- def __init__(self,
139
- cmdopts: types.Cmdopts,
140
- exp_num: int) -> None:
141
- self.cmdopts = cmdopts
142
- self.logger = logging.getLogger(__name__)
143
-
144
- module = pm.pipeline.get_plugin_module(self.cmdopts['platform'])
145
- if hasattr(module, 'ExpShellCmdsGenerator'):
146
- self.logger.debug(("Skipping generating experiment shell commands "
147
- "for --platform=%s"),
148
- self.cmdopts['platform'])
149
-
150
- self.platform = module.ExpShellCmdsGenerator(self.cmdopts,
151
- exp_num)
152
- else:
153
- self.platform = None
154
-
155
- module = pm.pipeline.get_plugin_module(self.cmdopts['exec_env'])
156
- if hasattr(module, 'ExpShellCmdsGenerator'):
157
- self.logger.debug(("Skipping generating experiment shell commands "
158
- "for --exec-env=%s"),
159
- self.cmdopts['exec_env'])
160
-
161
- self.env = module.ExpShellCmdsGenerator(self.cmdopts,
162
- exp_num)
163
- else:
164
- self.env = None
165
-
166
- def pre_exp_cmds(self) -> tp.List[types.ShellCmdSpec]:
167
- cmds = []
168
-
169
- if self.platform:
170
- cmds.extend(self.platform.pre_exp_cmds())
171
-
172
- if self.env:
173
- cmds.extend(self.env.pre_exp_cmds())
174
-
175
- return cmds
176
-
177
- def exec_exp_cmds(self, exec_opts: types.StrDict) -> tp.List[types.ShellCmdSpec]:
178
- cmds = []
179
-
180
- if self.platform:
181
- cmds.extend(self.platform.exec_exp_cmds(exec_opts))
182
-
183
- if self.env:
184
- cmds.extend(self.env.exec_exp_cmds(exec_opts))
185
-
186
- return cmds
187
-
188
- def post_exp_cmds(self) -> tp.List[types.ShellCmdSpec]:
189
- cmds = []
190
-
191
- if self.platform:
192
- cmds.extend(self.platform.post_exp_cmds())
193
-
194
- if self.env:
195
- cmds.extend(self.env.post_exp_cmds())
196
-
197
- return cmds
198
-
199
-
200
- class ParsedCmdlineConfigurer():
201
- """Dispatcher for configuring the cmdopts dictionary.
202
-
203
- Dispatches configuring to the selected platform and execution environment.
204
- Called before the pipeline starts to add new/modify existing cmdline
205
- arguments after initial parsing.
206
-
207
- """
208
-
209
- def __init__(self,
210
- platform: str,
211
- exec_env: str) -> None:
212
- self.platform = platform
213
- self.exec_env = exec_env
214
- self.logger = logging.getLogger(__name__)
215
-
216
- module = pm.pipeline.get_plugin_module(self.platform)
217
- if hasattr(module, 'ParsedCmdlineConfigurer'):
218
- self.platformg = module.ParsedCmdlineConfigurer(exec_env)
219
- else:
220
- self.platformg = None
221
- self.logger.debug("Skipping configuring cmdline from --platform=%s",
222
- self.platform)
223
-
224
- module = pm.pipeline.get_plugin_module(self.exec_env)
225
- if hasattr(module, 'ParsedCmdlineConfigurer'):
226
- self.envg = module.ParsedCmdlineConfigurer(exec_env)
227
- else:
228
- self.envg = None
229
- self.logger.debug("Skipping configuring cmdline from --exec-env=%s",
230
- self.exec_env)
231
-
232
- def __call__(self, args: argparse.Namespace) -> argparse.Namespace:
233
- # Configure for selected execution enivornment first, to check for
234
- # low-level details.
235
- args.__dict__['exec_env'] = self.exec_env
236
-
237
- if self.envg:
238
- self.envg(args)
239
-
240
- # Configure for selected platform
241
- args.__dict__['platform'] = self.platform
242
-
243
- if self.platformg:
244
- self.platformg(args)
245
-
246
- return args
247
-
248
-
249
- class ExpConfigurer():
250
- """Perform platform-specific configuration for an :term:`Experimental Run`.
251
-
252
- For things can do programmatically (i.e., without needing a shell). This
253
- usually is things like creating directories, etc. Called at the end of
254
- stage 1 during for each experimental run.
255
-
256
- """
257
-
258
- def __init__(self, cmdopts: types.Cmdopts) -> None:
259
- self.cmdopts = cmdopts
260
- module = pm.pipeline.get_plugin_module(cmdopts['platform'])
261
- self.platform = module.ExpConfigurer(self.cmdopts)
262
-
263
- def for_exp_run(self,
264
- exp_input_root: pathlib.Path,
265
- run_output_dir: pathlib.Path) -> None:
266
- self.platform.for_exp_run(exp_input_root, run_output_dir)
267
-
268
- def for_exp(self, exp_input_root: pathlib.Path) -> None:
269
- self.platform.for_exp(exp_input_root)
270
-
271
- def cmdfile_paradigm(self) -> str:
272
- return self.platform.cmdfile_paradigm()
273
-
274
-
275
- class ExecEnvChecker():
276
- """Base class for verifying execution environments before running experiments.
277
-
278
- Platforms and/or execution environments needed to perform verification
279
- should derive from this class to use the common functionality present in it.
280
-
281
- """
282
-
283
- @staticmethod
284
- def parse_nodefile(nodefile: str) -> tp.List[types.ParsedNodefileSpec]:
285
- ret = []
286
-
287
- with utils.utf8open(nodefile, 'r') as f:
288
- lines = f.readlines()
289
-
290
- for line in lines:
291
- if parsed := ExecEnvChecker._parse_nodefile_line(line):
292
- ret.append(parsed)
293
-
294
- return ret
295
-
296
- @staticmethod
297
- def _parse_nodefile_line(line: str) -> tp.Optional[types.ParsedNodefileSpec]:
298
- # Line starts with a comment--no parsing needed
299
- comment_re = r"^#"
300
- if res := re.search(comment_re, line):
301
- return None
302
-
303
- cores_re = r"^[0-9]+/"
304
- if res := re.search(cores_re, line):
305
- cores = int(line.split('/')[0])
306
- ssh = line.split('/')[1]
307
- else:
308
- cores = 1
309
- ssh = line
310
-
311
- identifier_re = r"[a-zA-Z0-9_.:]+"
312
- port_re = r"ssh -p\s*([0-9]+)"
313
- username_at_host_re = f"({identifier_re})+@({identifier_re})"
314
- port_and_username_at_host_re = port_re + r"\*s" + username_at_host_re
315
- port_and_hostname_re = port_re + rf"\s+({identifier_re})"
316
-
317
- if res := re.search(port_and_username_at_host_re, ssh):
318
- # They specified the port AND 'username@host'
319
- port = int(res.group(1))
320
- login = res.group(2)
321
- hostname = res.group(3)
322
- elif res := re.search(port_and_hostname_re, ssh):
323
- # They only specified the port and hostname
324
- port = int(res.group(1))
325
- hostname = res.group(2)
326
- login = pwd.getpwuid(os.getuid())[0]
327
- elif res := re.search(username_at_host_re, ssh):
328
- # They only specified 'username@host'
329
- port = 22
330
- login = res.group(1)
331
- hostname = res.group(2)
332
- elif res := re.search(identifier_re, ssh):
333
- # They only specified the hostname
334
- port = 22
335
- login = pwd.getpwuid(os.getuid())[0]
336
- hostname = res.group(0)
337
- else:
338
- raise ValueError(f"Bad ssh/hostname spec {ssh}")
339
-
340
- return types.ParsedNodefileSpec(hostname=hostname,
341
- n_cores=cores,
342
- login=login,
343
- port=port)
344
-
345
- def __init__(self, cmdopts: types.Cmdopts):
346
- self.cmdopts = cmdopts
347
- self.exec_env = self.cmdopts['exec_env']
348
- self.platform = self.cmdopts['platform']
349
- self.logger = logging.getLogger(__name__)
350
-
351
- def __call__(self) -> None:
352
- module = pm.pipeline.get_plugin_module(self.cmdopts['platform'])
353
- if hasattr(module, 'ExecEnvChecker'):
354
- module.ExecEnvChecker(self.cmdopts)()
355
-
356
- module = pm.pipeline.get_plugin_module(self.cmdopts['exec_env'])
357
- if hasattr(module, 'ExecEnvChecker'):
358
- module.ExecEnvChecker(self.cmdopts)()
359
-
360
- def check_connectivity(self,
361
- login: str,
362
- hostname: str,
363
- port: int,
364
- host_type: str) -> None:
365
- self.logger.info("Checking connectivity to %s", hostname)
366
- ssh_diag = f"{host_type},port={port} via {login}@{hostname}"
367
- nc_diag = f"{host_type},port={port} via {hostname}"
368
-
369
- if self.cmdopts['online_check_method'] == 'ping+ssh':
370
- try:
371
- self.logger.debug("Attempt to ping %s, type=%s",
372
- hostname,
373
- host_type)
374
- timeout = config.kPlatform['ping_timeout']
375
- subprocess.run(f"ping -c 3 -W {timeout} {hostname}",
376
- shell=True,
377
- check=True,
378
- stdout=subprocess.PIPE,
379
- stderr=subprocess.PIPE)
380
- except subprocess.CalledProcessError:
381
- self.logger.fatal("Unable to ping %s, type=%s",
382
- hostname,
383
- host_type)
384
- raise
385
- self.logger.debug("%s is alive, type=%s", hostname, host_type)
386
- elif self.cmdopts['online_check_method'] == 'nc+ssh':
387
- try:
388
- self.logger.debug("Check for ssh tunnel to %s", nc_diag)
389
- timeout = config.kPlatform['ping_timeout']
390
- subprocess.run(f"nc -z {hostname} {port}",
391
- shell=True,
392
- check=True,
393
- stdout=subprocess.PIPE,
394
- stderr=subprocess.PIPE)
395
- except subprocess.CalledProcessError:
396
- self.logger.fatal("No ssh tunnel to %s", nc_diag)
397
- raise
398
- self.logger.debug("ssh tunnel to %s alive", nc_diag)
399
-
400
- try:
401
-
402
- self.logger.debug("Verify ssh to %s", ssh_diag)
403
- subprocess.run((f"ssh -p{port} "
404
- "-o PasswordAuthentication=no "
405
- "-o StrictHostKeyChecking=no "
406
- "-o BatchMode=yes "
407
- f"{login}@{hostname} exit"),
408
- shell=True,
409
- check=True,
410
- stdout=subprocess.PIPE,
411
- stderr=subprocess.PIPE)
412
- except subprocess.CalledProcessError:
413
- self.logger.fatal("Unable to connect to %s", ssh_diag)
414
- raise
415
- self.logger.info("%s@%s online", host_type, hostname)
416
-
417
- def check_for_simulator(self, name: str):
418
- shellname = get_executable_shellname(name)
419
-
420
- version_cmd = f'{shellname} -v'
421
- self.logger.debug("Check version for '%s' via '%s'",
422
- shellname,
423
- version_cmd)
424
-
425
- if shutil.which(shellname):
426
- res = subprocess.run(version_cmd,
427
- stdout=subprocess.PIPE,
428
- stderr=subprocess.PIPE,
429
- shell=True)
430
- return res
431
- else:
432
- error = "Bad --exec-env '{0}' for platform '{1}': cannot find '{2}'".format(self.exec_env,
433
- self.platform,
434
- name)
435
- raise RuntimeError(error)
436
-
437
-
438
- def get_executable_shellname(base: str) -> str:
439
- if 'SIERRA_ARCH' in os.environ:
440
- arch = os.environ['SIERRA_ARCH']
441
- return f'{base}-{arch}'
442
- else:
443
- return base
444
-
445
-
446
- def get_free_port() -> int:
447
- """Determine a free port using sockets.
448
-
449
- From
450
- https://stackoverflow.com/questions/44875422/how-to-pick-a-free-port-for-a-subprocess
451
-
452
- Because of TCP TIME_WAIT, close()d ports are still unusable for a few
453
- minutes, which will leave plenty of time for SIERRA to assign all unique
454
- ports to processes during stage 2.
455
-
456
- """
457
- s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
458
- s.bind(('', 0)) # bind to port 0 -> OS allocates free port
459
- port = s.getsockname()[1]
460
- s.close()
461
- return port
462
-
463
-
464
- def get_local_ip():
465
- """
466
- Get the local IP address of the SIERRA host machine.
467
- """
468
- active = []
469
- for iface in netifaces.interfaces():
470
- # Active=has a normal IP address (that's what AF_INET means)
471
- if socket.AF_INET in netifaces.ifaddresses(iface):
472
- active.append(iface)
473
-
474
- active = list(filter('lo'.__ne__, active))
475
-
476
- if len(active) > 1:
477
- logging.critical(("SIERRA host machine has > 1 non-loopback IP addresses"
478
- "/network interfaces--SIERRA may select the wrong "
479
- "one: %s"), active)
480
- s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
481
- s.connect(("8.8.8.8", 80))
482
- return s.getsockname()[0]
483
-
484
-
485
- __api__ = [
486
- 'CmdlineParserGenerator',
487
- 'ExpRunShellCmdsGenerator',
488
- 'ExpShellCmdsGenerator',
489
- 'ParsedCmdlineConfigurer',
490
- 'ExpRunShellCmdsGenerator',
491
- 'ExpShellCmdsGenerator',
492
- 'ExecEnvChecker',
493
- ]