summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorVanessasaurus <814322+vsoch@users.noreply.github.com>2021-06-15 15:36:02 -0600
committerGitHub <noreply@github.com>2021-06-15 14:36:02 -0700
commit53dae0040a6bba725b8a23cf60f4cfe7023bec80 (patch)
tree6e937c63196f74d05c1db257c240c1de72808e92 /lib
parentcdc28a96232f40a112adef6dd7dcbb79388c8e6d (diff)
downloadspack-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.rst13
-rw-r--r--lib/spack/spack/cmd/monitor.py35
-rw-r--r--lib/spack/spack/monitor.py81
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