sierra-research 1.3.11__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.
- sierra/__init__.py +3 -3
- sierra/core/__init__.py +3 -3
- sierra/core/batchroot.py +223 -0
- sierra/core/cmdline.py +681 -1057
- sierra/core/compare.py +11 -0
- sierra/core/config.py +96 -88
- sierra/core/engine.py +306 -0
- sierra/core/execenv.py +380 -0
- sierra/core/expdef.py +11 -0
- sierra/core/experiment/__init__.py +1 -0
- sierra/core/experiment/bindings.py +150 -101
- sierra/core/experiment/definition.py +414 -245
- sierra/core/experiment/spec.py +83 -85
- sierra/core/exproot.py +44 -0
- sierra/core/generators/__init__.py +10 -0
- sierra/core/generators/experiment.py +528 -0
- sierra/core/generators/generator_factory.py +138 -137
- sierra/core/graphs/__init__.py +23 -0
- sierra/core/graphs/bcbridge.py +94 -0
- sierra/core/graphs/heatmap.py +245 -324
- sierra/core/graphs/pathset.py +27 -0
- sierra/core/graphs/schema.py +77 -0
- sierra/core/graphs/stacked_line.py +341 -0
- sierra/core/graphs/summary_line.py +506 -0
- sierra/core/logging.py +3 -2
- sierra/core/models/__init__.py +3 -1
- sierra/core/models/info.py +19 -0
- sierra/core/models/interface.py +52 -122
- sierra/core/pipeline/__init__.py +2 -5
- sierra/core/pipeline/pipeline.py +228 -126
- sierra/core/pipeline/stage1/__init__.py +10 -0
- sierra/core/pipeline/stage1/pipeline_stage1.py +45 -31
- sierra/core/pipeline/stage2/__init__.py +10 -0
- sierra/core/pipeline/stage2/pipeline_stage2.py +8 -11
- sierra/core/pipeline/stage2/runner.py +401 -0
- sierra/core/pipeline/stage3/__init__.py +12 -0
- sierra/core/pipeline/stage3/gather.py +321 -0
- sierra/core/pipeline/stage3/pipeline_stage3.py +37 -84
- sierra/core/pipeline/stage4/__init__.py +12 -2
- sierra/core/pipeline/stage4/pipeline_stage4.py +36 -354
- sierra/core/pipeline/stage5/__init__.py +12 -0
- sierra/core/pipeline/stage5/pipeline_stage5.py +33 -208
- sierra/core/pipeline/yaml.py +48 -0
- sierra/core/plugin.py +529 -62
- sierra/core/proc.py +11 -0
- sierra/core/prod.py +11 -0
- sierra/core/ros1/__init__.py +5 -1
- sierra/core/ros1/callbacks.py +22 -21
- sierra/core/ros1/cmdline.py +59 -88
- sierra/core/ros1/generators.py +159 -175
- sierra/core/ros1/variables/__init__.py +3 -0
- sierra/core/ros1/variables/exp_setup.py +122 -116
- sierra/core/startup.py +106 -76
- sierra/core/stat_kernels.py +4 -5
- sierra/core/storage.py +13 -32
- sierra/core/trampoline.py +30 -0
- sierra/core/types.py +116 -71
- sierra/core/utils.py +103 -106
- sierra/core/variables/__init__.py +1 -1
- sierra/core/variables/base_variable.py +12 -17
- sierra/core/variables/batch_criteria.py +387 -481
- sierra/core/variables/builtin.py +135 -0
- sierra/core/variables/exp_setup.py +19 -39
- sierra/core/variables/population_size.py +72 -76
- sierra/core/variables/variable_density.py +44 -68
- sierra/core/vector.py +1 -1
- sierra/main.py +256 -88
- sierra/plugins/__init__.py +119 -0
- sierra/plugins/compare/__init__.py +14 -0
- sierra/plugins/compare/graphs/__init__.py +19 -0
- sierra/plugins/compare/graphs/cmdline.py +120 -0
- sierra/plugins/compare/graphs/comparator.py +291 -0
- sierra/plugins/compare/graphs/inter_controller.py +531 -0
- sierra/plugins/compare/graphs/inter_scenario.py +297 -0
- sierra/plugins/compare/graphs/namecalc.py +53 -0
- sierra/plugins/compare/graphs/outputroot.py +73 -0
- sierra/plugins/compare/graphs/plugin.py +147 -0
- sierra/plugins/compare/graphs/preprocess.py +172 -0
- sierra/plugins/compare/graphs/schema.py +37 -0
- sierra/plugins/engine/__init__.py +14 -0
- sierra/plugins/engine/argos/__init__.py +18 -0
- sierra/plugins/{platform → engine}/argos/cmdline.py +144 -151
- sierra/plugins/{platform/argos/variables → engine/argos/generators}/__init__.py +5 -0
- sierra/plugins/engine/argos/generators/engine.py +394 -0
- sierra/plugins/engine/argos/plugin.py +393 -0
- sierra/plugins/{platform/argos/generators → engine/argos/variables}/__init__.py +5 -0
- sierra/plugins/engine/argos/variables/arena_shape.py +183 -0
- sierra/plugins/engine/argos/variables/cameras.py +240 -0
- sierra/plugins/engine/argos/variables/constant_density.py +112 -0
- sierra/plugins/engine/argos/variables/exp_setup.py +82 -0
- sierra/plugins/{platform → engine}/argos/variables/physics_engines.py +83 -87
- sierra/plugins/engine/argos/variables/population_constant_density.py +178 -0
- sierra/plugins/engine/argos/variables/population_size.py +115 -0
- sierra/plugins/engine/argos/variables/population_variable_density.py +123 -0
- sierra/plugins/engine/argos/variables/rendering.py +108 -0
- sierra/plugins/engine/ros1gazebo/__init__.py +18 -0
- sierra/plugins/engine/ros1gazebo/cmdline.py +175 -0
- sierra/plugins/{platform/ros1robot → engine/ros1gazebo}/generators/__init__.py +5 -0
- sierra/plugins/engine/ros1gazebo/generators/engine.py +125 -0
- sierra/plugins/engine/ros1gazebo/plugin.py +404 -0
- sierra/plugins/engine/ros1gazebo/variables/__init__.py +15 -0
- sierra/plugins/engine/ros1gazebo/variables/population_size.py +214 -0
- sierra/plugins/engine/ros1robot/__init__.py +18 -0
- sierra/plugins/engine/ros1robot/cmdline.py +159 -0
- sierra/plugins/{platform/ros1gazebo → engine/ros1robot}/generators/__init__.py +4 -0
- sierra/plugins/engine/ros1robot/generators/engine.py +95 -0
- sierra/plugins/engine/ros1robot/plugin.py +410 -0
- sierra/plugins/{hpc/local → engine/ros1robot/variables}/__init__.py +5 -0
- sierra/plugins/engine/ros1robot/variables/population_size.py +146 -0
- sierra/plugins/execenv/__init__.py +11 -0
- sierra/plugins/execenv/hpc/__init__.py +18 -0
- sierra/plugins/execenv/hpc/adhoc/__init__.py +18 -0
- sierra/plugins/execenv/hpc/adhoc/cmdline.py +30 -0
- sierra/plugins/execenv/hpc/adhoc/plugin.py +131 -0
- sierra/plugins/execenv/hpc/cmdline.py +137 -0
- sierra/plugins/execenv/hpc/local/__init__.py +18 -0
- sierra/plugins/execenv/hpc/local/cmdline.py +31 -0
- sierra/plugins/execenv/hpc/local/plugin.py +145 -0
- sierra/plugins/execenv/hpc/pbs/__init__.py +18 -0
- sierra/plugins/execenv/hpc/pbs/cmdline.py +30 -0
- sierra/plugins/execenv/hpc/pbs/plugin.py +121 -0
- sierra/plugins/execenv/hpc/slurm/__init__.py +18 -0
- sierra/plugins/execenv/hpc/slurm/cmdline.py +30 -0
- sierra/plugins/execenv/hpc/slurm/plugin.py +133 -0
- sierra/plugins/execenv/prefectserver/__init__.py +18 -0
- sierra/plugins/execenv/prefectserver/cmdline.py +66 -0
- sierra/plugins/execenv/prefectserver/dockerremote/__init__.py +18 -0
- sierra/plugins/execenv/prefectserver/dockerremote/cmdline.py +66 -0
- sierra/plugins/execenv/prefectserver/dockerremote/plugin.py +132 -0
- sierra/plugins/execenv/prefectserver/flow.py +66 -0
- sierra/plugins/execenv/prefectserver/local/__init__.py +18 -0
- sierra/plugins/execenv/prefectserver/local/cmdline.py +29 -0
- sierra/plugins/execenv/prefectserver/local/plugin.py +133 -0
- sierra/plugins/{hpc/adhoc → execenv/robot}/__init__.py +1 -0
- sierra/plugins/execenv/robot/turtlebot3/__init__.py +18 -0
- sierra/plugins/execenv/robot/turtlebot3/plugin.py +204 -0
- sierra/plugins/expdef/__init__.py +14 -0
- sierra/plugins/expdef/json/__init__.py +14 -0
- sierra/plugins/expdef/json/plugin.py +504 -0
- sierra/plugins/expdef/xml/__init__.py +14 -0
- sierra/plugins/expdef/xml/plugin.py +386 -0
- sierra/{core/hpc → plugins/proc}/__init__.py +1 -1
- sierra/plugins/proc/collate/__init__.py +15 -0
- sierra/plugins/proc/collate/cmdline.py +47 -0
- sierra/plugins/proc/collate/plugin.py +271 -0
- sierra/plugins/proc/compress/__init__.py +18 -0
- sierra/plugins/proc/compress/cmdline.py +47 -0
- sierra/plugins/proc/compress/plugin.py +123 -0
- sierra/plugins/proc/decompress/__init__.py +18 -0
- sierra/plugins/proc/decompress/plugin.py +96 -0
- sierra/plugins/proc/imagize/__init__.py +15 -0
- sierra/plugins/proc/imagize/cmdline.py +49 -0
- sierra/plugins/proc/imagize/plugin.py +270 -0
- sierra/plugins/proc/modelrunner/__init__.py +16 -0
- sierra/plugins/proc/modelrunner/plugin.py +250 -0
- sierra/plugins/proc/statistics/__init__.py +15 -0
- sierra/plugins/proc/statistics/cmdline.py +64 -0
- sierra/plugins/proc/statistics/plugin.py +390 -0
- sierra/plugins/{hpc → prod}/__init__.py +1 -0
- sierra/plugins/prod/graphs/__init__.py +18 -0
- sierra/plugins/prod/graphs/cmdline.py +269 -0
- sierra/plugins/prod/graphs/collate.py +279 -0
- sierra/plugins/prod/graphs/inter/__init__.py +13 -0
- sierra/plugins/prod/graphs/inter/generate.py +83 -0
- sierra/plugins/prod/graphs/inter/heatmap.py +86 -0
- sierra/plugins/prod/graphs/inter/line.py +134 -0
- sierra/plugins/prod/graphs/intra/__init__.py +15 -0
- sierra/plugins/prod/graphs/intra/generate.py +202 -0
- sierra/plugins/prod/graphs/intra/heatmap.py +74 -0
- sierra/plugins/prod/graphs/intra/line.py +114 -0
- sierra/plugins/prod/graphs/plugin.py +103 -0
- sierra/plugins/prod/graphs/targets.py +63 -0
- sierra/plugins/prod/render/__init__.py +18 -0
- sierra/plugins/prod/render/cmdline.py +72 -0
- sierra/plugins/prod/render/plugin.py +282 -0
- sierra/plugins/storage/__init__.py +5 -0
- sierra/plugins/storage/arrow/__init__.py +18 -0
- sierra/plugins/storage/arrow/plugin.py +38 -0
- sierra/plugins/storage/csv/__init__.py +9 -0
- sierra/plugins/storage/csv/plugin.py +12 -5
- sierra/version.py +3 -2
- sierra_research-1.5.0.dist-info/METADATA +238 -0
- sierra_research-1.5.0.dist-info/RECORD +186 -0
- {sierra_research-1.3.11.dist-info → sierra_research-1.5.0.dist-info}/WHEEL +1 -2
- sierra/core/experiment/xml.py +0 -454
- sierra/core/generators/controller_generator_parser.py +0 -34
- sierra/core/generators/exp_creator.py +0 -351
- sierra/core/generators/exp_generators.py +0 -142
- sierra/core/graphs/scatterplot2D.py +0 -109
- sierra/core/graphs/stacked_line_graph.py +0 -251
- sierra/core/graphs/stacked_surface_graph.py +0 -220
- sierra/core/graphs/summary_line_graph.py +0 -371
- sierra/core/hpc/cmdline.py +0 -142
- sierra/core/models/graphs.py +0 -87
- sierra/core/pipeline/stage2/exp_runner.py +0 -286
- sierra/core/pipeline/stage3/imagizer.py +0 -149
- sierra/core/pipeline/stage3/run_collator.py +0 -317
- sierra/core/pipeline/stage3/statistics_calculator.py +0 -478
- sierra/core/pipeline/stage4/graph_collator.py +0 -320
- sierra/core/pipeline/stage4/inter_exp_graph_generator.py +0 -240
- sierra/core/pipeline/stage4/intra_exp_graph_generator.py +0 -317
- sierra/core/pipeline/stage4/model_runner.py +0 -168
- sierra/core/pipeline/stage4/rendering.py +0 -283
- sierra/core/pipeline/stage4/yaml_config_loader.py +0 -103
- sierra/core/pipeline/stage5/inter_scenario_comparator.py +0 -328
- sierra/core/pipeline/stage5/intra_scenario_comparator.py +0 -989
- sierra/core/platform.py +0 -493
- sierra/core/plugin_manager.py +0 -369
- sierra/core/root_dirpath_generator.py +0 -241
- sierra/plugins/hpc/adhoc/plugin.py +0 -125
- sierra/plugins/hpc/local/plugin.py +0 -81
- sierra/plugins/hpc/pbs/__init__.py +0 -9
- sierra/plugins/hpc/pbs/plugin.py +0 -126
- sierra/plugins/hpc/slurm/__init__.py +0 -9
- sierra/plugins/hpc/slurm/plugin.py +0 -130
- sierra/plugins/platform/__init__.py +0 -9
- sierra/plugins/platform/argos/__init__.py +0 -9
- sierra/plugins/platform/argos/generators/platform_generators.py +0 -383
- sierra/plugins/platform/argos/plugin.py +0 -337
- sierra/plugins/platform/argos/variables/arena_shape.py +0 -145
- sierra/plugins/platform/argos/variables/cameras.py +0 -243
- sierra/plugins/platform/argos/variables/constant_density.py +0 -136
- sierra/plugins/platform/argos/variables/exp_setup.py +0 -113
- sierra/plugins/platform/argos/variables/population_constant_density.py +0 -175
- sierra/plugins/platform/argos/variables/population_size.py +0 -102
- sierra/plugins/platform/argos/variables/population_variable_density.py +0 -132
- sierra/plugins/platform/argos/variables/rendering.py +0 -104
- sierra/plugins/platform/ros1gazebo/__init__.py +0 -9
- sierra/plugins/platform/ros1gazebo/cmdline.py +0 -213
- sierra/plugins/platform/ros1gazebo/generators/platform_generators.py +0 -137
- sierra/plugins/platform/ros1gazebo/plugin.py +0 -335
- sierra/plugins/platform/ros1gazebo/variables/__init__.py +0 -10
- sierra/plugins/platform/ros1gazebo/variables/population_size.py +0 -204
- sierra/plugins/platform/ros1robot/__init__.py +0 -9
- sierra/plugins/platform/ros1robot/cmdline.py +0 -175
- sierra/plugins/platform/ros1robot/generators/platform_generators.py +0 -112
- sierra/plugins/platform/ros1robot/plugin.py +0 -373
- sierra/plugins/platform/ros1robot/variables/__init__.py +0 -10
- sierra/plugins/platform/ros1robot/variables/population_size.py +0 -146
- sierra/plugins/robot/__init__.py +0 -9
- sierra/plugins/robot/turtlebot3/__init__.py +0 -9
- sierra/plugins/robot/turtlebot3/plugin.py +0 -194
- sierra_research-1.3.11.data/data/share/man/man1/sierra-cli.1 +0 -2349
- sierra_research-1.3.11.data/data/share/man/man7/sierra-examples.7 +0 -508
- sierra_research-1.3.11.data/data/share/man/man7/sierra-exec-envs.7 +0 -331
- sierra_research-1.3.11.data/data/share/man/man7/sierra-glossary.7 +0 -285
- sierra_research-1.3.11.data/data/share/man/man7/sierra-platforms.7 +0 -358
- sierra_research-1.3.11.data/data/share/man/man7/sierra-usage.7 +0 -729
- sierra_research-1.3.11.data/data/share/man/man7/sierra.7 +0 -78
- sierra_research-1.3.11.dist-info/METADATA +0 -492
- sierra_research-1.3.11.dist-info/RECORD +0 -133
- sierra_research-1.3.11.dist-info/top_level.txt +0 -1
- {sierra_research-1.3.11.dist-info → sierra_research-1.5.0.dist-info}/entry_points.txt +0 -0
- {sierra_research-1.3.11.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
|
-
]
|