blob: 27d4503c5ef0bdb38e83b9aa336c8c5cf277c259 [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
17from __future__ import print_function
18
19import logging
20import os
21import subprocess
22import time
23
24import common
25
26
27def check_service_key_secret_exists():
28 """Raises an error if the service account secret key file does not exist.
29
30 This can be generated on GCP under service accounts (Generate service token)
31 This file should automatically be generated when running the gce-startup.sh script.
32 """
33 secret_file_path = os.path.join(common.HOMEDIR, 'secrets/linux_patches_robot_key.json')
34
35 if not os.path.exists(secret_file_path):
36 raise FileNotFoundError('Service token secret file %s not found' % secret_file_path)
37
38
39def check_service_running(keyword):
40 """Raises an error if there is no running process commands that match `keyword`."""
41 process_grep = ['pgrep', '-f', keyword]
42 try:
43 subprocess.run(process_grep, check=True, stdout=subprocess.DEVNULL,
44 encoding='utf-8', errors='ignore')
Guenter Roeck807aaac2021-01-08 13:56:50 -080045 except subprocess.CalledProcessError as e:
46 raise ProcessLookupError('Service %s is not running.' % keyword) from e
Guenter Roeck755e27c2020-04-25 11:44:18 -070047
48
49def check_cloud_sql_proxy_running():
50 """Raises an error if cloud_sql_proxy service is not running."""
51 check_service_running('cloud_sql_proxy')
52
53
54def check_git_cookie_authdaemon_running():
55 """Raises an error if git-cookie-authdaemon service is not running."""
56 check_service_running('git-cookie-authdaemon')
57
58
59def preliminary_check_decorator(is_gce):
60 """Decorator for performing environment related checks."""
61 def wrap_preliminary_check(f):
62 """Inner function that wraps method with preliminary check."""
63 def wrapped_preliminary_check(*args):
64 """Sanity checks on state of environment before executing decorated function."""
65 if is_gce:
66 # Ensures we have service account credentials to connect to cloudsql (GCP)
67 check_service_key_secret_exists()
68
69 # Ensure cloudsql proxy is running to allow connection
70 check_cloud_sql_proxy_running()
71
72 if is_gce:
73 level = logging.INFO
74 # Ensure we have token to allow service account to perform Gerrit API operations
75 check_git_cookie_authdaemon_running()
76 else:
77 level = logging.WARNING
78
Guenter Roeck807aaac2021-01-08 13:56:50 -080079 logging.basicConfig(format='%(asctime)s %(levelname)s: %(message)s', level=level,
80 datefmt='%Y-%m-%d %H:%M:%S')
Guenter Roeck755e27c2020-04-25 11:44:18 -070081
82 f(*args)
83 return wrapped_preliminary_check
84 return wrap_preliminary_check
85
86
87def set_gcloud_project_config():
88 """Sets project settings to chromeos-missing-patches project."""
89 set_project_cmd = ['gcloud', 'config', 'set', 'project', 'google.com:chromeos-missing-patches']
90 subprocess.run(set_project_cmd, stderr=subprocess.DEVNULL, check=True)
91
92
93def cloud_sql_proxy_decorator(func):
94 """Decorator for starting and stopping cloud_sql_proxy."""
95 def cloud_sql_proxy_wrapper(*args, **kwargs):
96 """Create cloud_sql_proxy process, run func, send signal.SIGKILL cloud_sql_proxy"""
97 try:
98 set_gcloud_project_config()
99 sql_instance_cmd = ['gcloud', 'sql', 'instances', 'describe',
100 'linux-patches-sql', '--format=value[](connectionName)']
101 sql_instance = subprocess.check_output(sql_instance_cmd, encoding='utf-8').rstrip()
102
103 cloudsql_cmd = ['cloud_sql_proxy', '-instances=%s=tcp:3306' % sql_instance]
104 cloud_sql_proxy_pid = subprocess.Popen(cloudsql_cmd, stdout=subprocess.DEVNULL,
105 stderr=subprocess.DEVNULL)
106
107 # Wait for cloud_sql_proxy to spin up
108 # todo(hirthanan): read cloud_sql pipe to see when it starts up
109 time.sleep(3)
110
111 func(*args, **kwargs)
112
113 cloud_sql_proxy_pid.kill()
114 except subprocess.CalledProcessError:
115 logging.error('Failed to retrieve sql_instance from gcloud')
116 logging.error('User must be authenticated with Cloud SDK (run `gcloud auth login`)')
117 logging.error('User must also be added to GCP project chromeos-missing-patches.')
118 raise
119 return cloud_sql_proxy_wrapper