lsst-ctrl-execute 28.2025.500__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.
@@ -0,0 +1,230 @@
1
+ #!/usr/bin/env python
2
+
3
+ #
4
+ # LSST Data Management System
5
+ # Copyright 2008-2016 LSST Corporation.
6
+ #
7
+ # This product includes software developed by the
8
+ # LSST Project (http://www.lsst.org/).
9
+ #
10
+ # This program is free software: you can redistribute it and/or modify
11
+ # it under the terms of the GNU General Public License as published by
12
+ # the Free Software Foundation, either version 3 of the License, or
13
+ # (at your option) any later version.
14
+ #
15
+ # This program is distributed in the hope that it will be useful,
16
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
17
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
+ # GNU General Public License for more details.
19
+ #
20
+ # You should have received a copy of the LSST License Statement and
21
+ # the GNU General Public License along with this program. If not,
22
+ # see <http://www.lsstcorp.org/LegalNotices/>.
23
+ #
24
+
25
+ import argparse
26
+
27
+
28
+ class AllocatorParser:
29
+ """An argument parser for node allocation requests.
30
+
31
+ Parameters
32
+ ----------
33
+ basename : `str`
34
+ The name used to identify the running program
35
+ """
36
+
37
+ def __init__(self, basename):
38
+ """Construct an AllocatorParser
39
+ @param argv: list containing the command line arguments
40
+ @return: the parser options and remaining arguments
41
+ """
42
+
43
+ self.defaults = {}
44
+ self.args = self.parseArgs(basename)
45
+
46
+ def parseArgs(self, basename) -> argparse.Namespace:
47
+ """Parse command line, and test for required arguments
48
+
49
+ Parameters
50
+ ----------
51
+ argv: `list`
52
+ list of strings containing the command line arguments
53
+
54
+ Returns
55
+ -------
56
+ The parser options and remaining arguments
57
+ """
58
+
59
+ parser = argparse.ArgumentParser(prog=basename)
60
+ parser.add_argument(
61
+ "platform", type=str, default="s3df", help="node allocation platform"
62
+ )
63
+ parser.add_argument(
64
+ "--auto",
65
+ action="store_true",
66
+ dest="auto",
67
+ help="use automatic detection of jobs to determine glide-ins",
68
+ )
69
+ parser.add_argument(
70
+ "-n",
71
+ "--node-count",
72
+ action="store",
73
+ default=None,
74
+ dest="nodeCount",
75
+ help="number of glideins to submit; these are chunks of a node, size the number of cores/cpus",
76
+ type=int,
77
+ required=True,
78
+ )
79
+ parser.add_argument(
80
+ "-c",
81
+ "--cpus",
82
+ action="store",
83
+ default=16,
84
+ dest="cpus",
85
+ help="cores / cpus per glidein",
86
+ type=int,
87
+ required=False,
88
+ )
89
+ parser.add_argument(
90
+ "-a",
91
+ "--account",
92
+ action="store",
93
+ default="rubin:developers",
94
+ dest="account",
95
+ help="Slurm account for glidein job",
96
+ type=str,
97
+ )
98
+ parser.add_argument(
99
+ "--collector",
100
+ action="store",
101
+ default=None,
102
+ dest="collector",
103
+ help="machine name of nondefault htcondor collector",
104
+ type=str,
105
+ required=False,
106
+ )
107
+ parser.add_argument(
108
+ "--collector-port",
109
+ action="store",
110
+ default=9618,
111
+ dest="collectorport",
112
+ help="port used for nondefault htcondor collector",
113
+ type=int,
114
+ required=False,
115
+ )
116
+ parser.add_argument(
117
+ "-s",
118
+ "--qos",
119
+ action="store",
120
+ default=None,
121
+ dest="qos",
122
+ help="Slurm qos for glidein job",
123
+ type=str,
124
+ )
125
+ parser.add_argument(
126
+ "-m",
127
+ "--maximum-wall-clock",
128
+ action="store",
129
+ dest="maximumWallClock",
130
+ default=None,
131
+ help="maximum wall clock time; e.g., 3600, 10:00:00, 6-00:00:00, etc",
132
+ type=str,
133
+ required=True,
134
+ )
135
+ parser.add_argument(
136
+ "-q",
137
+ "--queue",
138
+ action="store",
139
+ dest="queue",
140
+ default="roma,milano",
141
+ help="queue / partition name",
142
+ )
143
+ parser.add_argument(
144
+ "-O",
145
+ "--output-log",
146
+ action="store",
147
+ dest="outputLog",
148
+ default=None,
149
+ help="Output log filename; this option for PBS, unused with Slurm",
150
+ )
151
+ parser.add_argument(
152
+ "-E",
153
+ "--error-log",
154
+ action="store",
155
+ dest="errorLog",
156
+ default=None,
157
+ help="Error log filename; this option for PBS, unused with Slurm",
158
+ )
159
+ parser.add_argument(
160
+ "-g",
161
+ "--glidein-shutdown",
162
+ action="store",
163
+ dest="glideinShutdown",
164
+ type=int,
165
+ default=None,
166
+ help="glide-in inactivity shutdown time in seconds",
167
+ )
168
+ parser.add_argument(
169
+ "--openfiles",
170
+ action="store",
171
+ dest="openfiles",
172
+ type=int,
173
+ default=20480,
174
+ help="set the limit on number of open files (fd) per process",
175
+ )
176
+ parser.add_argument(
177
+ "-p",
178
+ "--pack",
179
+ action="store_true",
180
+ dest="packnodes",
181
+ help="encourage nodes to pack jobs rather than spread",
182
+ )
183
+ parser.add_argument(
184
+ "-v", "--verbose", action="store_true", dest="verbose", help="verbose"
185
+ )
186
+ parser.add_argument(
187
+ "-r",
188
+ "--reservation",
189
+ action="store",
190
+ dest="reservation",
191
+ default=None,
192
+ help="target a particular Slurm reservation",
193
+ )
194
+ parser.add_argument(
195
+ "-d",
196
+ "--dynamic",
197
+ const="__default__",
198
+ nargs="?",
199
+ action="store",
200
+ dest="dynamic",
201
+ type=str,
202
+ default="__default__",
203
+ help="configure to use dynamic/partitionable slot; legacy option: this is always enabled now",
204
+ )
205
+
206
+ self.args = parser.parse_args()
207
+
208
+ return self.args
209
+
210
+ def getArgs(self):
211
+ """Accessor method to get arguments left after standard parsed options
212
+ are initialized.
213
+
214
+ Returns
215
+ -------
216
+ args: `argparse.Namespace`
217
+ remaining command line arguments
218
+ """
219
+ return self.args
220
+
221
+ def getPlatform(self):
222
+ """Accessor method to retrieve the "platform" that was specified on
223
+ the command line.
224
+
225
+ Returns
226
+ -------
227
+ platform: `str`
228
+ the name of the "platform"
229
+ """
230
+ return self.args.platform
@@ -0,0 +1,75 @@
1
+ #!/usr/bin/env python
2
+
3
+ #
4
+ # LSST Data Management System
5
+ # Copyright 2008-2016 LSST Corporation.
6
+ #
7
+ # This product includes software developed by the
8
+ # LSST Project (http://www.lsst.org/).
9
+ #
10
+ # This program is free software: you can redistribute it and/or modify
11
+ # it under the terms of the GNU General Public License as published by
12
+ # the Free Software Foundation, either version 3 of the License, or
13
+ # (at your option) any later version.
14
+ #
15
+ # This program is distributed in the hope that it will be useful,
16
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
17
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
+ # GNU General Public License for more details.
19
+ #
20
+ # You should have received a copy of the LSST License Statement and
21
+ # the GNU General Public License along with this program. If not,
22
+ # see <http://www.lsstcorp.org/LegalNotices/>.
23
+ #
24
+
25
+ import lsst.pex.config as pexConfig
26
+
27
+
28
+ class PlatformConfig(pexConfig.Config):
29
+ """Platform specific information"""
30
+
31
+ defaultRoot = pexConfig.Field(
32
+ doc="remote root for working directories", dtype=str, default=None
33
+ )
34
+ localScratch = pexConfig.Field(
35
+ doc="local Condor scratch directory", dtype=str, default=None
36
+ )
37
+ idsPerJob = pexConfig.Field(
38
+ doc="number of ids to work on per job", dtype=int, default=1
39
+ )
40
+ dataDirectory = pexConfig.Field(
41
+ doc="remote directory where date that jobs will use is kept",
42
+ dtype=str,
43
+ default=None,
44
+ )
45
+ fileSystemDomain = pexConfig.Field(
46
+ doc="network domain name of remote system", dtype=str, default=None
47
+ )
48
+ eupsPath = pexConfig.Field(
49
+ doc="location of remote EUPS stack", dtype=str, default=None
50
+ )
51
+ nodeSetRequired = pexConfig.Field(
52
+ doc="is the nodeset required", dtype=bool, default=False
53
+ )
54
+ scheduler = pexConfig.Field(doc="scheduler type", dtype=str, default=None)
55
+ manager = pexConfig.Field(doc="workflow manager", dtype=str, default=None)
56
+ setup_using = pexConfig.Field(doc="environment setup type", dtype=str, default=None)
57
+ manager_software_home = pexConfig.Field(
58
+ doc="location of workflow manager software", dtype=str, default=None
59
+ )
60
+
61
+
62
+ class CondorConfig(pexConfig.Config):
63
+ """A pex_config file describing the platform specific information required
64
+ to fill out templates for running ctrl_orca jobs
65
+ """
66
+
67
+ platform = pexConfig.ConfigField("platform configuration", PlatformConfig)
68
+
69
+
70
+ class FakeTypeMap(dict):
71
+ def __init__(self, configClass):
72
+ self.configClass = configClass
73
+
74
+ def __getitem__(self, k):
75
+ return self.setdefault(k, self.configClass)
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/env python
2
+
3
+ #
4
+ # LSST Data Management System
5
+ # Copyright 2008-2016 LSST Corporation.
6
+ #
7
+ # This product includes software developed by the
8
+ # LSST Project (http://www.lsst.org/).
9
+ #
10
+ # This program is free software: you can redistribute it and/or modify
11
+ # it under the terms of the GNU General Public License as published by
12
+ # the Free Software Foundation, either version 3 of the License, or
13
+ # (at your option) any later version.
14
+ #
15
+ # This program is distributed in the hope that it will be useful,
16
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
17
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
+ # GNU General Public License for more details.
19
+ #
20
+ # You should have received a copy of the LSST License Statement and
21
+ # the GNU General Public License along with this program. If not,
22
+ # see <http://www.lsstcorp.org/LegalNotices/>.
23
+ #
24
+
25
+ import lsst.pex.config as pexConfig
26
+ from lsst.ctrl.execute.findPackageFile import find_package_file
27
+
28
+
29
+ class FakeTypeMap(dict):
30
+ def __init__(self, configClass):
31
+ self.configClass = configClass
32
+
33
+ def __getitem__(self, k):
34
+ return self.setdefault(k, self.configClass)
35
+
36
+
37
+ class UserInfoConfig(pexConfig.Config):
38
+ """User information"""
39
+
40
+ name = pexConfig.Field(doc="user login name", dtype=str, default=None)
41
+ home = pexConfig.Field(doc="user home directory", dtype=str, default=None)
42
+ scratch = pexConfig.Field(doc="user scratch directory", dtype=str, default=None)
43
+
44
+
45
+ class UserConfig(pexConfig.Config):
46
+ """User specific information"""
47
+
48
+ user = pexConfig.ConfigField(doc="user", dtype=UserInfoConfig)
49
+
50
+
51
+ class CondorInfoConfig(pexConfig.Config):
52
+ """A pex_config file describing the platform specific information about
53
+ remote user logins.
54
+ """
55
+
56
+ platform = pexConfig.ConfigChoiceField("platform info", FakeTypeMap(UserConfig))
57
+
58
+
59
+ if __name__ == "__main__":
60
+ config = CondorInfoConfig()
61
+ filename = find_package_file("condor-info.py")
62
+ config.loadFromStream(filename.read())
63
+
64
+ for i in config.platform:
65
+ print(i)
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env python
2
+
3
+ #
4
+ # LSST Data Management System
5
+ # Copyright 2008-2016 LSST Corporation.
6
+ #
7
+ # This product includes software developed by the
8
+ # LSST Project (http://www.lsst.org/).
9
+ #
10
+ # This program is free software: you can redistribute it and/or modify
11
+ # it under the terms of the GNU General Public License as published by
12
+ # the Free Software Foundation, either version 3 of the License, or
13
+ # (at your option) any later version.
14
+ #
15
+ # This program is distributed in the hope that it will be useful,
16
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
17
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
+ # GNU General Public License for more details.
19
+ #
20
+ # You should have received a copy of the LSST License Statement and
21
+ # the GNU General Public License along with this program. If not,
22
+ # see <http://www.lsstcorp.org/LegalNotices/>.
23
+ #
24
+
25
+ import os
26
+
27
+
28
+ def resolve(input: str) -> str:
29
+ """Render a string with any `$`-prefixed words substituted with a matching
30
+ environment variable.
31
+
32
+ .. deprecated:: w.2025.05
33
+ `lsst.ctrl.execute.envString.resolve` is deprecated and no longer used
34
+ by any internal APIs because `lsst.resource.ResourcePath` handles
35
+ environment variable expansion.
36
+
37
+ Parameters
38
+ ----------
39
+ input : `str`
40
+ A string containing environment variables to resolve.
41
+
42
+ Raises
43
+ ------
44
+ RuntimeError
45
+ If the environment variable does not exist
46
+ """
47
+
48
+ if "$" in (retVal := os.path.expandvars(input)):
49
+ raise RuntimeError(f"couldn't resolve all environment variables in {retVal}")
50
+ return retVal
@@ -0,0 +1,107 @@
1
+ #!/usr/bin/env python
2
+
3
+ #
4
+ # LSST Data Management System
5
+ # Copyright 2008-2016 LSST Corporation.
6
+ #
7
+ # This product includes software developed by the
8
+ # LSST Project (http://www.lsst.org/).
9
+ #
10
+ # This program is free software: you can redistribute it and/or modify
11
+ # it under the terms of the GNU General Public License as published by
12
+ # the Free Software Foundation, either version 3 of the License, or
13
+ # (at your option) any later version.
14
+ #
15
+ # This program is distributed in the hope that it will be useful,
16
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
17
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
+ # GNU General Public License for more details.
19
+ #
20
+ # You should have received a copy of the LSST License Statement and
21
+ # the GNU General Public License along with this program. If not,
22
+ # see <http://www.lsstcorp.org/LegalNotices/>.
23
+ #
24
+ import os
25
+ import sys
26
+
27
+ import lsst.utils
28
+ from lsst.resources import ResourcePath
29
+
30
+
31
+ def find_package_file(
32
+ filename: str, kind: str = "config", platform: str | None = None
33
+ ) -> ResourcePath:
34
+ """Find a package file from a set of candidate locations.
35
+
36
+ Parameters
37
+ ----------
38
+ filename : `str`
39
+ The unqualified name of a file to locate.
40
+
41
+ kind : `str`
42
+ The name of a subdirectory in which to look for the file within a
43
+ package location, relative to an ``etc/`` directory.
44
+
45
+ platform : `str` | `None`
46
+ The name of a platform plugin in which to look for the file, or `None`
47
+ if no platform plugin should be searched.
48
+
49
+ Returns
50
+ -------
51
+ `lsst.resources.ResourcePath`
52
+
53
+ Raises
54
+ ------
55
+ FileNotFoundError
56
+ If a requested file object cannot be located in the candidate hierarchy
57
+
58
+ Notes
59
+ -----
60
+ The candidate locations are, in descending order of preference:
61
+ - An ``.lsst`` directory in the user's home directory.
62
+ - An ``lsst`` directory in the user's ``$XDG_CONFIG_HOME`` directory
63
+ - An ``etc/{kind}`` directory in the EUPS stack environment for the
64
+ platform.
65
+ - An ``etc/{kind}`` directory in the current Python environment/venv shared
66
+ data directory.
67
+ - An ``etc/{kind}`` directory in an installed ``lsst.ctrl.platform.*``
68
+ package.
69
+ - An ``etc/{kind}`` directory in the ``lsst.ctrl.execute`` package.
70
+ """
71
+ # If the path, after expansion, is absolute, we don't need to go looking
72
+ # for it, it should be exactly where it is.
73
+ if (_filename := ResourcePath(filename, forceAbsolute=False)).isabs():
74
+ return _filename
75
+
76
+ home_dir = os.getenv("HOME", "~")
77
+ xdg_config_home = os.getenv("XDG_CONFIG_HOME", "~/.config")
78
+ try:
79
+ platform_pkg_dir = lsst.utils.getPackageDir(f"ctrl_platform_{platform}")
80
+ except (LookupError, ValueError):
81
+ platform_pkg_dir = None
82
+
83
+ file_candidates = [
84
+ ResourcePath(home_dir).join(".lsst").join(_filename),
85
+ ResourcePath(xdg_config_home).join("lsst").join(_filename),
86
+ (
87
+ ResourcePath(platform_pkg_dir).join("etc").join(kind).join(_filename)
88
+ if platform_pkg_dir
89
+ else None
90
+ ),
91
+ ResourcePath(sys.exec_prefix).join("etc").join(kind).join(_filename),
92
+ (
93
+ ResourcePath(
94
+ f"resource://lsst.ctrl.platform.{platform}/etc/{kind}/{_filename}"
95
+ )
96
+ if platform
97
+ else None
98
+ ),
99
+ ResourcePath(f"resource://lsst.ctrl.execute/etc/{kind}/{_filename}"),
100
+ ]
101
+ try:
102
+ found_file: ResourcePath = [
103
+ c for c in file_candidates if c is not None and c.exists()
104
+ ][0]
105
+ except IndexError:
106
+ raise FileNotFoundError(f"No file {filename} found in package file lookup")
107
+ return found_file
@@ -0,0 +1,93 @@
1
+ #!/usr/bin/env python
2
+
3
+ #
4
+ # LSST Data Management System
5
+ # Copyright 2008-2016 LSST Corporation.
6
+ #
7
+ # This product includes software developed by the
8
+ # LSST Project (http://www.lsst.org/).
9
+ #
10
+ # This program is free software: you can redistribute it and/or modify
11
+ # it under the terms of the GNU General Public License as published by
12
+ # the Free Software Foundation, either version 3 of the License, or
13
+ # (at your option) any later version.
14
+ #
15
+ # This program is distributed in the hope that it will be useful,
16
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
17
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
+ # GNU General Public License for more details.
19
+ #
20
+ # You should have received a copy of the LSST License Statement and
21
+ # the GNU General Public License along with this program. If not,
22
+ # see <http://www.lsstcorp.org/LegalNotices/>.
23
+ #
24
+
25
+ import logging
26
+ import sys
27
+ from typing import Any
28
+
29
+ from lsst.ctrl.execute.allocator import Allocator
30
+ from lsst.ctrl.execute.allocatorParser import AllocatorParser
31
+ from lsst.ctrl.execute.condorConfig import CondorConfig
32
+ from lsst.ctrl.execute.findPackageFile import find_package_file
33
+ from lsst.ctrl.execute.namedClassFactory import NamedClassFactory
34
+
35
+ _LOG = logging.getLogger("lsst.ctrl.execute")
36
+
37
+
38
+ def setup_logging(options: dict[str, Any] | None = None) -> None:
39
+ """Configure logger.
40
+
41
+ Parameters
42
+ ----------
43
+ options : dict[str, Any]
44
+ Logger settings. The key/value pairs it contains will be used to
45
+ override corresponding default settings. If empty or None (default),
46
+ logger will be set up with default settings.
47
+ """
48
+ settings = {
49
+ "datefmt": "%Y-%m-%dT%H:%M:%S%z",
50
+ "format": "%(levelname)s %(asctime)s %(name)s - %(message)s",
51
+ "level": logging.INFO,
52
+ "stream": sys.stderr,
53
+ }
54
+ if options is not None:
55
+ settings |= options
56
+ logging.basicConfig(**settings)
57
+
58
+
59
+ def main():
60
+ """Allocates Condor glide-in nodes a scheduler on a remote Node."""
61
+
62
+ p = AllocatorParser(sys.argv[0])
63
+
64
+ options = {}
65
+ if p.args.verbose:
66
+ options = {"level": logging.DEBUG}
67
+ setup_logging(options)
68
+
69
+ platform = p.getPlatform()
70
+
71
+ # load the CondorConfig file
72
+ execConfigName = find_package_file("execConfig.py", platform=platform)
73
+ configuration = CondorConfig()
74
+ configuration.loadFromStream(execConfigName.read())
75
+
76
+ # create the plugin class
77
+ schedulerName = configuration.platform.scheduler
78
+ schedulerClass = NamedClassFactory.createClass(
79
+ "lsst.ctrl.execute." + schedulerName + "Plugin"
80
+ )
81
+
82
+ # create the plugin
83
+ condor_info_file = find_package_file("condor-info.py", platform=platform)
84
+ scheduler: Allocator = schedulerClass(
85
+ platform, p.getArgs(), configuration, condor_info_file
86
+ )
87
+
88
+ # submit the request
89
+ scheduler.submit()
90
+
91
+
92
+ if __name__ == "__main__":
93
+ sys.exit(main())
@@ -0,0 +1,60 @@
1
+ #!/usr/bin/env python
2
+ #
3
+ # LSST Data Management System
4
+ # Copyright 2008-2016 LSST Corporation.
5
+ #
6
+ # This product includes software developed by the
7
+ # LSST Project (http://www.lsst.org/).
8
+ #
9
+ # This program is free software: you can redistribute it and/or modify
10
+ # it under the terms of the GNU General Public License as published by
11
+ # the Free Software Foundation, either version 3 of the License, or
12
+ # (at your option) any later version.
13
+ #
14
+ # This program is distributed in the hope that it will be useful,
15
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
+ # GNU General Public License for more details.
18
+ #
19
+ # You should have received a copy of the LSST License Statement and
20
+ # the GNU General Public License along with this program. If not,
21
+ # see <http://www.lsstcorp.org/LegalNotices/>.
22
+ #
23
+
24
+ import errno
25
+ import os
26
+ import re
27
+ import sys
28
+
29
+
30
+ # extracts a line from a DAG file to show which ids were processed for a
31
+ # particular dag node
32
+ def main():
33
+ if len(sys.argv) != 3:
34
+ print("usage: %s dagNodeName filename" % os.path.basename(sys.argv[0]))
35
+ return errno.EINVAL
36
+
37
+ dagNode = sys.argv[1]
38
+ filename = sys.argv[2]
39
+
40
+ if not os.path.exists(filename):
41
+ print("file %s not found" % filename)
42
+ return errno.ENOENT
43
+
44
+ ex = r"VARS %s var1=\"(?P<idlist>.+?)\"" % dagNode
45
+ with open(filename) as file:
46
+ for line in file:
47
+ line = line.rstrip(" \n")
48
+
49
+ # look for the line with the dagnode name in it
50
+ # and extract everything after "var1", but not the quotes
51
+ values = re.search(ex, line)
52
+ if values is None:
53
+ continue
54
+ ids = values.groupdict()["idlist"]
55
+ print(ids)
56
+ break
57
+
58
+
59
+ if __name__ == "__main__":
60
+ sys.exit(main())