diff options
author | Vanessasaurus <814322+vsoch@users.noreply.github.com> | 2021-06-15 15:36:02 -0600 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-06-15 14:36:02 -0700 |
commit | 53dae0040a6bba725b8a23cf60f4cfe7023bec80 (patch) | |
tree | 6e937c63196f74d05c1db257c240c1de72808e92 /lib | |
parent | cdc28a96232f40a112adef6dd7dcbb79388c8e6d (diff) | |
download | spack-53dae0040a6bba725b8a23cf60f4cfe7023bec80.tar.gz spack-53dae0040a6bba725b8a23cf60f4cfe7023bec80.tar.bz2 spack-53dae0040a6bba725b8a23cf60f4cfe7023bec80.tar.xz spack-53dae0040a6bba725b8a23cf60f4cfe7023bec80.zip |
adding spack upload command (#24321)
this will first support uploads for spack monitor, and eventually could be
used for other kinds of spack uploads
Signed-off-by: vsoch <vsoch@users.noreply.github.com>
Co-authored-by: vsoch <vsoch@users.noreply.github.com>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/spack/docs/monitoring.rst | 13 | ||||
-rw-r--r-- | lib/spack/spack/cmd/monitor.py | 35 | ||||
-rw-r--r-- | lib/spack/spack/monitor.py | 81 |
3 files changed, 121 insertions, 8 deletions
diff --git a/lib/spack/docs/monitoring.rst b/lib/spack/docs/monitoring.rst index 41a7a4a2d2..97f4fc4cd8 100644 --- a/lib/spack/docs/monitoring.rst +++ b/lib/spack/docs/monitoring.rst @@ -117,4 +117,15 @@ flag. $ spack install --monitor --monitor-save-local hdf5 This will save results in a subfolder, "monitor" in your designated spack -reports folder, which defaults to ``$HOME/.spack/reports/monitor``. +reports folder, which defaults to ``$HOME/.spack/reports/monitor``. When +you are ready to upload them to a spack monitor server: + + +.. code-block:: console + + $ spack monitor upload ~/.spack/reports/monitor + + +You can choose the root directory of results as shown above, or a specific +subdirectory. The command accepts other arguments to specify configuration +for the monitor. diff --git a/lib/spack/spack/cmd/monitor.py b/lib/spack/spack/cmd/monitor.py new file mode 100644 index 0000000000..aec40bbd6a --- /dev/null +++ b/lib/spack/spack/cmd/monitor.py @@ -0,0 +1,35 @@ +# Copyright 2013-2021 Lawrence Livermore National Security, LLC and other +# Spack Project Developers. See the top-level COPYRIGHT file for details. +# +# SPDX-License-Identifier: (Apache-2.0 OR MIT) + +import spack.monitor + + +description = "interact with a monitor server" +section = "analysis" +level = "long" + + +def setup_parser(subparser): + sp = subparser.add_subparsers(metavar='SUBCOMMAND', dest='monitor_command') + + # This adds the monitor group to the subparser + spack.monitor.get_monitor_group(subparser) + + # Spack Monitor Uploads + monitor_parser = sp.add_parser('upload', description="upload to spack monitor") + monitor_parser.add_argument("upload_dir", help="directory root to upload") + + +def monitor(parser, args, **kwargs): + + if args.monitor_command == "upload": + monitor = spack.monitor.get_client( + host=args.monitor_host, + prefix=args.monitor_prefix, + disable_auth=args.monitor_disable_auth, + ) + + # Upload the directory + monitor.upload_local_save(args.upload_dir) diff --git a/lib/spack/spack/monitor.py b/lib/spack/spack/monitor.py index a6ca3be316..f7d108cb75 100644 --- a/lib/spack/spack/monitor.py +++ b/lib/spack/spack/monitor.py @@ -29,7 +29,7 @@ import spack.util.spack_yaml as syaml import spack.util.path import llnl.util.tty as tty from copy import deepcopy - +from glob import glob # A global client to instantiate once cli = None @@ -382,7 +382,7 @@ class SpackMonitorClient: if self.save_local: filename = "spec-%s-%s-config.json" % (spec.name, spec.version) - self.save(sjson.dump(as_dict), filename) + self.save(as_dict, filename) else: response = self.do_request("specs/new/", data=sjson.dump(as_dict)) configs[spec.package.name] = response.get('data', {}) @@ -434,8 +434,8 @@ class SpackMonitorClient: hasher = hashlib.md5() hasher.update(str(data).encode('utf-8')) bid = hasher.hexdigest() - filename = "build-metadata-%s.json" % full_hash - response = self.save(sjson.dump(data), filename) + filename = "build-metadata-%s.json" % bid + response = self.save(data, filename) if return_response: return response return bid @@ -465,7 +465,7 @@ class SpackMonitorClient: data = {"build_id": self.get_build_id(spec), "status": status} if self.save_local: filename = "build-%s-status.json" % data['build_id'] - return self.save(sjson.dump(data), filename) + return self.save(data, filename) return self.do_request("builds/update/", data=sjson.dump(data)) @@ -510,7 +510,7 @@ class SpackMonitorClient: if self.save_local: filename = "build-%s-phase-%s.json" % (data['build_id'], phase_name) - return self.save(sjson.dump(data), filename) + return self.save(data, filename) return self.do_request("builds/phases/update/", data=sjson.dump(data)) @@ -530,10 +530,77 @@ class SpackMonitorClient: if self.save_local: filename = "spec-%s-%s.json" % (spec.name, spec.version) - return self.save(sjson.dump(data), filename) + return self.save(data, filename) return self.do_request("specs/new/", data=sjson.dump(data)) + def iter_read(self, pattern): + """ + A helper to read json from a directory glob and return it loaded. + """ + for filename in glob(pattern): + basename = os.path.basename(filename) + tty.info("Reading %s" % basename) + yield read_json(filename) + + def upload_local_save(self, dirname): + """ + Upload results from a locally saved directory to spack monitor. + + The general workflow will first include an install with save local: + spack install --monitor --monitor-save-local + And then a request to upload the root or specific directory. + spack upload monitor ~/.spack/reports/monitor/<date>/ + """ + dirname = os.path.abspath(dirname) + if not os.path.exists(dirname): + tty.die("%s does not exist." % dirname) + + # We can't be sure the level of nesting the user has provided + # So we walk recursively through and look for build metadata + for subdir, dirs, files in os.walk(dirname): + root = os.path.join(dirname, subdir) + + # A metadata file signals a monitor export + metadata = glob("%s%sbuild-metadata*" % (root, os.sep)) + if not metadata or not files or not root or not subdir: + continue + self._upload_local_save(root) + tty.info("Upload complete") + + def _upload_local_save(self, dirname): + """ + Given a found metadata file, upload results to spack monitor. + """ + # First find all the specs + for spec in self.iter_read("%s%sspec*" % (dirname, os.sep)): + self.do_request("specs/new/", data=sjson.dump(spec)) + + # Load build metadata to generate an id + metadata = glob("%s%sbuild-metadata*" % (dirname, os.sep)) + if not metadata: + tty.die("Build metadata file(s) missing in %s" % dirname) + + # Create a build_id lookup based on hash + hashes = {} + for metafile in metadata: + data = read_json(metafile) + build = self.do_request("builds/new/", data=sjson.dump(data)) + localhash = os.path.basename(metafile).replace(".json", "") + hashes[localhash.replace('build-metadata-', "")] = build + + # Next upload build phases + for phase in self.iter_read("%s%sbuild*phase*" % (dirname, os.sep)): + build_id = hashes[phase['build_id']]['data']['build']['build_id'] + phase['build_id'] = build_id + self.do_request("builds/phases/update/", data=sjson.dump(phase)) + + # Next find the status objects + for status in self.iter_read("%s%sbuild*status*" % (dirname, os.sep)): + build_id = hashes[status['build_id']]['data']['build']['build_id'] + status['build_id'] = build_id + self.do_request("builds/update/", data=sjson.dump(status)) + # Helper functions |