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