summaryrefslogtreecommitdiff
path: root/tempest/cmd/init.py
blob: 3eae5522d1a79e6b041a1d00a8eb86daf0a6e0f4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# 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 configparser
import os
import shutil
import sys

from cliff import command
from oslo_config import generator
from oslo_log import log as logging
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 = 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)