Statistics
| Branch: | Tag: | Revision:

root / snf-tools / synnefo_tools / burnin / __init__.py @ 100feeda

History | View | Annotate | Download (10.5 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
from synnefo_tools.burnin.network_tests import NetworkTestSuite
50
from synnefo_tools.burnin.stale_tests import \
51
    StaleServersTestSuite, StaleFloatingIPsTestSuite, StaleNetworksTestSuite
52

    
53

    
54
# --------------------------------------------------------------------
55
# Define our TestSuites
56
TESTSUITES = [
57
    AstakosTestSuite,
58
    FlavorsTestSuite,
59
    ImagesTestSuite,
60
    PithosTestSuite,
61
    ServerTestSuite,
62
    NetworkTestSuite,
63
]
64
TSUITES_NAMES = [tsuite.__name__ for tsuite in TESTSUITES]
65

    
66
STALE_TESTSUITES = [
67
    # Must be runned in this order
68
    StaleServersTestSuite,
69
    StaleFloatingIPsTestSuite,
70
    StaleNetworksTestSuite,
71
]
72
STALE_TSUITES_NAMES = [tsuite.__name__ for tsuite in STALE_TESTSUITES]
73

    
74

    
75
def string_to_class(names):
76
    """Convert class namesto class objects"""
77
    return [eval(name) for name in names]
78

    
79

    
80
# --------------------------------------------------------------------
81
# Parse arguments
82
def parse_comma(option, _, value, parser):
83
    """Parse comma separated arguments"""
84
    parse_input = [p.strip() for p in value.split(',')]
85
    setattr(parser.values, option.dest, parse_input)
86

    
87

    
88
def parse_arguments(args):
89
    """Parse burnin arguments"""
90
    kwargs = {}
91
    kwargs["usage"] = "%prog [options]"
92
    kwargs["description"] = \
93
        "%prog runs a number of test scenarios on a Synnefo deployment."
94

    
95
    # Used * or ** magic. pylint: disable-msg=W0142
96
    parser = optparse.OptionParser(**kwargs)
97
    parser.disable_interspersed_args()
98

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

    
198
    (opts, args) = parser.parse_args(args)
199

    
200
    # ----------------------------------
201
    # Verify arguments
202
    # If `version' is given show version and exit
203
    if opts.show_version:
204
        show_version()
205
        sys.exit(0)
206

    
207
    # `delete_stale' implies `show_stale'
208
    if opts.delete_stale:
209
        opts.show_stale = True
210

    
211
    # log_level:
212
    #  0 -> log to console and file
213
    #  1 -> log to file and output the results in console
214
    #  2 -> don't log
215
    opts.log_level = 0
216
    if opts.final_report:
217
        opts.log_level = 1
218
    if opts.quiet:
219
        opts.log_level = 2
220

    
221
    # Check `--set-tests' and `--exclude-tests' options
222
    if opts.tests != "all" and \
223
            not (set(opts.tests)).issubset(set(TSUITES_NAMES)):
224
        raise optparse.OptionValueError("The selected set of tests is invalid")
225
    if opts.exclude_tests is not None and \
226
            not (set(opts.exclude_tests)).issubset(set(TSUITES_NAMES)):
227
        raise optparse.OptionValueError("The selected set of tests is invalid")
228

    
229
    # `token' is mandatory
230
    mandatory_argument(opts.token, "--token")
231
    # `auth_url' is mandatory
232
    mandatory_argument(opts.auth_url, "--auth-url")
233

    
234
    return (opts, args)
235

    
236

    
237
def show_version():
238
    """Show burnin's version"""
239
    sys.stdout.write("Burnin: version %s\n" % version.__version__)
240

    
241

    
242
def mandatory_argument(value, arg_name):
243
    """Check if a mandatory argument is given"""
244
    if (value is None) or (value == ""):
245
        sys.stderr.write("The " + arg_name + " argument is mandatory.\n")
246
        sys.exit("Invalid input")
247

    
248

    
249
# --------------------------------------------------------------------
250
# Burnin main function
251
def main():
252
    """Assemble test cases into a test suite, and run it
253

254
    IMPORTANT: Tests have dependencies and have to be run in the specified
255
    order inside a single test case. They communicate through attributes of the
256
    corresponding TestCase class (shared fixtures). Distinct subclasses of
257
    TestCase MAY SHARE NO DATA, since they are run in parallel, in distinct
258
    test runner processes.
259

260
    """
261

    
262
    # Parse arguments using `optparse'
263
    (opts, _) = parse_arguments(sys.argv[1:])
264

    
265
    # Initialize burnin
266
    (testsuites, failfast) = \
267
        common.initialize(opts, TSUITES_NAMES, STALE_TSUITES_NAMES)
268
    testsuites = string_to_class(testsuites)
269

    
270
    # Run burnin
271
    # The return value denotes the success status
272
    return common.run_burnin(testsuites, failfast=failfast)
273

    
274

    
275
if __name__ == "__main__":
276
    sys.exit(main())