blob: a85529005da9cb59e72845d938f1bc5fd54bf45e [file] [log] [blame]
Guenter Roeck755e27c2020-04-25 11:44:18 -07001#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3#
4# Copyright 2020 The Chromium OS Authors. All rights reserved.
5# Use of this source code is governed by a BSD-style license that can be
6# found in the LICENSE file.
7
8"""Helper functions used by various commands
9
10preliminary_check_decorator():
11 Check if environment is set up correctly.
12
13cloud_sql_proxy_decorator():
14 Start and stop cloud_sql_proxy.
15"""
16
Guenter Roeck755e27c2020-04-25 11:44:18 -070017
18import logging
19import os
20import subprocess
21import time
22
23import common
24
25
26def check_service_key_secret_exists():
27 """Raises an error if the service account secret key file does not exist.
28
29 This can be generated on GCP under service accounts (Generate service token)
30 This file should automatically be generated when running the gce-startup.sh script.
31 """
32 secret_file_path = os.path.join(common.HOMEDIR, 'secrets/linux_patches_robot_key.json')
33
34 if not os.path.exists(secret_file_path):
35 raise FileNotFoundError('Service token secret file %s not found' % secret_file_path)
36
37
38def check_service_running(keyword):
39 """Raises an error if there is no running process commands that match `keyword`."""
40 process_grep = ['pgrep', '-f', keyword]
41 try:
42 subprocess.run(process_grep, check=True, stdout=subprocess.DEVNULL,
43 encoding='utf-8', errors='ignore')
Guenter Roeck807aaac2021-01-08 13:56:50 -080044 except subprocess.CalledProcessError as e:
45 raise ProcessLookupError('Service %s is not running.' % keyword) from e
Guenter Roeck755e27c2020-04-25 11:44:18 -070046
47
48def check_cloud_sql_proxy_running():
49 """Raises an error if cloud_sql_proxy service is not running."""
50 check_service_running('cloud_sql_proxy')
51
52
53def check_git_cookie_authdaemon_running():
54 """Raises an error if git-cookie-authdaemon service is not running."""
55 check_service_running('git-cookie-authdaemon')
56
57
58def preliminary_check_decorator(is_gce):
59 """Decorator for performing environment related checks."""
60 def wrap_preliminary_check(f):
61 """Inner function that wraps method with preliminary check."""
62 def wrapped_preliminary_check(*args):
63 """Sanity checks on state of environment before executing decorated function."""
64 if is_gce:
65 # Ensures we have service account credentials to connect to cloudsql (GCP)
66 check_service_key_secret_exists()
Tzung-Bi Shih9ce8c462022-02-15 17:10:39 +080067 # Ensure we have token to allow service account to perform Gerrit API operations
68 check_git_cookie_authdaemon_running()
Guenter Roeck755e27c2020-04-25 11:44:18 -070069
70 # Ensure cloudsql proxy is running to allow connection
71 check_cloud_sql_proxy_running()
72
73 if is_gce:
74 level = logging.INFO
Guenter Roeck755e27c2020-04-25 11:44:18 -070075 else:
76 level = logging.WARNING
77
Guenter Roeck807aaac2021-01-08 13:56:50 -080078 logging.basicConfig(format='%(asctime)s %(levelname)s: %(message)s', level=level,
79 datefmt='%Y-%m-%d %H:%M:%S')
Guenter Roeck755e27c2020-04-25 11:44:18 -070080
81 f(*args)
82 return wrapped_preliminary_check
83 return wrap_preliminary_check
84
85
86def set_gcloud_project_config():
87 """Sets project settings to chromeos-missing-patches project."""
88 set_project_cmd = ['gcloud', 'config', 'set', 'project', 'google.com:chromeos-missing-patches']
89 subprocess.run(set_project_cmd, stderr=subprocess.DEVNULL, check=True)
90
91
92def cloud_sql_proxy_decorator(func):
93 """Decorator for starting and stopping cloud_sql_proxy."""
94 def cloud_sql_proxy_wrapper(*args, **kwargs):
95 """Create cloud_sql_proxy process, run func, send signal.SIGKILL cloud_sql_proxy"""
96 try:
97 set_gcloud_project_config()
98 sql_instance_cmd = ['gcloud', 'sql', 'instances', 'describe',
Guenter Roeck99635d42021-01-14 11:17:55 -080099 'linux-patches-mysql-8', '--format=value[](connectionName)']
Guenter Roeck755e27c2020-04-25 11:44:18 -0700100 sql_instance = subprocess.check_output(sql_instance_cmd, encoding='utf-8').rstrip()
101
102 cloudsql_cmd = ['cloud_sql_proxy', '-instances=%s=tcp:3306' % sql_instance]
103 cloud_sql_proxy_pid = subprocess.Popen(cloudsql_cmd, stdout=subprocess.DEVNULL,
104 stderr=subprocess.DEVNULL)
105
106 # Wait for cloud_sql_proxy to spin up
107 # todo(hirthanan): read cloud_sql pipe to see when it starts up
108 time.sleep(3)
109
110 func(*args, **kwargs)
111
112 cloud_sql_proxy_pid.kill()
113 except subprocess.CalledProcessError:
114 logging.error('Failed to retrieve sql_instance from gcloud')
115 logging.error('User must be authenticated with Cloud SDK (run `gcloud auth login`)')
116 logging.error('User must also be added to GCP project chromeos-missing-patches.')
117 raise
118 return cloud_sql_proxy_wrapper