Matthew Treinish | f610aca | 2015-06-30 15:32:34 -0400 | [diff] [blame] | 1 | # Copyright 2015 Hewlett-Packard Development Company, L.P. |
| 2 | # |
| 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may |
| 4 | # not use this file except in compliance with the License. You may obtain |
| 5 | # a copy of the License at |
| 6 | # |
| 7 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | # |
| 9 | # Unless required by applicable law or agreed to in writing, software |
| 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| 12 | # License for the specific language governing permissions and limitations |
| 13 | # under the License. |
| 14 | |
| 15 | import os |
| 16 | import shutil |
Andrea Frittoli (andreaf) | 5a69e55 | 2015-07-31 18:40:17 +0100 | [diff] [blame] | 17 | import sys |
Matthew Treinish | f610aca | 2015-06-30 15:32:34 -0400 | [diff] [blame] | 18 | |
| 19 | from cliff import command |
Matthew Treinish | bdef1c7 | 2016-06-21 18:06:49 -0400 | [diff] [blame] | 20 | from oslo_config import generator |
Matthew Treinish | f610aca | 2015-06-30 15:32:34 -0400 | [diff] [blame] | 21 | from oslo_log import log as logging |
| 22 | from six import moves |
Chandan Kumar | 8a4396e | 2017-09-15 12:18:10 +0530 | [diff] [blame] | 23 | from stestr import commands |
Matthew Treinish | f610aca | 2015-06-30 15:32:34 -0400 | [diff] [blame] | 24 | |
Cao Xuan Hoang | 36fe23c | 2016-08-25 16:11:14 +0700 | [diff] [blame] | 25 | from tempest.cmd import workspace |
step6829 | 80c14ec | 2016-02-23 14:53:52 -0500 | [diff] [blame] | 26 | |
Matthew Treinish | f610aca | 2015-06-30 15:32:34 -0400 | [diff] [blame] | 27 | LOG = logging.getLogger(__name__) |
| 28 | |
Stephen Finucane | 7f4a621 | 2018-07-06 13:58:21 +0100 | [diff] [blame] | 29 | STESTR_CONF = r"""[DEFAULT] |
Chandan Kumar | 8a4396e | 2017-09-15 12:18:10 +0530 | [diff] [blame] | 30 | test_path=%s |
| 31 | top_dir=%s |
Matthew Treinish | f610aca | 2015-06-30 15:32:34 -0400 | [diff] [blame] | 32 | group_regex=([^\.]*\.)* |
| 33 | """ |
| 34 | |
| 35 | |
Andrea Frittoli (andreaf) | 5a69e55 | 2015-07-31 18:40:17 +0100 | [diff] [blame] | 36 | def get_tempest_default_config_dir(): |
Ken'ichi Ohmichi | 2e2ee19 | 2015-11-19 09:48:27 +0000 | [diff] [blame] | 37 | """Get default config directory of tempest |
| 38 | |
Matthew Treinish | 3fe57b3 | 2016-06-21 14:39:00 -0400 | [diff] [blame] | 39 | There are 3 dirs that get tried in priority order. First is /etc/tempest, |
| 40 | if that doesn't exist it looks for a tempest dir in the XDG_CONFIG_HOME |
| 41 | dir (defaulting to ~/.config/tempest) and last it tries for a |
| 42 | ~/.tempest/etc directory. If none of these exist a ~/.tempest/etc |
| 43 | directory will be created. |
Andrea Frittoli (andreaf) | 5a69e55 | 2015-07-31 18:40:17 +0100 | [diff] [blame] | 44 | |
| 45 | :return: default config dir |
| 46 | """ |
Masayuki Igawa | 9e492ee | 2019-09-19 12:15:04 +0900 | [diff] [blame] | 47 | # NOTE: The default directory should be on a Linux box. |
Ken'ichi Ohmichi | 0ce1652 | 2016-04-23 12:52:05 -0700 | [diff] [blame] | 48 | global_conf_dir = '/etc/tempest' |
Matthew Treinish | 3fe57b3 | 2016-06-21 14:39:00 -0400 | [diff] [blame] | 49 | xdg_config = os.environ.get('XDG_CONFIG_HOME', |
Masayuki Igawa | 9e492ee | 2019-09-19 12:15:04 +0900 | [diff] [blame] | 50 | os.path.expanduser(os.path.join('~', |
| 51 | '.config'))) |
Matthew Treinish | 3fe57b3 | 2016-06-21 14:39:00 -0400 | [diff] [blame] | 52 | user_xdg_global_path = os.path.join(xdg_config, 'tempest') |
Masayuki Igawa | 9e492ee | 2019-09-19 12:15:04 +0900 | [diff] [blame] | 53 | user_global_path = os.path.join(os.path.expanduser('~'), |
| 54 | '.tempest', 'etc') |
Matthew Treinish | 3fe57b3 | 2016-06-21 14:39:00 -0400 | [diff] [blame] | 55 | if os.path.isdir(global_conf_dir): |
Ken'ichi Ohmichi | 0ce1652 | 2016-04-23 12:52:05 -0700 | [diff] [blame] | 56 | return global_conf_dir |
Matthew Treinish | 3fe57b3 | 2016-06-21 14:39:00 -0400 | [diff] [blame] | 57 | elif os.path.isdir(user_xdg_global_path): |
| 58 | return user_xdg_global_path |
| 59 | elif os.path.isdir(user_global_path): |
| 60 | return user_global_path |
Andrea Frittoli (andreaf) | 5a69e55 | 2015-07-31 18:40:17 +0100 | [diff] [blame] | 61 | else: |
Matthew Treinish | 3fe57b3 | 2016-06-21 14:39:00 -0400 | [diff] [blame] | 62 | os.makedirs(user_global_path) |
| 63 | return user_global_path |
Andrea Frittoli (andreaf) | 5a69e55 | 2015-07-31 18:40:17 +0100 | [diff] [blame] | 64 | |
| 65 | |
Matthew Treinish | f610aca | 2015-06-30 15:32:34 -0400 | [diff] [blame] | 66 | class TempestInit(command.Command): |
| 67 | """Setup a local working environment for running tempest""" |
| 68 | |
| 69 | def get_parser(self, prog_name): |
| 70 | parser = super(TempestInit, self).get_parser(prog_name) |
Masayuki Igawa | 0670a2b | 2016-09-12 14:55:11 +0900 | [diff] [blame] | 71 | parser.add_argument('dir', nargs='?', default=os.getcwd(), |
| 72 | help="The path to the workspace directory. If you " |
| 73 | "omit this argument, the workspace directory is " |
| 74 | "your current directory") |
Andrea Frittoli (andreaf) | 5a69e55 | 2015-07-31 18:40:17 +0100 | [diff] [blame] | 75 | parser.add_argument('--config-dir', '-c', default=None) |
Matthew Treinish | 054f45d | 2016-04-23 16:30:29 -0400 | [diff] [blame] | 76 | parser.add_argument('--show-global-config-dir', '-s', |
| 77 | action='store_true', dest='show_global_dir', |
| 78 | help="Print the global config dir location, " |
| 79 | "then exit") |
step6829 | 80c14ec | 2016-02-23 14:53:52 -0500 | [diff] [blame] | 80 | parser.add_argument('--name', help="The workspace name", default=None) |
| 81 | parser.add_argument('--workspace-path', default=None, |
| 82 | help="The path to the workspace file, the default " |
Masayuki Igawa | 0670a2b | 2016-09-12 14:55:11 +0900 | [diff] [blame] | 83 | "is ~/.tempest/workspace.yaml") |
Matthew Treinish | f610aca | 2015-06-30 15:32:34 -0400 | [diff] [blame] | 84 | return parser |
| 85 | |
Chandan Kumar | 8a4396e | 2017-09-15 12:18:10 +0530 | [diff] [blame] | 86 | def generate_stestr_conf(self, local_path): |
| 87 | stestr_conf_path = os.path.join(local_path, '.stestr.conf') |
Matthew Treinish | f610aca | 2015-06-30 15:32:34 -0400 | [diff] [blame] | 88 | top_level_path = os.path.dirname(os.path.dirname(__file__)) |
| 89 | discover_path = os.path.join(top_level_path, 'test_discover') |
Chandan Kumar | 8a4396e | 2017-09-15 12:18:10 +0530 | [diff] [blame] | 90 | stestr_conf = STESTR_CONF % (discover_path, top_level_path) |
| 91 | with open(stestr_conf_path, 'w+') as stestr_conf_file: |
| 92 | stestr_conf_file.write(stestr_conf) |
Matthew Treinish | f610aca | 2015-06-30 15:32:34 -0400 | [diff] [blame] | 93 | |
Matthew Treinish | 3c39bb6 | 2016-08-09 14:44:44 -0400 | [diff] [blame] | 94 | def get_configparser(self, conf_path): |
Janonymous | 8254a3f | 2016-09-15 10:38:48 +0530 | [diff] [blame] | 95 | config_parse = moves.configparser.ConfigParser() |
Matthew Treinish | f610aca | 2015-06-30 15:32:34 -0400 | [diff] [blame] | 96 | config_parse.optionxform = str |
Matthew Treinish | 3c39bb6 | 2016-08-09 14:44:44 -0400 | [diff] [blame] | 97 | # get any existing values if a config file already exists |
| 98 | if os.path.isfile(conf_path): |
| 99 | # use read() for Python 2 and 3 compatibility |
| 100 | config_parse.read(conf_path) |
| 101 | return config_parse |
| 102 | |
| 103 | def update_local_conf(self, conf_path, lock_dir, log_dir): |
| 104 | config_parse = self.get_configparser(conf_path) |
| 105 | # Set local lock_dir in tempest conf |
| 106 | if not config_parse.has_section('oslo_concurrency'): |
| 107 | config_parse.add_section('oslo_concurrency') |
| 108 | config_parse.set('oslo_concurrency', 'lock_path', lock_dir) |
| 109 | # Set local log_dir in tempest conf |
| 110 | config_parse.set('DEFAULT', 'log_dir', log_dir) |
| 111 | # Set default log filename to tempest.log |
| 112 | config_parse.set('DEFAULT', 'log_file', 'tempest.log') |
| 113 | |
| 114 | # write out a new file with the updated configurations |
| 115 | with open(conf_path, 'w+') as conf_file: |
ghanshyam | 0e1dd84 | 2016-04-27 07:59:23 +0900 | [diff] [blame] | 116 | config_parse.write(conf_file) |
Matthew Treinish | f610aca | 2015-06-30 15:32:34 -0400 | [diff] [blame] | 117 | |
| 118 | def copy_config(self, etc_dir, config_dir): |
Matthew Treinish | d5cef95 | 2016-06-07 16:54:55 -0400 | [diff] [blame] | 119 | if os.path.isdir(config_dir): |
| 120 | shutil.copytree(config_dir, etc_dir) |
| 121 | else: |
Jordan Pittier | 525ec71 | 2016-12-07 17:51:26 +0100 | [diff] [blame] | 122 | LOG.warning("Global config dir %s can't be found", config_dir) |
Matthew Treinish | f610aca | 2015-06-30 15:32:34 -0400 | [diff] [blame] | 123 | |
Matthew Treinish | bdef1c7 | 2016-06-21 18:06:49 -0400 | [diff] [blame] | 124 | def generate_sample_config(self, local_dir): |
| 125 | conf_generator = os.path.join(os.path.dirname(__file__), |
| 126 | 'config-generator.tempest.conf') |
Masayuki Igawa | 9e492ee | 2019-09-19 12:15:04 +0900 | [diff] [blame] | 127 | output_file = os.path.join(local_dir, 'etc', 'tempest.conf.sample') |
Matthew Treinish | bdef1c7 | 2016-06-21 18:06:49 -0400 | [diff] [blame] | 128 | if os.path.isfile(conf_generator): |
| 129 | generator.main(['--config-file', conf_generator, '--output-file', |
| 130 | output_file]) |
Matthew Treinish | d5cef95 | 2016-06-07 16:54:55 -0400 | [diff] [blame] | 131 | else: |
| 132 | LOG.warning("Skipping sample config generation because global " |
Jordan Pittier | 525ec71 | 2016-12-07 17:51:26 +0100 | [diff] [blame] | 133 | "config file %s can't be found", conf_generator) |
Matthew Treinish | c8a39b4 | 2015-07-27 17:07:37 -0400 | [diff] [blame] | 134 | |
Matthew Treinish | f610aca | 2015-06-30 15:32:34 -0400 | [diff] [blame] | 135 | def create_working_dir(self, local_dir, config_dir): |
Jake Yip | 9346483 | 2016-06-18 00:57:40 +1000 | [diff] [blame] | 136 | # make sure we are working with abspath however tempest init is called |
| 137 | local_dir = os.path.abspath(local_dir) |
Matthew Treinish | f610aca | 2015-06-30 15:32:34 -0400 | [diff] [blame] | 138 | # Create local dir if missing |
| 139 | if not os.path.isdir(local_dir): |
Jordan Pittier | 525ec71 | 2016-12-07 17:51:26 +0100 | [diff] [blame] | 140 | LOG.debug('Creating local working dir: %s', local_dir) |
Matthew Treinish | f610aca | 2015-06-30 15:32:34 -0400 | [diff] [blame] | 141 | os.mkdir(local_dir) |
wangqi | 814a87c | 2018-04-19 02:31:40 +0000 | [diff] [blame] | 142 | elif os.listdir(local_dir): |
David Paterson | 0bf52d4 | 2015-04-13 21:55:58 -0400 | [diff] [blame] | 143 | raise OSError("Directory you are trying to initialize already " |
Marc Koderer | 090b5dc | 2015-11-04 10:35:48 +0100 | [diff] [blame] | 144 | "exists and is not empty: %s" % local_dir) |
David Paterson | 0bf52d4 | 2015-04-13 21:55:58 -0400 | [diff] [blame] | 145 | |
Matthew Treinish | f610aca | 2015-06-30 15:32:34 -0400 | [diff] [blame] | 146 | lock_dir = os.path.join(local_dir, 'tempest_lock') |
| 147 | etc_dir = os.path.join(local_dir, 'etc') |
| 148 | config_path = os.path.join(etc_dir, 'tempest.conf') |
| 149 | log_dir = os.path.join(local_dir, 'logs') |
Chandan Kumar | 8a4396e | 2017-09-15 12:18:10 +0530 | [diff] [blame] | 150 | stestr_dir = os.path.join(local_dir, '.stestr') |
Matthew Treinish | f610aca | 2015-06-30 15:32:34 -0400 | [diff] [blame] | 151 | # Create lock dir |
| 152 | if not os.path.isdir(lock_dir): |
Jordan Pittier | 525ec71 | 2016-12-07 17:51:26 +0100 | [diff] [blame] | 153 | LOG.debug('Creating lock dir: %s', lock_dir) |
Matthew Treinish | f610aca | 2015-06-30 15:32:34 -0400 | [diff] [blame] | 154 | os.mkdir(lock_dir) |
| 155 | # Create log dir |
| 156 | if not os.path.isdir(log_dir): |
Jordan Pittier | 525ec71 | 2016-12-07 17:51:26 +0100 | [diff] [blame] | 157 | LOG.debug('Creating log dir: %s', log_dir) |
Matthew Treinish | f610aca | 2015-06-30 15:32:34 -0400 | [diff] [blame] | 158 | os.mkdir(log_dir) |
| 159 | # Create and copy local etc dir |
| 160 | self.copy_config(etc_dir, config_dir) |
Matthew Treinish | c8a39b4 | 2015-07-27 17:07:37 -0400 | [diff] [blame] | 161 | # Generate the sample config file |
Matthew Treinish | bdef1c7 | 2016-06-21 18:06:49 -0400 | [diff] [blame] | 162 | self.generate_sample_config(local_dir) |
Matthew Treinish | f610aca | 2015-06-30 15:32:34 -0400 | [diff] [blame] | 163 | # Update local confs to reflect local paths |
| 164 | self.update_local_conf(config_path, lock_dir, log_dir) |
Chandan Kumar | 8a4396e | 2017-09-15 12:18:10 +0530 | [diff] [blame] | 165 | # Generate a stestr conf file |
| 166 | self.generate_stestr_conf(local_dir) |
| 167 | # setup local stestr working dir |
| 168 | if not os.path.isdir(stestr_dir): |
| 169 | commands.init_command(repo_url=local_dir) |
Matthew Treinish | f610aca | 2015-06-30 15:32:34 -0400 | [diff] [blame] | 170 | |
| 171 | def take_action(self, parsed_args): |
Cao Xuan Hoang | 36fe23c | 2016-08-25 16:11:14 +0700 | [diff] [blame] | 172 | workspace_manager = workspace.WorkspaceManager( |
| 173 | parsed_args.workspace_path) |
step6829 | 80c14ec | 2016-02-23 14:53:52 -0500 | [diff] [blame] | 174 | name = parsed_args.name or parsed_args.dir.split(os.path.sep)[-1] |
Andrea Frittoli (andreaf) | 5a69e55 | 2015-07-31 18:40:17 +0100 | [diff] [blame] | 175 | config_dir = parsed_args.config_dir or get_tempest_default_config_dir() |
Matthew Treinish | 054f45d | 2016-04-23 16:30:29 -0400 | [diff] [blame] | 176 | if parsed_args.show_global_dir: |
| 177 | print("Global config dir is located at: %s" % config_dir) |
| 178 | sys.exit(0) |
Andrea Frittoli (andreaf) | 5a69e55 | 2015-07-31 18:40:17 +0100 | [diff] [blame] | 179 | self.create_working_dir(parsed_args.dir, config_dir) |
Masayuki Igawa | f802641 | 2016-09-12 17:12:35 +0900 | [diff] [blame] | 180 | workspace_manager.register_new_workspace( |
| 181 | name, parsed_args.dir, init=True) |