blob: a5c94f59553cc4b652df4e31370f41344f96176e [file] [log] [blame]
Ben Kwa5e2bb5c2017-11-01 16:44:16 -07001#!/usr/bin/python
2# Copyright 2017 The Chromium Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""This tool manages the lxc container pool service."""
7
8import argparse
9import logging
10import os
11import signal
Ben Kwafe04bb32017-11-03 10:50:31 -070012import time
Ben Kwa5e2bb5c2017-11-01 16:44:16 -070013from contextlib import contextmanager
14
15import common
16from autotest_lib.client.bin import utils
17from autotest_lib.client.common_lib import logging_config
Ben Kwafe04bb32017-11-03 10:50:31 -070018from autotest_lib.server import server_logging_config
Ben Kwa5e2bb5c2017-11-01 16:44:16 -070019from autotest_lib.site_utils import lxc
20from autotest_lib.site_utils.lxc import container_pool
21
Ben Kwa9b18c712017-12-13 15:38:56 -080022try:
23 from chromite.lib import ts_mon_config
24except ImportError:
25 ts_mon_config = utils.metrics_mock
26
Ben Kwa5e2bb5c2017-11-01 16:44:16 -070027
Ben Kwafe04bb32017-11-03 10:50:31 -070028# Location and base name of log files.
29_LOG_LOCATION = '/usr/local/autotest/logs'
30_LOG_NAME = 'lxc_pool.%d' % time.time()
31
32
Ben Kwa181814d2017-11-03 09:27:58 -070033def _start(args):
Ben Kwa5e2bb5c2017-11-01 16:44:16 -070034 """Starts up the container pool service.
35
36 This function instantiates and starts up the pool service on the current
37 thread (i.e. the function will block, and not return until the service is
38 shut down).
39 """
40 # TODO(dshi): crbug.com/459344 Set remove this enforcement when test
41 # container can be unprivileged container.
42 if utils.sudo_require_password():
43 logging.warning('SSP requires root privilege to run commands, please '
44 'grant root access to this process.')
45 utils.run('sudo true')
Ben Kwa5ab77c82017-12-01 13:39:40 -080046
47 # Configure logging.
48 config = server_logging_config.ServerLoggingConfig()
49 config.configure_logging(verbose=args.verbose)
50 config.add_debug_file_handlers(log_dir=_LOG_LOCATION, log_name=_LOG_NAME)
51 # Pool code is heavily multi-threaded. This will help debugging.
52 logging_config.add_threadname_in_log()
53
Ben Kwa5e2bb5c2017-11-01 16:44:16 -070054 host_dir = lxc.SharedHostDir()
55 service = container_pool.Service(host_dir)
Ben Kwa14e76e52017-11-03 15:18:25 -070056 # Catch signals, and send the appropriate stop request to the service
57 # instead of killing the main thread.
58 # - SIGINT is generated by Ctrl-C
59 # - SIGTERM is generated by an upstart stopping event.
60 for sig in (signal.SIGINT, signal.SIGTERM):
61 signal.signal(sig, lambda s, f: service.stop())
62
Ben Kwa9b18c712017-12-13 15:38:56 -080063 with ts_mon_config.SetupTsMonGlobalState(service_name='lxc_pool_service',
64 indirect=True,
65 short_lived=False):
66 # Start the service. This blocks and does not return till the service
67 # shuts down.
68 service.start(pool_size=args.size)
Ben Kwa5e2bb5c2017-11-01 16:44:16 -070069
70
71def _status(_args):
72 """Requests status from the running container pool.
73
74 The retrieved status is printed out via logging.
75 """
76 with _create_client() as client:
77 logging.debug('Requesting status...')
78 logging.info(client.get_status())
79
80
81def _stop(_args):
82 """Shuts down the running container pool."""
83 with _create_client() as client:
84 logging.debug('Requesting stop...')
85 logging.info(client.shutdown())
86
87
88@contextmanager
89# TODO(kenobi): Don't hard-code the timeout.
90def _create_client(timeout=3):
91 logging.debug('Creating client...')
Ben Kwa5e2bb5c2017-11-01 16:44:16 -070092 address = os.path.join(lxc.SharedHostDir().path,
Ben Kwa181814d2017-11-03 09:27:58 -070093 lxc.DEFAULT_CONTAINER_POOL_SOCKET)
Ben Kwa5e2bb5c2017-11-01 16:44:16 -070094 with container_pool.Client.connect(address, timeout) as connection:
95 yield connection
96
97
98def parse_args():
99 """Parse command line inputs.
100
101 @raise argparse.ArgumentError: If command line arguments are invalid.
102 """
103 parser = argparse.ArgumentParser()
Ben Kwa5e2bb5c2017-11-01 16:44:16 -0700104
Ben Kwa181814d2017-11-03 09:27:58 -0700105 parser.add_argument('-v', '--verbose',
106 help='Enable verbose output.',
107 action='store_true')
Ben Kwa5e2bb5c2017-11-01 16:44:16 -0700108
Ben Kwa181814d2017-11-03 09:27:58 -0700109 subparsers = parser.add_subparsers(title='Commands')
Ben Kwa5e2bb5c2017-11-01 16:44:16 -0700110
Ben Kwa181814d2017-11-03 09:27:58 -0700111 parser_start = subparsers.add_parser('start',
112 help='Start the LXC container pool.')
113 parser_start.set_defaults(func=_start)
114 parser_start.add_argument('--size',
115 type=int,
116 default=lxc.DEFAULT_CONTAINER_POOL_SIZE,
117 help='Pool size (default=%d)' %
118 lxc.DEFAULT_CONTAINER_POOL_SIZE)
119
120 parser_stop = subparsers.add_parser('stop',
121 help='Stop the container pool.')
122 parser_stop.set_defaults(func=_stop)
123
124 parser_status = subparsers.add_parser('status',
125 help='Query pool status.')
126 parser_status.set_defaults(func=_status)
Ben Kwa5e2bb5c2017-11-01 16:44:16 -0700127
128 options = parser.parse_args()
129 return options
130
131
132def main():
133 """Main function."""
Ben Kwa181814d2017-11-03 09:27:58 -0700134 # Parse args
135 args = parse_args()
136
Ben Kwa181814d2017-11-03 09:27:58 -0700137 # Dispatch control to the appropriate helper.
Ben Kwa5e2bb5c2017-11-01 16:44:16 -0700138 args.func(args)
139
140
141if __name__ == '__main__':
142 main()