tests: replace pycodestyle with black
[vpp.git] / extras / vpp_config / vpplib / VppGrubUtil.py
1 # Copyright (c) 2016 Cisco 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 """VPP Grub Utility Library."""
15
16 import re
17
18 from vpplib.VPPUtil import VPPUtil
19
20 __all__ = ["VppGrubUtil"]
21
22
23 class VppGrubUtil(object):
24     """VPP Grub Utilities."""
25
26     def _get_current_cmdline(self):
27         """
28         Using /proc/cmdline return the current grub cmdline
29
30         :returns: The current grub cmdline
31         :rtype: string
32         """
33
34         # Get the memory information using /proc/meminfo
35         cmd = "sudo cat /proc/cmdline"
36         (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
37         if ret != 0:
38             raise RuntimeError(
39                 "{} on node {} {} {}".format(cmd, self._node["host"], stdout, stderr)
40             )
41
42         self._current_cmdline = stdout.strip("\n")
43
44     def _get_default_cmdline(self):
45         """
46         Using /etc/default/grub return the default grub cmdline
47
48         :returns: The default grub cmdline
49         :rtype: string
50         """
51
52         # Get the default grub cmdline
53         rootdir = self._node["rootdir"]
54         gfile = self._node["cpu"]["grub_config_file"]
55         grubcmdline = self._node["cpu"]["grubcmdline"]
56         cmd = "cat {}".format(rootdir + gfile)
57         (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
58         if ret != 0:
59             raise RuntimeError(
60                 "{} Executing failed on node {} {}".format(
61                     cmd, self._node["host"], stderr
62                 )
63             )
64
65         # Get the Default Linux command line, ignoring commented lines
66         lines = stdout.split("\n")
67         for line in lines:
68             if line == "" or line[0] == "#":
69                 continue
70             ldefault = re.findall(r"{}=.+".format(grubcmdline), line)
71             if ldefault:
72                 self._default_cmdline = ldefault[0]
73                 break
74
75     def get_current_cmdline(self):
76         """
77         Returns the saved grub cmdline
78
79         :returns: The saved grub cmdline
80         :rtype: string
81         """
82         return self._current_cmdline
83
84     def get_default_cmdline(self):
85         """
86         Returns the default grub cmdline
87
88         :returns: The default grub cmdline
89         :rtype: string
90         """
91         return self._default_cmdline
92
93     def create_cmdline(self, isolated_cpus):
94         """
95         Create the new grub cmdline
96
97         :param isolated_cpus: The isolated cpu string
98         :type isolated_cpus: string
99         :returns: The command line
100         :rtype: string
101         """
102         grubcmdline = self._node["cpu"]["grubcmdline"]
103         cmdline = self._default_cmdline
104         value = cmdline.split("{}=".format(grubcmdline))[1]
105         value = value.rstrip('"').lstrip('"')
106
107         # jadfix intel_pstate=disable sometimes cause networks to
108         # hang on reboot
109         # iommu = re.findall(r'iommu=\w+', value)
110         # pstate = re.findall(r'intel_pstate=\w+', value)
111         # If there is already some iommu commands set, leave them,
112         # if not use ours
113         # if iommu == [] and pstate == []:
114         #    value = '{} intel_pstate=disable'.format(value)
115
116         # Replace isolcpus with ours
117         isolcpus = re.findall(r"isolcpus=[\w+\-,]+", value)
118         if not isolcpus:
119             if isolated_cpus != "":
120                 value = "{} isolcpus={}".format(value, isolated_cpus)
121         else:
122             if isolated_cpus != "":
123                 value = re.sub(
124                     r"isolcpus=[\w+\-,]+", "isolcpus={}".format(isolated_cpus), value
125                 )
126             else:
127                 value = re.sub(r"isolcpus=[\w+\-,]+", "", value)
128
129         nohz = re.findall(r"nohz_full=[\w+\-,]+", value)
130         if not nohz:
131             if isolated_cpus != "":
132                 value = "{} nohz_full={}".format(value, isolated_cpus)
133         else:
134             if isolated_cpus != "":
135                 value = re.sub(
136                     r"nohz_full=[\w+\-,]+", "nohz_full={}".format(isolated_cpus), value
137                 )
138             else:
139                 value = re.sub(r"nohz_full=[\w+\-,]+", "", value)
140
141         rcu = re.findall(r"rcu_nocbs=[\w+\-,]+", value)
142         if not rcu:
143             if isolated_cpus != "":
144                 value = "{} rcu_nocbs={}".format(value, isolated_cpus)
145         else:
146             if isolated_cpus != "":
147                 value = re.sub(
148                     r"rcu_nocbs=[\w+\-,]+", "rcu_nocbs={}".format(isolated_cpus), value
149                 )
150             else:
151                 value = re.sub(r"rcu_nocbs=[\w+\-,]+", "", value)
152
153         value = value.lstrip(" ").rstrip(" ")
154         cmdline = '{}="{}"'.format(grubcmdline, value)
155         return cmdline
156
157     def apply_cmdline(self, node, isolated_cpus):
158         """
159         Apply cmdline to the default grub file
160
161         :param node: Node dictionary with cpuinfo.
162         :param isolated_cpus: The isolated cpu string
163         :type node: dict
164         :type isolated_cpus: string
165         :return The vpp cmdline
166         :rtype string
167         """
168
169         vpp_cmdline = self.create_cmdline(isolated_cpus)
170         if len(vpp_cmdline):
171             # Update grub
172             # Save the original file
173             rootdir = node["rootdir"]
174             grubcmdline = node["cpu"]["grubcmdline"]
175             ofilename = rootdir + node["cpu"]["grub_config_file"] + ".orig"
176             filename = rootdir + node["cpu"]["grub_config_file"]
177
178             # Write the output file
179             # Does a copy of the original file exist, if not create one
180             (ret, stdout, stderr) = VPPUtil.exec_command("ls {}".format(ofilename))
181             if ret != 0:
182                 if stdout.strip("\n") != ofilename:
183                     cmd = "sudo cp {} {}".format(filename, ofilename)
184                     (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
185                     if ret != 0:
186                         raise RuntimeError(
187                             "{} failed on node {} {}".format(
188                                 cmd, self._node["host"], stderr
189                             )
190                         )
191
192             # Get the contents of the current grub config file
193             cmd = "cat {}".format(filename)
194             (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
195             if ret != 0:
196                 raise RuntimeError(
197                     "{} failed on node {} {}".format(cmd, self._node["host"], stderr)
198                 )
199
200             # Write the new contents
201             # Get the Default Linux command line, ignoring commented lines
202             content = ""
203             lines = stdout.split("\n")
204             for line in lines:
205                 if line == "":
206                     content += line + "\n"
207                     continue
208                 if line[0] == "#":
209                     content += line + "\n"
210                     continue
211
212                 ldefault = re.findall(r"{}=.+".format(grubcmdline), line)
213                 if ldefault:
214                     content += vpp_cmdline + "\n"
215                 else:
216                     content += line + "\n"
217
218             content = content.replace(r"`", r"\`")
219             content = content.rstrip("\n")
220             cmd = "sudo cat > {0} << EOF\n{1}\n".format(filename, content)
221             (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
222             if ret != 0:
223                 raise RuntimeError(
224                     "{} failed on node {} {}".format(cmd, self._node["host"], stderr)
225                 )
226
227         return vpp_cmdline
228
229     def __init__(self, node):
230         distro = VPPUtil.get_linux_distro()
231         if distro[0] == "Ubuntu":
232             node["cpu"]["grubcmdline"] = "GRUB_CMDLINE_LINUX_DEFAULT"
233         else:
234             node["cpu"]["grubcmdline"] = "GRUB_CMDLINE_LINUX"
235
236         self._node = node
237         self._current_cmdline = ""
238         self._default_cmdline = ""
239         self._get_current_cmdline()
240         self._get_default_cmdline()