From 29282b581bc629786c29fc1445c977a74cd7b22e Mon Sep 17 00:00:00 2001 From: Ben Segall Date: Thu, 7 Sep 2023 14:52:08 +0000 Subject: [PATCH] [reclient] Add cred cache status as a metrics label This will help analyze startup metrics Bug: b/294945709 Change-Id: Ia397dbebef7cc30b49c614dda51e56f482b6145b Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/4847325 Commit-Queue: Ben Segall Auto-Submit: Ben Segall Reviewed-by: Junji Watanabe --- reclient_helper.py | 26 ++++- tests/ninja_reclient_test.py | 186 ++++++++++++++++++++++++++++++++++- 2 files changed, 207 insertions(+), 5 deletions(-) diff --git a/reclient_helper.py b/reclient_helper.py index 05fdc3b03..0e38776ff 100644 --- a/reclient_helper.py +++ b/reclient_helper.py @@ -94,6 +94,26 @@ def find_cache_dir(tmp_dir): return os.path.join(tmp_dir, 'cache') +def auth_cache_status(): + cred_file = os.path.join(os.environ["RBE_cache_dir"], "reproxy.creds") + if not os.path.isfile(cred_file): + return "missing", "UNSPECIFIED" + try: + with open(cred_file) as f: + status = "valid" + mechanism = "UNSPECIFIED" + for line in f.readlines(): + if "seconds:" in line: + exp = int(line.strip()[len("seconds:"):].strip()) + if exp < (time.time() + 5 * 60): + status = "expired" + elif "mechanism:" in line: + mechanism = line.strip()[len("mechanism:"):].strip() + return status, mechanism + except OSError: + return "missing", "UNSPECIFIED" + + def set_reproxy_metrics_flags(tool): """Helper to setup metrics collection flags for reproxy. @@ -109,7 +129,11 @@ def set_reproxy_metrics_flags(tool): os.environ.setdefault("RBE_invocation_id", autoninja_id) os.environ.setdefault("RBE_metrics_project", "chromium-reclient-metrics") os.environ.setdefault("RBE_metrics_table", "rbe_metrics.builds") - os.environ.setdefault("RBE_metrics_labels", "source=developer,tool=" + tool) + labels = "source=developer,tool=" + tool + auth_status, auth_mechanism = auth_cache_status() + labels += ",creds_cache_status=" + auth_status + labels += ",creds_cache_mechanism=" + auth_mechanism + os.environ.setdefault("RBE_metrics_labels", labels) os.environ.setdefault("RBE_metrics_prefix", "go.chromium.org") diff --git a/tests/ninja_reclient_test.py b/tests/ninja_reclient_test.py index 9a35ee2d7..9c680b11f 100755 --- a/tests/ninja_reclient_test.py +++ b/tests/ninja_reclient_test.py @@ -7,6 +7,7 @@ import hashlib import os import os.path import sys +import time import unittest import unittest.mock @@ -42,8 +43,8 @@ class NinjaReclientTest(trial_dir.TestCase): @unittest.mock.patch('subprocess.call', return_value=0) @unittest.mock.patch('ninja.main', return_value=0) @unittest.mock.patch('reclient_metrics.check_status', return_value=True) - def test_ninja_reclient_collect_metrics(self, mock_metrics_status, - mock_ninja, mock_call): + def test_ninja_reclient_collect_metrics_cache_missing( + self, mock_metrics_status, mock_ninja, mock_call): reclient_bin_dir = os.path.join('src', 'buildtools', 'reclient') reclient_cfg = os.path.join('src', 'buildtools', 'reclient_cfgs', 'reproxy.cfg') @@ -99,8 +100,185 @@ class NinjaReclientTest(trial_dir.TestCase): "chromium-reclient-metrics") self.assertEqual(os.environ.get('RBE_metrics_table'), "rbe_metrics.builds") - self.assertEqual(os.environ.get('RBE_metrics_labels'), - "source=developer,tool=ninja_reclient") + self.assertEqual( + os.environ.get('RBE_metrics_labels'), + "source=developer,tool=ninja_reclient," + "creds_cache_status=missing,creds_cache_mechanism=UNSPECIFIED") + self.assertEqual(os.environ.get('RBE_metrics_prefix'), + "go.chromium.org") + + mock_metrics_status.assert_called_once_with("out/a") + mock_ninja.assert_called_once_with(argv) + mock_call.assert_has_calls([ + unittest.mock.call([ + os.path.join(self.root_dir, reclient_bin_dir, + 'bootstrap' + gclient_paths.GetExeSuffix()), + "--re_proxy=" + + os.path.join(self.root_dir, reclient_bin_dir, + 'reproxy' + gclient_paths.GetExeSuffix()), + "--cfg=" + os.path.join(self.root_dir, reclient_cfg) + ]), + unittest.mock.call([ + os.path.join(self.root_dir, reclient_bin_dir, + 'bootstrap' + gclient_paths.GetExeSuffix()), + "--shutdown", + "--cfg=" + os.path.join(self.root_dir, reclient_cfg) + ]), + ]) + + @unittest.mock.patch.dict(os.environ, {}) + @unittest.mock.patch('subprocess.call', return_value=0) + @unittest.mock.patch('ninja.main', return_value=0) + @unittest.mock.patch('reclient_metrics.check_status', return_value=True) + def test_ninja_reclient_collect_metrics_cache_valid(self, + mock_metrics_status, + mock_ninja, mock_call): + reclient_bin_dir = os.path.join('src', 'buildtools', 'reclient') + reclient_cfg = os.path.join('src', 'buildtools', 'reclient_cfgs', + 'reproxy.cfg') + cache_dir = os.path.join( + self.root_dir, ".reproxy_cache", + hashlib.md5( + os.path.join(self.root_dir, "out", "a", + ".reproxy_tmp").encode()).hexdigest()) + write('.gclient', '') + write('.gclient_entries', 'entries = {"buildtools": "..."}') + write(os.path.join(reclient_bin_dir, 'version.txt'), '0.0') + write(reclient_cfg, '0.0') + write( + os.path.join(cache_dir, "reproxy.creds"), """ +mechanism: GCLOUD +expiry: { + seconds: %d +} + """ % (int(time.time()) + 10 * 60)) + argv = ["ninja_reclient.py", "-C", "out/a", "chrome"] + + self.assertEqual(0, ninja_reclient.main(argv)) + + self.assertTrue( + os.path.isdir( + os.path.join(self.root_dir, "out", "a", ".reproxy_tmp"))) + self.assertTrue(os.path.isdir(cache_dir)) + self.assertTrue( + os.path.isdir( + os.path.join(self.root_dir, "out", "a", ".reproxy_tmp", + "logs"))) + self.assertEqual( + os.environ.get('RBE_output_dir'), + os.path.join(self.root_dir, "out", "a", ".reproxy_tmp", "logs")) + self.assertEqual( + os.environ.get('RBE_proxy_log_dir'), + os.path.join(self.root_dir, "out", "a", ".reproxy_tmp", "logs")) + self.assertEqual(os.environ.get('RBE_cache_dir'), cache_dir) + if sys.platform.startswith('win'): + self.assertEqual( + os.environ.get('RBE_server_address'), + "pipe://%s/reproxy.pipe" % hashlib.md5( + os.path.join(self.root_dir, "out", "a", + ".reproxy_tmp").encode()).hexdigest()) + else: + self.assertEqual( + os.environ.get('RBE_server_address'), + "unix:///tmp/reproxy_%s.sock" % hashlib.sha256( + os.path.join(self.root_dir, "out", "a", + ".reproxy_tmp").encode()).hexdigest()) + + self.assertEqual(os.environ.get('RBE_metrics_project'), + "chromium-reclient-metrics") + self.assertEqual(os.environ.get('RBE_metrics_table'), + "rbe_metrics.builds") + self.assertEqual( + os.environ.get('RBE_metrics_labels'), + "source=developer,tool=ninja_reclient," + "creds_cache_status=valid,creds_cache_mechanism=GCLOUD") + self.assertEqual(os.environ.get('RBE_metrics_prefix'), + "go.chromium.org") + + mock_metrics_status.assert_called_once_with("out/a") + mock_ninja.assert_called_once_with(argv) + mock_call.assert_has_calls([ + unittest.mock.call([ + os.path.join(self.root_dir, reclient_bin_dir, + 'bootstrap' + gclient_paths.GetExeSuffix()), + "--re_proxy=" + + os.path.join(self.root_dir, reclient_bin_dir, + 'reproxy' + gclient_paths.GetExeSuffix()), + "--cfg=" + os.path.join(self.root_dir, reclient_cfg) + ]), + unittest.mock.call([ + os.path.join(self.root_dir, reclient_bin_dir, + 'bootstrap' + gclient_paths.GetExeSuffix()), + "--shutdown", + "--cfg=" + os.path.join(self.root_dir, reclient_cfg) + ]), + ]) + + @unittest.mock.patch.dict(os.environ, {}) + @unittest.mock.patch('subprocess.call', return_value=0) + @unittest.mock.patch('ninja.main', return_value=0) + @unittest.mock.patch('reclient_metrics.check_status', return_value=True) + def test_ninja_reclient_collect_metrics_cache_expired( + self, mock_metrics_status, mock_ninja, mock_call): + reclient_bin_dir = os.path.join('src', 'buildtools', 'reclient') + reclient_cfg = os.path.join('src', 'buildtools', 'reclient_cfgs', + 'reproxy.cfg') + cache_dir = os.path.join( + self.root_dir, ".reproxy_cache", + hashlib.md5( + os.path.join(self.root_dir, "out", "a", + ".reproxy_tmp").encode()).hexdigest()) + write('.gclient', '') + write('.gclient_entries', 'entries = {"buildtools": "..."}') + write(os.path.join(reclient_bin_dir, 'version.txt'), '0.0') + write(reclient_cfg, '0.0') + write( + os.path.join(cache_dir, "reproxy.creds"), """ +mechanism: GCLOUD +expiry: { + seconds: %d +} + """ % (int(time.time()))) + argv = ["ninja_reclient.py", "-C", "out/a", "chrome"] + + self.assertEqual(0, ninja_reclient.main(argv)) + + self.assertTrue( + os.path.isdir( + os.path.join(self.root_dir, "out", "a", ".reproxy_tmp"))) + self.assertTrue(os.path.isdir(cache_dir)) + self.assertTrue( + os.path.isdir( + os.path.join(self.root_dir, "out", "a", ".reproxy_tmp", + "logs"))) + self.assertEqual( + os.environ.get('RBE_output_dir'), + os.path.join(self.root_dir, "out", "a", ".reproxy_tmp", "logs")) + self.assertEqual( + os.environ.get('RBE_proxy_log_dir'), + os.path.join(self.root_dir, "out", "a", ".reproxy_tmp", "logs")) + self.assertEqual(os.environ.get('RBE_cache_dir'), cache_dir) + if sys.platform.startswith('win'): + self.assertEqual( + os.environ.get('RBE_server_address'), + "pipe://%s/reproxy.pipe" % hashlib.md5( + os.path.join(self.root_dir, "out", "a", + ".reproxy_tmp").encode()).hexdigest()) + else: + self.assertEqual( + os.environ.get('RBE_server_address'), + "unix:///tmp/reproxy_%s.sock" % hashlib.sha256( + os.path.join(self.root_dir, "out", "a", + ".reproxy_tmp").encode()).hexdigest()) + + self.assertEqual(os.environ.get('RBE_metrics_project'), + "chromium-reclient-metrics") + self.assertEqual(os.environ.get('RBE_metrics_table'), + "rbe_metrics.builds") + self.assertEqual( + os.environ.get('RBE_metrics_labels'), + "source=developer,tool=ninja_reclient," + "creds_cache_status=expired,creds_cache_mechanism=GCLOUD") self.assertEqual(os.environ.get('RBE_metrics_prefix'), "go.chromium.org")