Merge "yardstick setup ansible, including load_images"
[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 from __future__ import absolute_import
16 from __future__ import print_function
17
18 import sys
19 import os
20 import logging
21
22 # ixload uses its own py2. So importing jsonutils fails. So adding below
23 # workaround to support call from yardstick
24 try:
25     from oslo_serialization import jsonutils
26 except ImportError:
27     import json as jsonutils
28
29 from yardstick.common.utils import join_non_strings
30 from yardstick.common.utils import ErrorClass
31
32 try:
33     from IxLoad import IxLoad, StatCollectorUtils
34 except ImportError:
35     IxLoad = ErrorClass
36     StatCollectorUtils = ErrorClass
37
38 LOG = logging.getLogger(__name__)
39 CSV_FILEPATH_NAME = 'IxL_statResults.csv'
40
41 STATS_TO_GET = (
42     'HTTP_Client.csv',
43     'HTTP_Server.csv',
44     'L2-3 Stats for Client Ports.csv',
45     'L2-3 Stats for Server Ports.csv',
46     'IxLoad Detailed Report.html',
47     'IxLoad Detailed Report.pdf'
48 )
49
50 HTTP_CLIENT_STATS = [
51     ["HTTP Client", "TCP Connections Established", "kSum"],
52     ["HTTP Client", "TCP Connection Requests Failed", "kSum"],
53     ["HTTP Client", "HTTP Simulated Users", "kSum"],
54     ["HTTP Client", "HTTP Concurrent Connections", "kSum"],
55     ["HTTP Client", "HTTP Connections", "kSum"],
56     ["HTTP Client", "HTTP Transactions", "kSum"],
57     ["HTTP Client", "HTTP Connection Attempts", "kSum"]
58 ]
59
60 HTTP_SERVER_STATS = [
61     ["HTTP Server", "TCP Connections Established", "kSum"],
62     ["HTTP Server", "TCP Connection Requests Failed", "kSum"]
63 ]
64
65
66 INCOMING_STAT_RECORD_TEMPLATE = """
67 =====================================
68 INCOMING STAT RECORD >>> %s
69 Len = %s
70 %s
71 %s
72 =====================================
73 """
74
75 INCOMING_STAT_INTERVAL_TEMPLATE = """
76 =====================================
77 Incoming stats: Time interval: %s
78 Incoming stats: Time interval: %s
79 =====================================
80 """
81
82
83 class IXLOADHttpTest(object):
84
85     def __init__(self, test_input):
86         self.test_input = jsonutils.loads(test_input)
87         self.parse_run_test()
88         self.ix_load = None
89         self.stat_utils = None
90         self.remote_server = None
91         self.config_file = None
92         self.results_on_windows = None
93         self.result_dir = None
94         self.chassis = None
95         self.card = None
96         self.ports_to_reassign = None
97
98     @staticmethod
99     def format_ports_for_reassignment(ports):
100         formatted = [join_non_strings(';', p) for p in ports if len(p) == 3]
101         LOG.debug('for client ports:%s', os.linesep.join(formatted))
102         return formatted
103
104     def reassign_ports(self, test, repository, ports_to_reassign):
105         LOG.debug('ReassignPorts: %s %s', test, repository)
106
107         chassis_chain = repository.cget('chassisChain')
108         LOG.debug('chassischain: %s', chassis_chain)
109         client_ports = ports_to_reassign[0::2]
110         server_ports = ports_to_reassign[1::2]
111
112         client_ports = self.format_ports_for_reassignment(client_ports)
113         LOG.debug('Reassigning client ports: %s', client_ports)
114         server_ports = self.format_ports_for_reassignment(server_ports)
115         LOG.debug('Reassigning server ports: %s', server_ports)
116         ports_to_set = client_ports + server_ports
117
118         try:
119             LOG.debug('Reassigning ports: %s', ports_to_set)
120             test.setPorts(ports_to_set)
121         except Exception:
122             LOG.error('Error: Could not remap port assignment for: %s',
123                       ports_to_set)
124             self.ix_load.delete(repository)
125             self.ix_load.disconnect()
126             raise
127
128     @staticmethod
129     def stat_collector(*args):
130         LOG.debug(INCOMING_STAT_RECORD_TEMPLATE, args, len(args), args[0], args[1])
131
132     @staticmethod
133     def IxL_StatCollectorCommand(*args):
134         stats = args[1][3]
135         timestamp = args[1][1]
136         LOG.debug(INCOMING_STAT_INTERVAL_TEMPLATE, timestamp, stats)
137
138     @staticmethod
139     def set_results_dir(test_controller, results_on_windows):
140         """
141         If the folder doesn't exists on the Windows Client PC,
142         IxLoad will automatically create it.
143         """
144         try:
145             test_controller.setResultDir(results_on_windows)
146         except Exception:
147             LOG.error('Error creating results dir on Win: %s',
148                       results_on_windows)
149             raise
150
151     def load_config_file(self, config_file):
152         try:
153             LOG.debug(config_file)
154             repository = self.ix_load.new("ixRepository", name=config_file)
155             return repository
156         except Exception:
157             LOG.error('Error: IxLoad config file not found: %s', config_file)
158             raise
159
160     def start_http_test(self):
161         self.ix_load = IxLoad()
162
163         LOG.debug('--- ixLoad obj: %s', self.ix_load)
164         try:
165             self.ix_load.connect(self.remote_server)
166         except Exception:
167             raise
168
169         log_tag = "IxLoad-api"
170         log_name = "reprun"
171         logger = self.ix_load.new("ixLogger", log_tag, 1)
172         log_engine = logger.getEngine()
173         log_engine.setLevels(self.ix_load.ixLogger.kLevelDebug,
174                              self.ix_load.ixLogger.kLevelInfo)
175         log_engine.setFile(log_name, 2, 256, 1)
176
177         # Initialize stat collection utilities
178         self.stat_utils = StatCollectorUtils()
179
180         test_controller = self.ix_load.new("ixTestController", outputDir=1)
181
182         repository = self.load_config_file(self.config_file)
183
184         # Get the first test on the testList
185         test_name = repository.testList[0].cget("name")
186         test = repository.testList.getItem(test_name)
187
188         self.set_results_dir(test_controller, self.results_on_windows)
189
190         test.config(statsRequired=1, enableResetPorts=1, csvInterval=2,
191                     enableForceOwnership=True)
192
193         #  ---- Remap ports ----
194         try:
195             self.reassign_ports(test, repository, self.ports_to_reassign)
196         except Exception:
197             LOG.exception("Exception occurred during reassign_ports")
198
199         # -----------------------------------------------------------------------
200         # Set up stat Collection
201         # -----------------------------------------------------------------------
202         test_server_handle = test_controller.getTestServerHandle()
203         self.stat_utils.Initialize(test_server_handle)
204
205         # Clear any stats that may have been registered previously
206         self.stat_utils.ClearStats()
207
208         # Define the stats we would like to collect
209         self.stat_utils.AddStat(caption="Watch_Stat_1",
210                                 statSourceType="HTTP Client",
211                                 statName="TCP Connections Established",
212                                 aggregationType="kSum",
213                                 filterList={})
214
215         self.stat_utils.AddStat(caption="Watch_Stat_2",
216                                 statSourceType="HTTP Client",
217                                 statName="TCP Connection Requests Failed",
218                                 aggregationType="kSum",
219                                 filterList={})
220
221         self.stat_utils.AddStat(caption="Watch_Stat_3",
222                                 statSourceType="HTTP Server",
223                                 statName="TCP Connections Established",
224                                 aggregationType="kSum",
225                                 filterList={})
226
227         self.stat_utils.AddStat(caption="Watch_Stat_4",
228                                 statSourceType="HTTP Server",
229                                 statName="TCP Connection Requests Failed",
230                                 aggregationType="kSum",
231                                 filterList={})
232
233         self.stat_utils.StartCollector(self.IxL_StatCollectorCommand)
234
235         test_controller.run(test)
236         self.ix_load.waitForTestFinish()
237
238         test_controller.releaseConfigWaitFinish()
239
240         # Stop the collector (running in the tcl event loop)
241         self.stat_utils.StopCollector()
242
243         # Cleanup
244         test_controller.generateReport(detailedReport=1, format="PDF;HTML")
245         test_controller.releaseConfigWaitFinish()
246
247         self.ix_load.delete(test)
248         self.ix_load.delete(test_controller)
249         self.ix_load.delete(logger)
250         self.ix_load.delete(log_engine)
251
252         LOG.debug('Retrieving CSV stats from Windows Client PC ...')
253         for stat_file in STATS_TO_GET:
254             enhanced_stat_file = stat_file.replace('-', '')
255             enhanced_stat_file = enhanced_stat_file.replace(' ', '_')
256             enhanced_stat_file = enhanced_stat_file.replace('__', '_')
257
258             LOG.debug('Getting csv stat file: %s', stat_file)
259             src_file = os.path.join(self.results_on_windows, stat_file)
260             dst_file = os.path.join(self.result_dir, '_'.join(['ixLoad', enhanced_stat_file]))
261             self.ix_load.retrieveFileCopy(src_file, dst_file)
262
263         self.ix_load.disconnect()
264
265     def parse_run_test(self):
266         self.remote_server = self.test_input["remote_server"]
267         LOG.debug("remote tcl server: %s", self.remote_server)
268
269         self.config_file = self.test_input["ixload_cfg"]
270         LOG.debug("ixload config: %s", self.remote_server)
271
272         self.results_on_windows = 'C:/Results'
273         self.result_dir = self.test_input["result_dir"]
274         self.chassis = self.test_input["ixia_chassis"]
275         LOG.debug("remote ixia chassis: %s", self.chassis)
276
277         self.card = self.test_input["IXIA"]["card"]
278         self.ports_to_reassign = [
279             [self.chassis, self.card, port] for port in
280             self.test_input["IXIA"]["ports"]
281         ]
282
283         LOG.debug("Ports to be reassigned: %s", self.ports_to_reassign)
284
285
286 def main(args):
287     # Get the args from cmdline and parse and run the test
288     test_input = "".join(args[1:])
289     if test_input:
290         ixload_obj = IXLOADHttpTest(test_input)
291         ixload_obj.start_http_test()
292
293 if __name__ == '__main__':
294     main(sys.argv)