JumpAvg: Fix string format
[csit.git] / resources / libraries / python / NginxConfigGenerator.py
1 # Copyright (c) 2021 Intel and/or its affiliates.
2 # Licensed under the Apache License, Version 2.0 (the "License");
3 # you may not use this file except in compliance with the License.
4 # You may obtain a copy of the License at:
5 #
6 #     http://www.apache.org/licenses/LICENSE-2.0
7 #
8 # Unless required by applicable law or agreed to in writing, software
9 # distributed under the License is distributed on an "AS IS" BASIS,
10 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 # See the License for the specific language governing permissions and
12 # limitations under the License.
13
14 """Nginx Configuration File Generator library.
15 """
16
17 from resources.libraries.python.ssh import exec_cmd_no_error
18 from resources.libraries.python.topology import NodeType
19 from resources.libraries.python.NginxUtil import NginxUtil
20
21 __all__ = [u"NginxConfigGenerator"]
22
23
24 class NginxConfigGenerator:
25     """NGINX Configuration File Generator."""
26
27     def __init__(self):
28         """Initialize library."""
29         # VPP Node to apply configuration on
30         self._node = u""
31         # NGINX Startup config location
32         self._nginx_path = u"/usr/local/nginx/"
33         # Serialized NGinx Configuration
34         self._nginx_config = u""
35         # VPP Configuration
36         self._nodeconfig = dict()
37
38     def set_node(self, node):
39         """Set DUT node.
40
41         :param node: Node to store configuration on.
42         :type node: dict
43         :raises RuntimeError: If Node type is not DUT.
44         """
45         if node[u"type"] != NodeType.DUT:
46             raise RuntimeError(
47                 u"Startup config can only be applied to DUTnode."
48             )
49         self._node = node
50
51     def set_nginx_path(self, packages_dir, nginx_version):
52         """Set NGINX Conf Name.
53
54         :param packages_dir: NGINX install path.
55         :param nginx_version: Test NGINX version.
56         :type packages_dir: str
57         :type nginx_version: str
58         :raises RuntimeError: If Node type is not DUT.
59         """
60         if nginx_version:
61             self._nginx_path = f"{packages_dir}/nginx-{nginx_version}"
62
63     def add_http_server_listen(self, value):
64         """Add Http Server listen port configuration."""
65         path = [u"http", u"server", u"listen"]
66         self.add_config_item(self._nodeconfig, value, path)
67
68     def add_http_server_root(self, value=u"html"):
69         """Add Http Server root configuration."""
70         path = [u"http", u"server", u"root"]
71         self.add_config_item(self._nodeconfig, value, path)
72
73     def add_http_server_index(self, value=u"index.html index.htm"):
74         """Add Http Server index configuration."""
75         path = [u"http", u"server", u"index"]
76         self.add_config_item(self._nodeconfig, value, path)
77
78     def add_config_item(self, config, value, path):
79         """Add NGINX configuration item.
80
81         :param config: Startup configuration of node.
82         :param value: Value to insert.
83         :param path: Path where to insert item.
84         :type config: dict
85         :type value: str
86         :type path: list
87         """
88         if len(path) == 1:
89             config[path[0]] = value
90             return
91         if path[0] not in config:
92             config[path[0]] = dict()
93         elif isinstance(config[path[0]], str):
94             config[path[0]] = dict() if config[path[0]] == u"" \
95                 else {config[path[0]]: u""}
96         self.add_config_item(config[path[0]], value, path[1:])
97
98     def dump_config(self, obj, level=-1):
99         """Dump the startup configuration in NGINX config format.
100
101         :param obj: Python Object to print.
102         :param level: Nested level for indentation.
103         :type obj: Obj
104         :type level: int
105         :returns: nothing
106         """
107         indent = u"  "
108         if level >= 0:
109             self._nginx_config += f"{level * indent}{{\n"
110         if isinstance(obj, dict):
111             for key, val in obj.items():
112                 if hasattr(val, u"__iter__") and not isinstance(val, str):
113                     self._nginx_config += f"{(level + 1) * indent}{key}\n"
114                     self.dump_config(val, level + 1)
115                 else:
116                     self._nginx_config += f"{(level + 1) * indent}" \
117                                           f"{key} {val};\n"
118         else:
119             for val in obj:
120                 self._nginx_config += f"{(level + 1) * indent}{val};\n"
121         if level >= 0:
122             self._nginx_config += f"{level * indent}}}\n"
123
124     def write_config(self, filename=None):
125         """Generate and write NGINX startup configuration to file.
126
127         :param filename: NGINX configuration file name.
128         :type filename: str
129         """
130         if filename is None:
131             filename = f"{self._nginx_path}/conf/nginx.conf"
132         self.dump_config(self._nodeconfig)
133         cmd = f"echo \"{self._nginx_config}\" | sudo tee {filename}"
134         exec_cmd_no_error(
135             self._node, cmd, message=u"Writing config file failed!"
136         )
137
138     def add_http_server_location(self, size):
139         """Add Http Server location configuration.
140
141         :param size: File size.
142         :type size: int
143         """
144         if size == 0:
145             files = u"return"
146         elif size >= 1024:
147             files = f"{int(size / 1024)}KB.json"
148         else:
149             files = f"{size}B.json"
150         key = f"{files}"
151         size_str = size * u"x"
152         value = "200 '%s'" % size_str
153         path = [u"http", u"server", f"location /{key}", u"return"]
154         self.add_config_item(self._nodeconfig, value, path)
155
156     def add_http_access_log(self, value=u"off"):
157         """Add Http access_log configuration."""
158         path = [u"http", u"access_log"]
159         self.add_config_item(self._nodeconfig, value, path)
160
161     def add_http_include(self, value=u"mime.types"):
162         """Add Http include configuration."""
163         path = [u"http", u"include"]
164         self.add_config_item(self._nodeconfig, value, path)
165
166     def add_http_default_type(self, value=u"application/octet-stream"):
167         """Add Http default_type configuration."""
168         path = [u"http", u"default_type"]
169         self.add_config_item(self._nodeconfig, value, path)
170
171     def add_http_sendfile(self, value=u"on"):
172         """Add Http sendfile configuration."""
173         path = [u"http", u"sendfile"]
174         self.add_config_item(self._nodeconfig, value, path)
175
176     def add_http_keepalive_timeout(self, value):
177         """Add Http keepalive alive timeout configuration."""
178         path = [u"http", u"keepalive_timeout"]
179         self.add_config_item(self._nodeconfig, value, path)
180
181     def add_http_keepalive_requests(self, value):
182         """Add Http keepalive alive requests configuration."""
183         path = [u"http", u"keepalive_requests"]
184         self.add_config_item(self._nodeconfig, value, path)
185
186     def add_events_use(self, value=u"epoll"):
187         """Add Events use configuration."""
188         path = [u"events", u"use"]
189         self.add_config_item(self._nodeconfig, value, path)
190
191     def add_events_worker_connections(self, value=10240):
192         """Add Events worker connections configuration."""
193         path = [u"events", u"worker_connections"]
194         self.add_config_item(self._nodeconfig, value, path)
195
196     def add_events_accept_mutex(self, value=u"off"):
197         """Add Events accept mutex configuration."""
198         path = [u"events", u"accept_mutex"]
199         self.add_config_item(self._nodeconfig, value, path)
200
201     def add_events_multi_accept(self, value=u"off"):
202         """Add Events multi accept configuration."""
203         path = [u"events", u"multi_accept"]
204         self.add_config_item(self._nodeconfig, value, path)
205
206     def add_worker_rlimit_nofile(self, value=10240):
207         """Add Events worker rlimit nofile configuration."""
208         path = [u"worker_rlimit_nofile"]
209         self.add_config_item(self._nodeconfig, value, path)
210
211     def add_master_process(self, value=u"on"):
212         """Add master process configuration."""
213         path = [u"master_process"]
214         self.add_config_item(self._nodeconfig, value, path)
215
216     def add_daemon(self, value=u"off"):
217         """Add daemon configuration."""
218         path = [u"daemon"]
219         self.add_config_item(self._nodeconfig, value, path)
220
221     def add_worker_processes(self, value, smt_used):
222         """Add worker processes configuration."""
223         # nginx workers : vpp used phy workers = 2:1
224         if smt_used:
225             value = value * 4
226         else:
227             value = value * 2
228         path = [u"worker_processes"]
229         self.add_config_item(self._nodeconfig, value, path)
230
231     def apply_config(self, filename=None, verify_nginx=True):
232         """Generate and write NGINX configuration to file and
233         verify configuration.
234
235         :param filename: NGINX configuration file name.
236         :param verify_nginx: Verify NGINX configuration.
237         :type filename: str
238         :type verify_nginx: bool
239         """
240         self.write_config(filename=filename)
241
242         app_path = f"{self._nginx_path}/sbin/nginx"
243         if verify_nginx:
244             NginxUtil.nginx_config_verify(self._node, app_path)