Statistics
| Branch: | Tag: | Revision:

root / snf-tools / synnefo_tools / burnin / __init__.py @ a6e5a05f

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.projects_tests import QuotasTestSuite
51
from synnefo_tools.burnin.stale_tests import \
52
    StaleServersTestSuite, StaleFloatingIPsTestSuite, StaleNetworksTestSuite
53

    
54

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

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

    
76

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

    
81

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

    
89

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

    
97
    parser = optparse.OptionParser(**kwargs)  # pylint: disable=star-args
98
    parser.disable_interspersed_args()
99

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

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

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

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

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

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

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

    
235
    return (opts, args)
236

    
237

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

    
242

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

    
249

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

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

261
    """
262

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

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

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

    
275

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