# Copyright 2015 Hewlett-Packard Development Company, L.P. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import os import shutil import sys from cliff import command from oslo_config import generator from oslo_log import log as logging from six import moves from stestr import commands from tempest.cmd import workspace LOG = logging.getLogger(__name__) STESTR_CONF = r"""[DEFAULT] test_path=%s top_dir=%s group_regex=([^\.]*\.)* """ def get_tempest_default_config_dir(): """Get default config directory of tempest There are 3 dirs that get tried in priority order. First is /etc/tempest, if that doesn't exist it looks for a tempest dir in the XDG_CONFIG_HOME dir (defaulting to ~/.config/tempest) and last it tries for a ~/.tempest/etc directory. If none of these exist a ~/.tempest/etc directory will be created. :return: default config dir """ # NOTE: The default directory should be on a Linux box. global_conf_dir = '/etc/tempest' xdg_config = os.environ.get('XDG_CONFIG_HOME', os.path.expanduser(os.path.join('~', '.config'))) user_xdg_global_path = os.path.join(xdg_config, 'tempest') user_global_path = os.path.join(os.path.expanduser('~'), '.tempest', 'etc') if os.path.isdir(global_conf_dir): return global_conf_dir elif os.path.isdir(user_xdg_global_path): return user_xdg_global_path elif os.path.isdir(user_global_path): return user_global_path else: os.makedirs(user_global_path) return user_global_path class TempestInit(command.Command): """Setup a local working environment for running tempest""" def get_parser(self, prog_name): parser = super(TempestInit, self).get_parser(prog_name) parser.add_argument('dir', nargs='?', default=os.getcwd(), help="The path to the workspace directory. If you " "omit this argument, the workspace directory is " "your current directory") parser.add_argument('--config-dir', '-c', default=None) parser.add_argument('--show-global-config-dir', '-s', action='store_true', dest='show_global_dir', help="Print the global config dir location, " "then exit") parser.add_argument('--name', help="The workspace name", default=None) parser.add_argument('--workspace-path', default=None, help="The path to the workspace file, the default " "is ~/.tempest/workspace.yaml") return parser def generate_stestr_conf(self, local_path): stestr_conf_path = os.path.join(local_path, '.stestr.conf') top_level_path = os.path.dirname(os.path.dirname(__file__)) discover_path = os.path.join(top_level_path, 'test_discover') stestr_conf = STESTR_CONF % (discover_path, top_level_path) with open(stestr_conf_path, 'w+') as stestr_conf_file: stestr_conf_file.write(stestr_conf) def get_configparser(self, conf_path): config_parse = moves.configparser.ConfigParser() config_parse.optionxform = str # get any existing values if a config file already exists if os.path.isfile(conf_path): # use read() for Python 2 and 3 compatibility config_parse.read(conf_path) return config_parse def update_local_conf(self, conf_path, lock_dir, log_dir): config_parse = self.get_configparser(conf_path) # Set local lock_dir in tempest conf if not config_parse.has_section('oslo_concurrency'): config_parse.add_section('oslo_concurrency') config_parse.set('oslo_concurrency', 'lock_path', lock_dir) # Set local log_dir in tempest conf config_parse.set('DEFAULT', 'log_dir', log_dir) # Set default log filename to tempest.log config_parse.set('DEFAULT', 'log_file', 'tempest.log') # write out a new file with the updated configurations with open(conf_path, 'w+') as conf_file: config_parse.write(conf_file) def copy_config(self, etc_dir, config_dir): if os.path.isdir(config_dir): shutil.copytree(config_dir, etc_dir) else: LOG.warning("Global config dir %s can't be found", config_dir) def generate_sample_config(self, local_dir): conf_generator = os.path.join(os.path.dirname(__file__), 'config-generator.tempest.conf') output_file = os.path.join(local_dir, 'etc', 'tempest.conf.sample') if os.path.isfile(conf_generator): generator.main(['--config-file', conf_generator, '--output-file', output_file]) else: LOG.warning("Skipping sample config generation because global " "config file %s can't be found", conf_generator) def create_working_dir(self, local_dir, config_dir): # make sure we are working with abspath however tempest init is called local_dir = os.path.abspath(local_dir) # Create local dir if missing if not os.path.isdir(local_dir): LOG.debug('Creating local working dir: %s', local_dir) os.mkdir(local_dir) elif os.listdir(local_dir): raise OSError("Directory you are trying to initialize already " "exists and is not empty: %s" % local_dir) lock_dir = os.path.join(local_dir, 'tempest_lock') etc_dir = os.path.join(local_dir, 'etc') config_path = os.path.join(etc_dir, 'tempest.conf') log_dir = os.path.join(local_dir, 'logs') stestr_dir = os.path.join(local_dir, '.stestr') # Create lock dir if not os.path.isdir(lock_dir): LOG.debug('Creating lock dir: %s', lock_dir) os.mkdir(lock_dir) # Create log dir if not os.path.isdir(log_dir): LOG.debug('Creating log dir: %s', log_dir) os.mkdir(log_dir) # Create and copy local etc dir self.copy_config(etc_dir, config_dir) # Generate the sample config file self.generate_sample_config(local_dir) # Update local confs to reflect local paths self.update_local_conf(config_path, lock_dir, log_dir) # Generate a stestr conf file self.generate_stestr_conf(local_dir) # setup local stestr working dir if not os.path.isdir(stestr_dir): commands.init_command(repo_url=local_dir) def take_action(self, parsed_args): workspace_manager = workspace.WorkspaceManager( parsed_args.workspace_path) name = parsed_args.name or parsed_args.dir.split(os.path.sep)[-1] config_dir = parsed_args.config_dir or get_tempest_default_config_dir() if parsed_args.show_global_dir: print("Global config dir is located at: %s" % config_dir) sys.exit(0) self.create_working_dir(parsed_args.dir, config_dir) workspace_manager.register_new_workspace( name, parsed_args.dir, init=True)