blob: 1c01d00cbc712a601ded0ac05374d97d86c31c5b [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."""
Tzung-Bi Shihcff04382022-02-15 17:02:38 +080062 def wrapped_preliminary_check(*args, **kwargs):
Guenter Roeck755e27c2020-04-25 11:44:18 -070063 """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:
Tzung-Bi Shihcff04382022-02-15 17:02:38 +080076 if kwargs.get('debug'):
77 level = logging.DEBUG
78 else:
79 level = logging.WARNING
Guenter Roeck755e27c2020-04-25 11:44:18 -070080
Guenter Roeck807aaac2021-01-08 13:56:50 -080081 logging.basicConfig(format='%(asctime)s %(levelname)s: %(message)s', level=level,
82 datefmt='%Y-%m-%d %H:%M:%S')
Guenter Roeck755e27c2020-04-25 11:44:18 -070083
Tzung-Bi Shihcff04382022-02-15 17:02:38 +080084 f(*args, **kwargs)
Guenter Roeck755e27c2020-04-25 11:44:18 -070085 return wrapped_preliminary_check
86 return wrap_preliminary_check
87
88
89def set_gcloud_project_config():
90 """Sets project settings to chromeos-missing-patches project."""
91 set_project_cmd = ['gcloud', 'config', 'set', 'project', 'google.com:chromeos-missing-patches']
92 subprocess.run(set_project_cmd, stderr=subprocess.DEVNULL, check=True)
93
94
95def cloud_sql_proxy_decorator(func):
96 """Decorator for starting and stopping cloud_sql_proxy."""
97 def cloud_sql_proxy_wrapper(*args, **kwargs):
98 """Create cloud_sql_proxy process, run func, send signal.SIGKILL cloud_sql_proxy"""
99 try:
100 set_gcloud_project_config()
101 sql_instance_cmd = ['gcloud', 'sql', 'instances', 'describe',
Guenter Roeck99635d42021-01-14 11:17:55 -0800102 'linux-patches-mysql-8', '--format=value[](connectionName)']
Guenter Roeck755e27c2020-04-25 11:44:18 -0700103 sql_instance = subprocess.check_output(sql_instance_cmd, encoding='utf-8').rstrip()
104
105 cloudsql_cmd = ['cloud_sql_proxy', '-instances=%s=tcp:3306' % sql_instance]
106 cloud_sql_proxy_pid = subprocess.Popen(cloudsql_cmd, stdout=subprocess.DEVNULL,
107 stderr=subprocess.DEVNULL)
108
109 # Wait for cloud_sql_proxy to spin up
110 # todo(hirthanan): read cloud_sql pipe to see when it starts up
111 time.sleep(3)
112
113 func(*args, **kwargs)
114
115 cloud_sql_proxy_pid.kill()
116 except subprocess.CalledProcessError:
117 logging.error('Failed to retrieve sql_instance from gcloud')
118 logging.error('User must be authenticated with Cloud SDK (run `gcloud auth login`)')
119 logging.error('User must also be added to GCP project chromeos-missing-patches.')
120 raise
121 return cloud_sql_proxy_wrapper