Added support for offline testing
[snaps.git] / snaps / custom_image_test_runner.py
1 # Copyright (c) 2017 Cable Television Laboratories, Inc. ("CableLabs")
2 #                    and others.  All rights reserved.
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at:
7 #
8 #     http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 import argparse
16 import logging
17 import os
18 import unittest
19
20 from snaps import test_suite_builder
21 from snaps.openstack.create_image import OpenStackImage
22 from snaps.openstack.tests import openstack_tests
23 from snaps.openstack.tests.os_source_file_test import OSComponentTestCase
24 from snaps.openstack.utils.tests.glance_utils_tests import GlanceUtilsTests
25
26 __author__ = 'spisarski'
27
28 logger = logging.getLogger('custom_image_test_runner')
29
30 ARG_NOT_SET = "argument not set"
31 LOG_LEVELS = {'FATAL': logging.FATAL, 'CRITICAL': logging.CRITICAL, 'ERROR': logging.ERROR, 'WARN': logging.WARN,
32               'INFO': logging.INFO, 'DEBUG': logging.DEBUG}
33
34
35 def __run_tests(source_filename, ext_net_name, proxy_settings, ssh_proxy_cmd, use_keystone, use_floating_ips,
36                 log_level):
37     """
38     Compiles the tests that should run
39     :param source_filename: the OpenStack credentials file (required)
40     :param ext_net_name: the name of the external network to use for floating IPs (required)
41     :param proxy_settings: <host>:<port> of the proxy server (optional)
42     :param ssh_proxy_cmd: the command used to connect via SSH over some proxy server (optional)
43     :param use_keystone: when true, tests creating users and projects will be exercised and must be run on a host that
44                          has access to the cloud's administrative network
45     :param use_floating_ips: when true, tests requiring floating IPs will be executed
46     :param log_level: the logging level
47     :return:
48     """
49     os_creds = openstack_tests.get_credentials(os_env_file=source_filename, proxy_settings_str=proxy_settings,
50                                                ssh_proxy_cmd=ssh_proxy_cmd)
51     # To ensure any files referenced via a relative path will begin from the diectory in which this file resides
52     os.chdir(os.path.dirname(os.path.realpath(__file__)))
53
54     image_creators = __create_images(os_creds)
55
56     meta_list = list()
57
58     # Create images from default
59     meta_list.append(None)
60
61     # Create images from specified URL
62     meta_list.append(
63         {'glance_tests': {'disk_url': openstack_tests.CIRROS_DEFAULT_IMAGE_URL},
64          'cirros': {'disk_url': openstack_tests.CIRROS_DEFAULT_IMAGE_URL},
65          'centos': {'disk_url': openstack_tests.CENTOS_DEFAULT_IMAGE_URL},
66          'ubuntu': {'disk_url': openstack_tests.UBUNTU_DEFAULT_IMAGE_URL}})
67
68     # Create images from file
69     meta_list.append(
70         {'glance_tests': {'disk_file': '../images/cirros-0.3.4-x86_64-disk.img'},
71          'cirros': {'disk_file': '../images/cirros-0.3.4-x86_64-disk.img'},
72          'centos': {'disk_file': '../images/CentOS-7-x86_64-GenericCloud.qcow2'},
73          'ubuntu': {'disk_file': '../images/ubuntu-14.04-server-cloudimg-amd64-disk1.img'}})
74
75     # Create images from Existing
76     meta_list.append(
77         {'glance_tests': {'disk_file': '../images/cirros-0.3.4-x86_64-disk.img'},
78          'cirros': {'config': {'name': image_creators['cirros'].image_settings.name,
79                                'exists': True, 'image_user': 'cirros'}},
80          'centos': {'config': {'name': image_creators['centos'].image_settings.name,
81                                'exists': True, 'image_user': 'centos'}},
82          'ubuntu': {'config': {'name': image_creators['ubuntu'].image_settings.name,
83                                'exists': True, 'image_user': 'ubuntu'}}})
84
85     failure_count = 0
86     error_count = 0
87
88     try:
89         for metadata in meta_list:
90             logger.info('Starting tests with image metadata of - ' + str(metadata))
91             suite = unittest.TestSuite()
92
93             # Long running integration type tests
94             suite.addTest(OSComponentTestCase.parameterize(
95                 GlanceUtilsTests, os_creds=os_creds, ext_net_name=ext_net_name, image_metadata=metadata,
96                 log_level=log_level))
97
98             test_suite_builder.add_openstack_integration_tests(
99                 suite=suite, os_creds=os_creds, ext_net_name=ext_net_name, use_keystone=use_keystone,
100                 image_metadata=metadata, use_floating_ips=use_floating_ips, log_level=log_level)
101
102             result = unittest.TextTestRunner(verbosity=2).run(suite)
103             if result.errors:
104                 logger.error('Number of errors in test suite - ' + str(len(result.errors)))
105                 for test, message in result.errors:
106                     logger.error(str(test) + " ERROR with " + message)
107                     error_count += 1
108
109             if result.failures:
110                 logger.error('Number of failures in test suite - ' + str(len(result.failures)))
111                 for test, message in result.failures:
112                     logger.error(str(test) + " FAILED with " + message)
113                     failure_count += 1
114
115             if (result.errors and len(result.errors) > 0) or (result.failures and len(result.failures) > 0):
116                 logger.error('See above for test failures')
117             else:
118                 logger.info('All tests completed successfully in run')
119
120         logger.info('Total number of errors = ' + str(error_count))
121         logger.info('Total number of failures = ' + str(failure_count))
122
123         if error_count + failure_count > 0:
124             exit(1)
125     except Exception as e:
126         logger.warn('Unexpected error running tests - %s', e)
127         pass
128     finally:
129         for image_creator in image_creators.values():
130             try:
131                 image_creator.clean()
132             except Exception as e:
133                 logger.error('Exception thrown while cleaning image - %s', e)
134
135
136 def __create_images(os_creds):
137     """
138     Returns a dictionary of 
139     :param os_creds: 
140     :return: 
141     """
142     image_meta = {'cirros': {'disk_url': openstack_tests.CIRROS_DEFAULT_IMAGE_URL,
143                              'kernel_url': openstack_tests.CIRROS_DEFAULT_KERNEL_IMAGE_URL,
144                              'ramdisk_url': openstack_tests.CIRROS_DEFAULT_RAMDISK_IMAGE_URL},
145                   'centos': {'disk_file': '../images/CentOS-7-x86_64-GenericCloud.qcow2'},
146                   'ubuntu': {'disk_file': '../images/ubuntu-14.04-server-cloudimg-amd64-disk1.img'}}
147     cirros_image_settings = openstack_tests.cirros_image_settings(name='static_image_test-cirros',
148                                                                   image_metadata=image_meta, public=True)
149     centos_image_settings = openstack_tests.centos_image_settings(name='static_image_test-centos',
150                                                                   image_metadata=image_meta, public=True)
151     ubuntu_image_settings = openstack_tests.ubuntu_image_settings(name='static_image_test-ubuntu',
152                                                                   image_metadata=image_meta, public=True)
153
154     out = dict()
155     out['cirros'] = OpenStackImage(os_creds, cirros_image_settings)
156     out['cirros'].create()
157     out['centos'] = OpenStackImage(os_creds, centos_image_settings)
158     out['centos'].create()
159     out['ubuntu'] = OpenStackImage(os_creds, ubuntu_image_settings)
160     out['ubuntu'].create()
161
162     return out
163
164
165 def main(arguments):
166     """
167     Begins running tests with different image_metadata configuration.
168     argv[1] if used must be the source filename else os_env.yaml will be leveraged instead
169     argv[2] if used must be the proxy server <host>:<port>
170     """
171     log_level = LOG_LEVELS.get(arguments.log_level, logging.DEBUG)
172     logging.basicConfig(level=log_level)
173     logger.info('Starting test suite')
174
175     __run_tests(arguments.env, arguments.ext_net, arguments.proxy, arguments.ssh_proxy_cmd,
176                 arguments.use_keystone != ARG_NOT_SET, arguments.floating_ips != ARG_NOT_SET, log_level)
177
178     exit(0)
179
180
181 if __name__ == '__main__':
182     parser = argparse.ArgumentParser()
183     parser.add_argument('-e', '--env', dest='env', required=True, help='OpenStack credentials file')
184     parser.add_argument('-n', '--net', dest='ext_net', required=True, help='External network name')
185     parser.add_argument('-p', '--proxy', dest='proxy', nargs='?', default=None,
186                         help='Optonal HTTP proxy socket (<host>:<port>)')
187     parser.add_argument('-s', '--ssh-proxy-cmd', dest='ssh_proxy_cmd', nargs='?', default=None,
188                         help='Optonal SSH proxy command value')
189     parser.add_argument('-l', '--log-level', dest='log_level', default='INFO',
190                         help='Logging Level (FATAL|CRITICAL|ERROR|WARN|INFO|DEBUG)')
191     parser.add_argument('-f', '--floating-ips', dest='floating_ips', default=ARG_NOT_SET, nargs='?',
192                         help='When argument is set, all integration tests requiring Floating IPs will be executed')
193     parser.add_argument('-k', '--use-keystone', dest='use_keystone', default=ARG_NOT_SET, nargs='?',
194                         help='When argument is set, the tests will exercise the keystone APIs and must be run on a ' +
195                              'machine that has access to the admin network' +
196                              ' and is able to create users and groups')
197
198     args = parser.parse_args()
199
200     main(args)