fix(core): QAT initialization
[csit.git] / resources / libraries / python / DUTSetup.py
1 # Copyright (c) 2023 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 """DUT setup library."""
15
16 from time import sleep
17 from robot.api import logger
18
19 from resources.libraries.python.Constants import Constants
20 from resources.libraries.python.ssh import exec_cmd, exec_cmd_no_error
21 from resources.libraries.python.topology import NodeType, Topology
22
23
24 class DUTSetup:
25     """Contains methods for setting up DUTs."""
26
27     @staticmethod
28     def get_service_logs(node, service):
29         """Get specific service unit logs from node.
30
31         :param node: Node in the topology.
32         :param service: Service unit name.
33         :type node: dict
34         :type service: str
35         """
36         if DUTSetup.running_in_container(node):
37             return
38         else:
39             command = (
40                 f"journalctl --no-pager _SYSTEMD_INVOCATION_ID=$(systemctl "
41                 f"show -p InvocationID --value {service})"
42             )
43         message = f"Node {node[u'host']} failed to get logs from unit {service}"
44
45         exec_cmd_no_error(
46             node, command, timeout=30, sudo=True, message=message
47         )
48
49     @staticmethod
50     def get_service_logs_on_all_duts(nodes, service):
51         """Get specific service unit logs from all DUTs.
52
53         :param nodes: Nodes in the topology.
54         :param service: Service unit name.
55         :type nodes: dict
56         :type service: str
57         """
58         for node in nodes.values():
59             if node[u"type"] == NodeType.DUT:
60                 DUTSetup.get_service_logs(node, service)
61
62     @staticmethod
63     def restart_service(node, service):
64         """Restart the named service on node.
65
66         :param node: Node in the topology.
67         :param service: Service unit name.
68         :type node: dict
69         :type service: str
70         """
71         if DUTSetup.running_in_container(node):
72             command = f"supervisorctl restart {service}"
73         else:
74             command = f"systemctl restart {service}"
75         message = f"Node {node[u'host']} failed to restart service {service}"
76
77         exec_cmd_no_error(
78             node, command, timeout=180, sudo=True, message=message
79         )
80
81         DUTSetup.get_service_logs(node, service)
82
83     @staticmethod
84     def restart_service_on_all_duts(nodes, service):
85         """Restart the named service on all DUTs.
86
87         :param nodes: Nodes in the topology.
88         :param service: Service unit name.
89         :type nodes: dict
90         :type service: str
91         """
92         for node in nodes.values():
93             if node[u"type"] == NodeType.DUT:
94                 DUTSetup.restart_service(node, service)
95
96     @staticmethod
97     def start_service(node, service):
98         """Start up the named service on node.
99
100         :param node: Node in the topology.
101         :param service: Service unit name.
102         :type node: dict
103         :type service: str
104         """
105         if DUTSetup.running_in_container(node):
106             command = f"supervisorctl restart {service}"
107         else:
108             command = f"systemctl restart {service}"
109         message = f"Node {node[u'host']} failed to start service {service}"
110
111         exec_cmd_no_error(
112             node, command, timeout=180, sudo=True, message=message
113         )
114
115         DUTSetup.get_service_logs(node, service)
116
117     @staticmethod
118     def start_service_on_all_duts(nodes, service):
119         """Start up the named service on all DUTs.
120
121         :param nodes: Nodes in the topology.
122         :param service: Service unit name.
123         :type nodes: dict
124         :type service: str
125         """
126         for node in nodes.values():
127             if node[u"type"] == NodeType.DUT:
128                 DUTSetup.start_service(node, service)
129
130     @staticmethod
131     def stop_service(node, service):
132         """Stop the named service on node.
133
134         :param node: Node in the topology.
135         :param service: Service unit name.
136         :type node: dict
137         :type service: str
138         """
139         DUTSetup.get_service_logs(node, service)
140
141         if DUTSetup.running_in_container(node):
142             command = f"supervisorctl stop {service}"
143         else:
144             command = f"systemctl stop {service}"
145         message = f"Node {node[u'host']} failed to stop service {service}"
146
147         exec_cmd_no_error(
148             node, command, timeout=180, sudo=True, message=message
149         )
150
151     @staticmethod
152     def stop_service_on_all_duts(nodes, service):
153         """Stop the named service on all DUTs.
154
155         :param nodes: Nodes in the topology.
156         :param service: Service unit name.
157         :type nodes: dict
158         :type service: str
159         """
160         for node in nodes.values():
161             if node[u"type"] == NodeType.DUT:
162                 DUTSetup.stop_service(node, service)
163
164     @staticmethod
165     def kill_program(node, program, namespace=None):
166         """Kill program on the specified topology node.
167
168         :param node: Topology node.
169         :param program: Program name.
170         :param namespace: Namespace program is running in.
171         :type node: dict
172         :type program: str
173         :type namespace: str
174         """
175         host = node[u"host"]
176         cmd_timeout = 5
177         if namespace in (None, u"default"):
178             shell_cmd = u"sh -c"
179         else:
180             shell_cmd = f"ip netns exec {namespace} sh -c"
181
182         pgrep_cmd = f"{shell_cmd} \'pgrep -c {program}\'"
183         _, stdout, _ = exec_cmd(node, pgrep_cmd, timeout=cmd_timeout,
184                                 sudo=True)
185         if int(stdout) == 0:
186             logger.trace(f"{program} is not running on {host}")
187             return
188         exec_cmd(node, f"{shell_cmd} \'pkill {program}\'",
189                  timeout=cmd_timeout, sudo=True)
190         for attempt in range(5):
191             _, stdout, _ = exec_cmd(node, pgrep_cmd, timeout=cmd_timeout,
192                                     sudo=True)
193             if int(stdout) == 0:
194                 logger.trace(f"Attempt {attempt}: {program} is dead on {host}")
195                 return
196             sleep(1)
197         logger.trace(f"SIGKILLing {program} on {host}")
198         exec_cmd(node, f"{shell_cmd} \'pkill -9 {program}\'",
199                  timeout=cmd_timeout, sudo=True)
200
201     @staticmethod
202     def verify_program_installed(node, program):
203         """Verify that program is installed on the specified topology node.
204
205         :param node: Topology node.
206         :param program: Program name.
207         :type node: dict
208         :type program: str
209         """
210         cmd = f"command -v {program}"
211         exec_cmd_no_error(node, cmd, message=f"{program} is not installed")
212
213     @staticmethod
214     def get_pid(node, process, retries=3):
215         """Get PID of running process.
216
217         :param node: DUT node.
218         :param process: process name.
219         :param retries: How many times to retry on failure.
220         :type node: dict
221         :type process: str
222         :type retries: int
223         :returns: PID
224         :rtype: int
225         :raises RuntimeError: If it is not possible to get the PID.
226         """
227         cmd = f"pidof {process}"
228         stdout, _ = exec_cmd_no_error(
229             node, cmd, retries=retries,
230             message=f"No {process} PID found on node {node[u'host']}")
231         pid_list = stdout.split()
232         return [int(pid) for pid in pid_list]
233
234     @staticmethod
235     def get_vpp_pids(nodes):
236         """Get PID of running VPP process on all DUTs.
237
238         :param nodes: DUT nodes.
239         :type nodes: dict
240         :returns: PIDs
241         :rtype: dict
242         """
243         pids = dict()
244         for node in nodes.values():
245             if node[u"type"] == NodeType.DUT:
246                 pids[node[u"host"]] = DUTSetup.get_pid(node, u"vpp")
247         return pids
248
249     @staticmethod
250     def get_virtfn_pci_addr(node, pf_pci_addr, vf_id):
251         """Get PCI address of Virtual Function.
252
253         :param node: DUT node.
254         :param pf_pci_addr: Physical Function PCI address.
255         :param vf_id: Virtual Function number.
256         :type node: dict
257         :type pf_pci_addr: str
258         :type vf_id: int
259         :returns: Virtual Function PCI address.
260         :rtype: str
261         :raises RuntimeError: If failed to get Virtual Function PCI address.
262         """
263         command = f"sh -c \"basename $(readlink " \
264             f"/sys/bus/pci/devices/{pf_pci_addr}/virtfn{vf_id})\""
265         message = u"Failed to get virtual function PCI address."
266
267         stdout, _ = exec_cmd_no_error(
268             node, command, timeout=30, sudo=True, message=message
269         )
270
271         return stdout.strip()
272
273     @staticmethod
274     def get_sriov_numvfs(node, pf_pci_addr):
275         """Get number of SR-IOV VFs.
276
277         :param node: DUT node.
278         :param pf_pci_addr: Physical Function PCI device address.
279         :type node: dict
280         :type pf_pci_addr: str
281         :returns: Number of VFs.
282         :rtype: int
283         :raises RuntimeError: If PCI device is not SR-IOV capable.
284         """
285         pci = pf_pci_addr.replace(u":", r"\:")
286         command = f"cat /sys/bus/pci/devices/{pci}/sriov_numvfs"
287         message = f"PCI device {pf_pci_addr} is not a SR-IOV device."
288
289         for _ in range(3):
290             stdout, _ = exec_cmd_no_error(
291                 node, command, timeout=30, sudo=True, message=message
292             )
293             try:
294                 sriov_numvfs = int(stdout)
295             except ValueError:
296                 logger.trace(
297                     f"Reading sriov_numvfs info failed on {node[u'host']}"
298                 )
299             else:
300                 return sriov_numvfs
301
302     @staticmethod
303     def set_sriov_numvfs(node, pf_pci_addr, numvfs=0):
304         """Init or reset SR-IOV virtual functions by setting its number on PCI
305         device on DUT. Setting to zero removes all VFs.
306
307         :param node: DUT node.
308         :param pf_pci_addr: Physical Function PCI device address.
309         :param numvfs: Number of VFs to initialize, 0 - removes the VFs.
310         :type node: dict
311         :type pf_pci_addr: str
312         :type numvfs: int
313         :raises RuntimeError: Failed to create VFs on PCI.
314         """
315         cmd = f"test -f /sys/bus/pci/devices/{pf_pci_addr}/sriov_numvfs"
316         sriov_unsupported, _, _ = exec_cmd(node, cmd)
317         # if sriov_numvfs doesn't exist, then sriov_unsupported != 0
318         if int(sriov_unsupported):
319             if numvfs == 0:
320                 # sriov is not supported and we want 0 VFs
321                 # no need to do anything
322                 return
323
324             raise RuntimeError(
325                 f"Can't configure {numvfs} VFs on {pf_pci_addr} device "
326                 f"on {node[u'host']} since it doesn't support SR-IOV."
327             )
328
329         pci = pf_pci_addr.replace(u":", r"\:")
330         command = f"sh -c \"echo {numvfs} | " \
331             f"tee /sys/bus/pci/devices/{pci}/sriov_numvfs\""
332         message = f"Failed to create {numvfs} VFs on {pf_pci_addr} device " \
333             f"on {node[u'host']}"
334
335         exec_cmd_no_error(
336             node, command, timeout=120, sudo=True, message=message
337         )
338
339     @staticmethod
340     def pci_driver_unbind(node, pci_addr):
341         """Unbind PCI device from current driver on node.
342
343         :param node: DUT node.
344         :param pci_addr: PCI device address.
345         :type node: dict
346         :type pci_addr: str
347         :raises RuntimeError: If PCI device unbind failed.
348         """
349         pci = pci_addr.replace(u":", r"\:")
350         command = f"sh -c \"echo {pci_addr} | " \
351             f"tee /sys/bus/pci/devices/{pci}/driver/unbind\""
352         message = f"Failed to unbind PCI device {pci_addr} on {node[u'host']}"
353
354         exec_cmd_no_error(
355             node, command, timeout=120, sudo=True, message=message
356         )
357
358     @staticmethod
359     def unbind_pci_devices_from_other_driver(node, driver, *pci_addrs):
360         """Unbind PCI devices from driver other than input driver on node.
361
362         :param node: DUT node.
363         :param driver: Driver to not unbind from. If None or empty string,
364             will attempt to unbind from the current driver.
365         :param pci_addrs: PCI device addresses.
366         :type node: dict
367         :type driver: str
368         :type pci_addrs: list
369         """
370         for pci_addr in pci_addrs:
371             cur_driver = DUTSetup.get_pci_dev_driver(node, pci_addr)
372             if not cur_driver:
373                 return
374             if not driver or cur_driver != driver:
375                 DUTSetup.pci_driver_unbind(node, pci_addr)
376
377     @staticmethod
378     def pci_driver_bind(node, pci_addr, driver):
379         """Bind PCI device to driver on node.
380
381         :param node: DUT node.
382         :param pci_addr: PCI device address.
383         :param driver: Driver to bind.
384         :type node: dict
385         :type pci_addr: str
386         :type driver: str
387         :raises RuntimeError: If PCI device bind failed.
388         """
389         message = f"Failed to bind PCI device {pci_addr} to {driver} " \
390             f"on host {node[u'host']}"
391         pci = pci_addr.replace(u":", r"\:")
392         command = f"sh -c \"echo {driver} | " \
393             f"tee /sys/bus/pci/devices/{pci}/driver_override\""
394
395         exec_cmd_no_error(
396             node, command, timeout=120, sudo=True, message=message
397         )
398
399         command = f"sh -c \"echo {pci_addr} | " \
400             f"tee /sys/bus/pci/drivers/{driver}/bind\""
401
402         exec_cmd_no_error(
403             node, command, timeout=120, sudo=True, message=message
404         )
405
406         command = f"sh -c \"echo  | " \
407             f"tee /sys/bus/pci/devices/{pci}/driver_override\""
408
409         exec_cmd_no_error(
410             node, command, timeout=120, sudo=True, message=message
411         )
412
413     @staticmethod
414     def pci_vf_driver_unbind(node, pf_pci_addr, vf_id):
415         """Unbind Virtual Function from driver on node.
416
417         :param node: DUT node.
418         :param pf_pci_addr: PCI device address.
419         :param vf_id: Virtual Function ID.
420         :type node: dict
421         :type pf_pci_addr: str
422         :type vf_id: int
423         :raises RuntimeError: If Virtual Function unbind failed.
424         """
425         vf_pci_addr = DUTSetup.get_virtfn_pci_addr(node, pf_pci_addr, vf_id)
426         pf_pci = pf_pci_addr.replace(u":", r"\:")
427         vf_path = f"/sys/bus/pci/devices/{pf_pci}/virtfn{vf_id}"
428
429         command = f"sh -c \"echo {vf_pci_addr} | tee {vf_path}/driver/unbind\""
430         message = f"Failed to unbind VF {vf_pci_addr} on {node[u'host']}"
431
432         exec_cmd_no_error(
433             node, command, timeout=120, sudo=True, message=message
434         )
435
436     @staticmethod
437     def pci_vf_driver_bind(node, pf_pci_addr, vf_id, driver):
438         """Bind Virtual Function to driver on node.
439
440         :param node: DUT node.
441         :param pf_pci_addr: PCI device address.
442         :param vf_id: Virtual Function ID.
443         :param driver: Driver to bind.
444         :type node: dict
445         :type pf_pci_addr: str
446         :type vf_id: int
447         :type driver: str
448         :raises RuntimeError: If PCI device bind failed.
449         """
450         vf_pci_addr = DUTSetup.get_virtfn_pci_addr(node, pf_pci_addr, vf_id)
451         pf_pci = pf_pci_addr.replace(u":", r'\:')
452         vf_path = f"/sys/bus/pci/devices/{pf_pci}/virtfn{vf_id}"
453
454         message = f"Failed to bind VF {vf_pci_addr} to {driver} " \
455             f"on {node[u'host']}"
456         command = f"sh -c \"echo {driver} | tee {vf_path}/driver_override\""
457
458         exec_cmd_no_error(
459             node, command, timeout=120, sudo=True, message=message
460         )
461
462         command = f"sh -c \"echo {vf_pci_addr} | " \
463             f"tee /sys/bus/pci/drivers/{driver}/bind\""
464
465         exec_cmd_no_error(
466             node, command, timeout=120, sudo=True, message=message
467         )
468
469         command = f"sh -c \"echo  | tee {vf_path}/driver_override\""
470
471         exec_cmd_no_error(
472             node, command, timeout=120, sudo=True, message=message
473         )
474
475     @staticmethod
476     def get_pci_dev_driver(node, pci_addr):
477         """Get current PCI device driver on node.
478
479         :param node: DUT node.
480         :param pci_addr: PCI device address.
481         :type node: dict
482         :type pci_addr: str
483         :returns: Driver or None
484         :raises RuntimeError: If it is not possible to get the interface driver
485             information from the node.
486         """
487         driver_path = f"/sys/bus/pci/devices/{pci_addr}/driver"
488         cmd = f"test -d {driver_path}"
489         ret_code, ret_val, _ = exec_cmd(node, cmd)
490         if int(ret_code):
491             # the directory doesn't exist which means the device is not bound
492             # to any driver
493             return None
494         cmd = f"basename $(readlink -f {driver_path})"
495         ret_val, _ = exec_cmd_no_error(node, cmd)
496         return ret_val.strip()
497
498     @staticmethod
499     def verify_kernel_module(node, module, force_load=False):
500         """Verify if kernel module is loaded on node. If parameter force
501         load is set to True, then try to load the modules.
502
503         :param node: Node.
504         :param module: Module to verify.
505         :param force_load: If True then try to load module.
506         :type node: dict
507         :type module: str
508         :type force_load: bool
509         :raises RuntimeError: If module is not loaded or failed to load.
510         """
511         command = f"grep -w {module} /proc/modules"
512         message = f"Kernel module {module} is not loaded " \
513             f"on host {node[u'host']}"
514
515         try:
516             exec_cmd_no_error(
517                 node, command, timeout=30, sudo=False, message=message
518             )
519         except RuntimeError:
520             if force_load:
521                 # Module is not loaded and we want to load it
522                 DUTSetup.load_kernel_module(node, module)
523             else:
524                 raise
525
526     @staticmethod
527     def verify_kernel_module_on_all_duts(nodes, module, force_load=False):
528         """Verify if kernel module is loaded on all DUTs. If parameter force
529         load is set to True, then try to load the modules.
530
531         :param nodes: DUT nodes.
532         :param module: Module to verify.
533         :param force_load: If True then try to load module.
534         :type nodes: dict
535         :type module: str
536         :type force_load: bool
537         """
538         for node in nodes.values():
539             if node[u"type"] == NodeType.DUT:
540                 DUTSetup.verify_kernel_module(node, module, force_load)
541
542     @staticmethod
543     def verify_uio_driver_on_all_duts(nodes):
544         """Verify if uio driver kernel module is loaded on all DUTs. If module
545         is not present it will try to load it.
546
547         :param nodes: DUT nodes.
548         :type nodes: dict
549         """
550         for node in nodes.values():
551             if node[u"type"] == NodeType.DUT:
552                 uio_driver = Topology.get_uio_driver(node)
553                 DUTSetup.verify_kernel_module(node, uio_driver, force_load=True)
554
555     @staticmethod
556     def load_kernel_module(node, module):
557         """Load kernel module on node.
558
559         :param node: DUT node.
560         :param module: Module to load.
561         :type node: dict
562         :type module: str
563         :returns: nothing
564         :raises RuntimeError: If loading failed.
565         """
566         command = f"modprobe {module}"
567         message = f"Failed to load {module} on host {node[u'host']}"
568
569         exec_cmd_no_error(node, command, timeout=30, sudo=True, message=message)
570
571     @staticmethod
572     def running_in_container(node):
573         """This method tests if topology node is running inside container.
574
575         :param node: Topology node.
576         :type node: dict
577         :returns: True if running in docker container, false if not or failed
578             to detect.
579         :rtype: bool
580         """
581         command = "cat /.dockerenv"
582         try:
583             exec_cmd_no_error(node, command, timeout=30)
584         except RuntimeError:
585             return False
586         return True
587
588     @staticmethod
589     def get_docker_mergeddir(node, uuid=None):
590         """Get Docker overlay for MergedDir diff.
591
592         :param node: DUT node.
593         :param uuid: Docker UUID.
594         :type node: dict
595         :type uuid: str
596         :returns: Docker container MergedDir.
597         :rtype: str
598         :raises RuntimeError: If getting output failed.
599         """
600         if not uuid:
601             command = 'fgrep "hostname" /proc/self/mountinfo | cut -f 4 -d" "'
602             message = "Failed to get UUID!"
603             stdout, _ = exec_cmd_no_error(node, command, message=message)
604             uuid = stdout.split(sep="/")[-2]
605         command = (
606             f"docker inspect "
607             f"--format='{{{{.GraphDriver.Data.MergedDir}}}}' {uuid}"
608         )
609         message = f"Failed to get directory of {uuid} on host {node[u'host']}"
610
611         stdout, _ = exec_cmd_no_error(node, command, sudo=True, message=message)
612         return stdout.strip()
613
614     @staticmethod
615     def get_hugepages_info(node, hugesize=None):
616         """Get number of huge pages in system.
617
618         :param node: Node in the topology.
619         :param hugesize: Size of hugepages. Default system huge size if None.
620         :type node: dict
621         :type hugesize: int
622         :returns: Number of huge pages in system.
623         :rtype: dict
624         :raises RuntimeError: If reading failed.
625         """
626         if not hugesize:
627             hugesize = "$(grep Hugepagesize /proc/meminfo | awk '{ print $2 }')"
628         command = f"cat /sys/kernel/mm/hugepages/hugepages-{hugesize}kB/*"
629         stdout, _ = exec_cmd_no_error(node, command)
630         try:
631             line = stdout.splitlines()
632             return {
633                 "free_hugepages": int(line[0]),
634                 "nr_hugepages": int(line[1]),
635                 "nr_hugepages_mempolicy": int(line[2]),
636                 "nr_overcommit_hugepages": int(line[3]),
637                 "resv_hugepages": int(line[4]),
638                 "surplus_hugepages": int(line[5])
639             }
640         except ValueError:
641             logger.trace(u"Reading huge pages information failed!")
642
643     @staticmethod
644     def check_huge_page(
645             node, huge_mnt, mem_size, hugesize=2048, allocate=False):
646         """Check if there is enough HugePages in system. If allocate is set to
647         true, try to allocate more HugePages.
648
649         :param node: Node in the topology.
650         :param huge_mnt: HugePage mount point.
651         :param mem_size: Reqeusted memory in MB.
652         :param hugesize: HugePage size in KB.
653         :param allocate: Whether to allocate more memory if not enough.
654         :type node: dict
655         :type huge_mnt: str
656         :type mem_size: int
657         :type hugesize: int
658         :type allocate: bool
659         :raises RuntimeError: Mounting hugetlbfs failed or not enough HugePages
660             or increasing map count failed.
661         """
662         # Get huge pages information.
663         hugepages = DUTSetup.get_hugepages_info(node, hugesize=hugesize)
664
665         # Check if hugepages requested are available on node.
666         if hugepages[u"nr_overcommit_hugepages"]:
667             # If overcommit is used, we need to know how many additional pages
668             # we can allocate
669             huge_available = hugepages[u"nr_overcommit_hugepages"] - \
670                 hugepages[u"surplus_hugepages"]
671         else:
672             # Fallbacking to free_hugepages which were used before to detect.
673             huge_available = hugepages[u"free_hugepages"]
674
675         if ((mem_size * 1024) // hugesize) > huge_available:
676             # If we want to allocate hugepage dynamically.
677             if allocate:
678                 huge_needed = ((mem_size * 1024) // hugesize) - huge_available
679                 huge_to_allocate = huge_needed + hugepages[u"nr_hugepages"]
680                 max_map_count = huge_to_allocate * 4
681                 # Check if huge pages mount point exist.
682                 try:
683                     exec_cmd_no_error(node, u"fgrep 'hugetlbfs' /proc/mounts")
684                 except RuntimeError:
685                     exec_cmd_no_error(node, f"mkdir -p {huge_mnt}", sudo=True)
686                     exec_cmd_no_error(
687                         node,
688                         f"mount -t hugetlbfs -o pagesize={hugesize}k none "
689                         f"{huge_mnt}",
690                         sudo=True)
691                 # Increase maximum number of memory map areas for process.
692                 exec_cmd_no_error(
693                     node,
694                     f"echo \"{max_map_count}\" | "
695                     f"sudo tee /proc/sys/vm/max_map_count",
696                     message=f"Increase map count failed on {node[u'host']}!"
697                 )
698                 # Increase hugepage count.
699                 exec_cmd_no_error(
700                     node,
701                     f"echo \"{huge_to_allocate}\" | "
702                     f"sudo tee /proc/sys/vm/nr_hugepages",
703                     message=f"Mount huge pages failed on {node[u'host']}!"
704                 )
705             # If we do not want to allocate dynamically end with error.
706             else:
707                 raise RuntimeError(
708                     f"Not enough availablehuge pages: {huge_available}!"
709                 )