Statistics
| Branch: | Tag: | Revision:

root / snf-tools / synnefo_tools / burnin / __init__.py @ 6c78720b

History | View | Annotate | Download (9.8 kB)

1
# Copyright 2013 GRNET S.A. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or
4
# without modification, are permitted provided that the following
5
# conditions are met:
6
#
7
#   1. Redistributions of source code must retain the above
8
#      copyright notice, this list of conditions and the following
9
#      disclaimer.
10
#
11
#   2. Redistributions in binary form must reproduce the above
12
#      copyright notice, this list of conditions and the following
13
#      disclaimer in the documentation and/or other materials
14
#      provided with the distribution.
15
#
16
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
# POSSIBILITY OF SUCH DAMAGE.
28
#
29
# The views and conclusions contained in the software and
30
# documentation are those of the authors and should not be
31
# interpreted as representing official policies, either expressed
32
# or implied, of GRNET S.A.
33

    
34
"""
35
Burnin: functional tests for Synnefo
36

37
"""
38

    
39
import sys
40
import optparse
41

    
42
from synnefo_tools import version
43
from synnefo_tools.burnin import common
44
from synnefo_tools.burnin.astakos_tests import AstakosTestSuite
45
from synnefo_tools.burnin.images_tests import \
46
    FlavorsTestSuite, ImagesTestSuite
47
from synnefo_tools.burnin.pithos_tests import PithosTestSuite
48
from synnefo_tools.burnin.server_tests import ServerTestSuite
49

    
50

    
51
# --------------------------------------------------------------------
52
# Define our TestSuites
53
TESTSUITES = [
54
    AstakosTestSuite,
55
    FlavorsTestSuite,
56
    ImagesTestSuite,
57
    PithosTestSuite,
58
    ServerTestSuite,
59
    ]
60

    
61
TSUITES_NAMES = [tsuite.__name__ for tsuite in TESTSUITES]
62

    
63

    
64
def string_to_class(names):
65
    """Convert class namesto class objects"""
66
    return [eval(name) for name in names]
67

    
68

    
69
# --------------------------------------------------------------------
70
# Parse arguments
71
def parse_comma(option, _, value, parser):
72
    """Parse comma separated arguments"""
73
    parse_input = [p.strip() for p in value.split(',')]
74
    setattr(parser.values, option.dest, parse_input)
75

    
76

    
77
def parse_arguments(args):
78
    """Parse burnin arguments"""
79
    kwargs = {}
80
    kwargs["usage"] = "%prog [options]"
81
    kwargs["description"] = \
82
        "%prog runs a number of test scenarios on a Synnefo deployment."
83

    
84
    # Used * or ** magic. pylint: disable-msg=W0142
85
    parser = optparse.OptionParser(**kwargs)
86
    parser.disable_interspersed_args()
87

    
88
    parser.add_option(
89
        "--auth-url", action="store",
90
        type="string", default=None, dest="auth_url",
91
        help="The AUTH URI to use to reach the Synnefo API")
92
    parser.add_option(
93
        "--token", action="store",
94
        type="string", default=None, dest="token",
95
        help="The token to use for authentication to the API")
96
    parser.add_option(
97
        "--failfast", action="store_true",
98
        default=False, dest="failfast",
99
        help="Fail immediately if one of the tests fails")
100
    parser.add_option(
101
        "--no-ipv6", action="store_false",
102
        default=True, dest="use_ipv6",
103
        help="Disable IPv6 related tests")
104
    parser.add_option(
105
        "--action-timeout", action="store",
106
        type="int", default=300, dest="action_timeout", metavar="TIMEOUT",
107
        help="Wait TIMEOUT seconds for a server action to complete, "
108
             "then the test is considered failed")
109
    parser.add_option(
110
        "--action-warning", action="store",
111
        type="int", default=120, dest="action_warning", metavar="TIMEOUT",
112
        help="Warn if TIMEOUT seconds have passed and a server action "
113
             "has not been completed yet")
114
    parser.add_option(
115
        "--query-interval", action="store",
116
        type="int", default=3, dest="query_interval", metavar="INTERVAL",
117
        help="Query server status when requests are pending "
118
             "every INTERVAL seconds")
119
    parser.add_option(
120
        "--flavors", action="callback", callback=parse_comma,
121
        type="string", default=None, dest="flavors", metavar="FLAVORS",
122
        help="Force all server creations to use one of the specified FLAVORS "
123
             "instead of a randomly chosen one. Supports both search by name "
124
             "(reg expression) with \"name:flavor name\" or by id with "
125
             "\"id:flavor id\"")
126
    parser.add_option(
127
        "--images", action="callback", callback=parse_comma,
128
        type="string", default=None, dest="images", metavar="IMAGES",
129
        help="Force all server creations to use one of the specified IMAGES "
130
             "instead of the default one (a Debian Base image). Just like the "
131
             "--flavors option, it supports both search by name and id")
