Merge "Run testcase 074 result overridden by job status" into stable/gambia
[yardstick.git] / yardstick / network_services / traffic_profile / http_ixload.py
1 # Copyright (c) 2016-2017 Intel Corporation
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #      http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 import sys
16 import os
17 import logging
18 import collections
19 import subprocess
20 try:
21     libs = subprocess.check_output(
22         'python -c "import site; print(site.getsitepackages())"', shell=True)
23
24     sys.path.extend(libs[1:-1].replace("'", "").split(','))
25 except subprocess.CalledProcessError:
26     pass
27
28 # ixload uses its own py2. So importing jsonutils fails. So adding below
29 # workaround to support call from yardstick
30 try:
31     from oslo_serialization import jsonutils
32 except ImportError:
33     import json as jsonutils
34
35 from yardstick.common import exceptions #pylint: disable=wrong-import-position
36
37 try:
38     from IxLoad import IxLoad, StatCollectorUtils
39 except ImportError:
40     IxLoad = exceptions.ErrorClass
41     StatCollectorUtils = exceptions.ErrorClass
42
43
44 LOG = logging.getLogger(__name__)
45 CSV_FILEPATH_NAME = 'IxL_statResults.csv'
46
47 STATS_TO_GET = (
48     'HTTP_Client.csv',
49     'HTTP_Server.csv',
50     'L2-3 Stats for Client Ports.csv',
51     'L2-3 Stats for Server Ports.csv',
52     'IxLoad Detailed Report.html',
53     'IxLoad Detailed Report.pdf'
54 )
55
56 HTTP_CLIENT_STATS = [
57     ["HTTP Client", "TCP Connections Established", "kSum"],
58     ["HTTP Client", "TCP Connection Requests Failed", "kSum"],
59     ["HTTP Client", "HTTP Simulated Users", "kSum"],
60     ["HTTP Client", "HTTP Concurrent Connections", "kSum"],
61     ["HTTP Client", "HTTP Connections", "kSum"],
62     ["HTTP Client", "HTTP Transactions", "kSum"],
63     ["HTTP Client", "HTTP Connection Attempts", "kSum"]
64 ]
65
66 HTTP_SERVER_STATS = [
67     ["HTTP Server", "TCP Connections Established", "kSum"],
68     ["HTTP Server", "TCP Connection Requests Failed", "kSum"]
69 ]
70
71
72 INCOMING_STAT_RECORD_TEMPLATE = """
73 =====================================
74 INCOMING STAT RECORD >>> %s
75 Len = %s
76 %s
77 %s
78 =====================================
79 """
80
81 INCOMING_STAT_INTERVAL_TEMPLATE = """
82 =====================================
83 Incoming stats: Time interval: %s
84 Incoming stats: Time interval: %s
85 =====================================
86 """
87
88
89 def validate_non_string_sequence(value, default=None, raise_exc=None):
90     if isinstance(value, collections.Sequence) and not isinstance(value, str):
91         return value
92     if raise_exc:
93         raise raise_exc  # pylint: disable=raising-bad-type
94     return default
95
96
97 def join_non_strings(separator, *non_strings):
98     try:
99         non_strings = validate_non_string_sequence(non_strings[0], raise_exc=RuntimeError)
100     except (IndexError, RuntimeError):
101         pass
102     return str(separator).join(str(non_string) for non_string in non_strings)
103
104
105 class IXLOADHttpTest(object):
106
107     def __init__(self, test_input):
108         self.ix_load = None
109         self.stat_utils = None
110         self.remote_server = None
111         self.config_file = None
112         self.results_on_windows = None
113         self.result_dir = None
114         self.chassis = None
115         self.card = None
116         self.ports_to_reassign = None
117         self.test_input = jsonutils.loads(test_input)
118         self.parse_run_test()
119
120     @staticmethod
121     def format_ports_for_reassignment(ports):
122         formatted = [join_non_strings(';', p) for p in ports if len(p) == 3]
123         LOG.debug('for client ports:%s', os.linesep.join(formatted))
124         return formatted
125
126     def reassign_ports(self, test, repository, ports_to_reassign):
127         LOG.debug('ReassignPorts: %s %s', test, repository)
128
129         chassis_chain = repository.cget('chassisChain')
130         LOG.debug('chassischain: %s', chassis_chain)
131         client_ports = ports_to_reassign[0::2]
132         server_ports = ports_to_reassign[1::2]
133
134         client_ports = self.format_ports_for_reassignment(client_ports)
135         LOG.debug('Reassigning client ports: %s', client_ports)
136         server_ports = self.format_ports_for_reassignment(server_ports)
137         LOG.debug('Reassigning server ports: %s', server_ports)
138         ports_to_set = client_ports + server_ports
139
140         try:
141             LOG.debug('Reassigning ports: %s', ports_to_set)
142             test.setPorts(ports_to_set)
143         except Exception:
144             LOG.error('Error: Could not remap port assignment for: %s',
145                       ports_to_set)
146             self.ix_load.delete(repository)
147             self.ix_load.disconnect()
148             raise
149
150     @staticmethod
151     def stat_collector(*args):
152         LOG.debug(INCOMING_STAT_RECORD_TEMPLATE, args, len(args), args[0], args[1])
153
154     @staticmethod
155     def IxL_StatCollectorCommand(*args):
156         stats = args[1][3]
157         timestamp = args[1][1]
158         LOG.debug(INCOMING_STAT_INTERVAL_TEMPLATE, timestamp, stats)
159
160     @staticmethod
161     def set_results_dir(test_controller, results_on_windows):
162         """
163         If the folder doesn't exists on the Windows Client PC,
164         IxLoad will automatically create it.
165         """
166         try:
167             test_controller.setResultDir(results_on_windows)
168         except Exception:
169             LOG.error('Error creating results dir on Win: %s',
170                       results_on_windows)
171             raise
172
173     def load_config_file(self, config_file):
174         try:
175             LOG.debug(config_file)
176             repository = self.ix_load.new("ixRepository", name=config_file)
177             return repository
178         except Exception:
179             LOG.error('Error: IxLoad config file not found: %s', config_file)
180             raise
181
182     def start_http_test(self):
183         self.ix_load = IxLoad()
184
185         LOG.debug('--- ixLoad obj: %s', self.ix_load)
186         try:
187             self.ix_load.connect(self.remote_server)
188         except Exception:
189             raise
190
191         log_tag = "IxLoad-api"
192         log_name = "reprun"
193         logger = self.ix_load.new("ixLogger", log_tag, 1)
194         log_engine = logger.getEngine()
195         log_engine.setLevels(self.ix_load.ixLogger.kLevelDebug,
196                              self.ix_load.ixLogger.kLevelInfo)
197         log_engine.setFile(log_name, 2, 256, 1)
198
199         # Initialize stat collection utilities
200         self.stat_utils = StatCollectorUtils()
201
202         test_controller = self.ix_load.new("ixTestController", outputDir=1)
203
204         repository = self.load_config_file(self.config_file)
205
206         # Get the first test on the testList
207         test_name = repository.testList[0].cget("name")
208         test = repository.testList.getItem(test_name)
209
210         self.set_results_dir(test_controller, self.results_on_windows)
211
212         test.config(statsRequired=1, enableResetPorts=1, csvInterval=2,
213                     enableForceOwnership=True)
214
215         #  ---- Remap ports ----
216         try:
217             self.reassign_ports(test, repository, self.ports_to_reassign)
218         except Exception:  # pylint: disable=broad-except
219             LOG.exception("Exception occurred during reassign_ports")
220
221         # -----------------------------------------------------------------------
222         # Set up stat Collection
223         # -----------------------------------------------------------------------
224         test_server_handle = test_controller.getTestServerHandle()
225         self.stat_utils.Initialize(test_server_handle)
226
227         # Clear any stats that may have been registered previously
228         self.stat_utils.ClearStats()
229
230         # Define the stats we would like to collect
231         self.stat_utils.AddStat(caption="Watch_Stat_1",
232                                 statSourceType="HTTP Client",
233                                 statName="TCP Connections Established",
234                                 aggregationType="kSum",
235                                 filterList={})
236
237         self.stat_utils.AddStat(caption="Watch_Stat_2",
238                                 statSourceType="HTTP Client",
239                                 statName="TCP Connection Requests Failed",
240                                 aggregationType="kSum",
241                                 filterList={})
242
243         self.stat_utils.AddStat(caption="Watch_Stat_3",
244                                 statSourceType="HTTP Server",
245                                 statName="TCP Connections Established",
246                                 aggregationType="kSum",
247                                 filterList={})
248
249         self.stat_utils.AddStat(caption="Watch_Stat_4",
250                                 statSourceType="HTTP Server",
251                                 statName="TCP Connection Requests Failed",
252                                 aggregationType="kSum",
253                                 filterList={})
254
255         self.stat_utils.StartCollector(self.IxL_StatCollectorCommand)
256
257         test_controller.run(test)
258         self.ix_load.waitForTestFinish()
259
260         test_controller.releaseConfigWaitFinish()
261
262         # Stop the collector (running in the tcl event loop)
263         self.stat_utils.StopCollector()
264
265         # Cleanup
266         test_controller.generateReport(detailedReport=1, format="PDF;HTML")
267         test_controller.releaseConfigWaitFinish()
268
269         self.ix_load.delete(test)
270         self.ix_load.delete(test_controller)
271         self.ix_load.delete(logger)
272         self.ix_load.delete(log_engine)
273
274         LOG.debug('Retrieving CSV stats from Windows Client PC ...')
275         for stat_file in STATS_TO_GET:
276             enhanced_stat_file = stat_file.replace('-', '')
277             enhanced_stat_file = enhanced_stat_file.replace(' ', '_')
278             enhanced_stat_file = enhanced_stat_file.replace('__', '_')
279
280             LOG.debug('Getting csv stat file: %s', stat_file)
281             src_file = os.path.join(self.results_on_windows, stat_file)
282             dst_file = os.path.join(self.result_dir, '_'.join(['ixLoad', enhanced_stat_file]))
283             self.ix_load.retrieveFileCopy(src_file, dst_file)
284
285         self.ix_load.disconnect()
286
287     def parse_run_test(self):
288         self.remote_server = self.test_input["remote_server"]
289         LOG.debug("remote tcl server: %s", self.remote_server)
290
291         self.config_file = self.test_input["ixload_cfg"]
292         LOG.debug("ixload config: %s", self.remote_server)
293
294         self.results_on_windows = 'C:/Results'
295         self.result_dir = self.test_input["result_dir"]
296         self.chassis = self.test_input["ixia_chassis"]
297         LOG.debug("remote ixia chassis: %s", self.chassis)
298
299         self.card = self.test_input["IXIA"]["card"]
300         self.ports_to_reassign = [
301             [self.chassis, self.card, port] for port in
302             self.test_input["IXIA"]["ports"]
303         ]
304
305         LOG.debug("Ports to be reassigned: %s", self.ports_to_reassign)
306
307
308 def main(args):
309     # Get the args from cmdline and parse and run the test
310     test_input = "".join(args[1:])
311     if test_input:
312         ixload_obj = IXLOADHttpTest(test_input)
313         ixload_obj.start_http_test()
314
315 if __name__ == '__main__':
316     LOG.info("Start http_ixload test")
317     main(sys.argv)