132
    parser.add_option(
133
        "--system-user", action="store",
134
        type="string", default=None, dest="system_user",
135
        help="Owner of system images (typed option in the form of "
136
             "\"name:user_name\" or \"id:uuuid\")")
137
    parser.add_option(
138
        "--show-stale", action="store_true",
139
        default=False, dest="show_stale",
140
        help="Show stale servers from previous runs. A server is considered "
141
             "stale if its name starts with `%s'. If stale servers are found, "
142
             "exit with exit status 1." % common.SNF_TEST_PREFIX)
143
    parser.add_option(
144
        "--delete-stale", action="store_true",
145
        default=False, dest="delete_stale",
146
        help="Delete stale servers from previous runs")
147
    parser.add_option(
148
        "--log-folder", action="store",
149
        type="string", default="/var/log/burnin/", dest="log_folder",
150
        help="Define the absolute path where the output log is stored")
151
    parser.add_option(
152
        "--verbose", "-v", action="store",
153
        type="int", default=1, dest="verbose",
154
        help="Print detailed output messages")
155
    parser.add_option(
156
        "--version", action="store_true",
157
        default=False, dest="show_version",
158
        help="Show version and exit")
159
    parser.add_option(
160
        "--set-tests", action="callback", callback=parse_comma,
161
        type="string", default="all", dest="tests",
162
        help="Set comma separated tests for this run. Available tests: %s"
163
             % ", ".join(TSUITES_NAMES))
164
    parser.add_option(
165
        "--exclude-tests", action="callback", callback=parse_comma,
166
        type="string", default=None, dest="exclude_tests",
167
        help="Set comma separated tests to be excluded for this run.")
168
    parser.add_option(
169
        "--no-colors", action="store_false",
170
        default=True, dest="use_colors",
171
        help="Disable colorful output")
172
    parser.add_option(
173
        "--quiet", action="store_true",
174
        default=False, dest="quiet",
175
        help="Turn off log output")
176
    parser.add_option(
177
        "--final-report-only", action="store_true",
178
        default=False, dest="final_report",
179
        help="Turn off log output and only print the contents of the log "
180
             "file at the end of the test. Useful when burnin is used in "
181
             "script files and it's output is to be sent using email")
182

    
183
    (opts, args) = parser.parse_args(args)
184

    
185
    # ----------------------------------
186
    # Verify arguments
187
    # If `version' is given show version and exit
188
    if opts.show_version:
189
        show_version()
190
        sys.exit(0)
191

    
192
    # `delete_stale' implies `show_stale'
193
    if opts.delete_stale:
194
        opts.show_stale = True
195

    
196
    # `quiet' implies not `final_report'
197
    if opts.quiet:
198
        opts.final_report = False
199
    # `final_report' implies `quiet'
200
    if opts.final_report:
201
        opts.quiet = True
202

    
203
    # Check `--set-tests' and `--exclude-tests' options
204
    if opts.tests != "all" and \
205
            not (set(opts.tests)).issubset(set(TSUITES_NAMES)):
206
        raise optparse.OptionValueError("The selected set of tests is invalid")
207
    if opts.exclude_tests is not None and \
208
            not (set(opts.exclude_tests)).issubset(set(TSUITES_NAMES)):
209
        raise optparse.OptionValueError("The selected set of tests is invalid")
210

    
211
    # `token' is mandatory
212
    mandatory_argument(opts.token, "--token")
213
    # `auth_url' is mandatory
214
    mandatory_argument(opts.auth_url, "--auth-url")
215

    
216
    return (opts, args)
217

    
218

    
219
def show_version():
220
    """Show burnin's version"""
221
    sys.stdout.write("Burnin: version %s\n" % version.__version__)
222

    
223

    
224
def mandatory_argument(value, arg_name):
225
    """Check if a mandatory argument is given"""
226
    if (value is None) or (value == ""):
227
        sys.stderr.write("The " + arg_name + " argument is mandatory.\n")
228
        sys.exit("Invalid input")
229

    
230

    
231
# --------------------------------------------------------------------
232
# Burnin main function
233
def main():
234
    """Assemble test cases into a test suite, and run it
235

236
    IMPORTANT: Tests have dependencies and have to be run in the specified
237
    order inside a single test case. They communicate through attributes of the
238
    corresponding TestCase class (shared fixtures). Distinct subclasses of
239
    TestCase MAY SHARE NO DATA, since they are run in parallel, in distinct
240
    test runner processes.
241

242
    """
243

    
244
    # Parse arguments using `optparse'
245
    (opts, _) = parse_arguments(sys.argv[1:])
246

    
247
    # Initialize burnin
248
    testsuites = common.initialize(opts, TSUITES_NAMES)
249
    testsuites = string_to_class(testsuites)
250

    
251
    # Run burnin
252
    # The return value denotes the success status
253
    return common.run_burnin(testsuites, failfast=opts.failfast,
254
                             final_report=opts.final_report)
255

    
256

    
257
if __name__ == "__main__":
258
    sys.exit(main())