blob: 43377b65c6abcdef0750f5295c49d350f65b83b4 [file] [log] [blame]
Naveen Joyc872cec2022-08-30 13:59:03 -07001#!/usr/bin/env python3
2
3# Supporting module for running tests against a running VPP.
4# This module is used by the test framework. Do not invoke this module
5# directly for running tests against a running vpp. Use run.py for
6# running all unit tests.
7
8from glob import glob
9import os
10import sys
11import subprocess
12from config import config
13
14
15def use_running(cls):
16 """Update VPPTestCase to use running VPP's sock files & methods.
17
18 Arguments:
19 cls -- VPPTestCase Class
20 """
21 if config.running_vpp:
22 if os.path.isdir(config.socket_dir):
23 RunningVPP.socket_dir = config.socket_dir
24 else:
25 RunningVPP.socket_dir = RunningVPP.get_default_socket_dir()
26 RunningVPP.get_set_vpp_sock_files()
27 cls.get_stats_sock_path = RunningVPP.get_stats_sock_path
28 cls.get_api_sock_path = RunningVPP.get_api_sock_path
Naveen Joy70335e82023-07-28 16:33:30 -070029 cls.get_memif_sock_path = RunningVPP.get_memif_sock_path
Naveen Joyc872cec2022-08-30 13:59:03 -070030 cls.run_vpp = RunningVPP.run_vpp
31 cls.quit_vpp = RunningVPP.quit_vpp
32 cls.vpp = RunningVPP
33 cls.running_vpp = True
34 return cls
35
36
37class RunningVPP:
Naveen Joyc872cec2022-08-30 13:59:03 -070038 api_sock = "" # api_sock file path
39 stats_sock = "" # stats sock_file path
Naveen Joy70335e82023-07-28 16:33:30 -070040 memif_sock = "" # memif sock path
Naveen Joyc872cec2022-08-30 13:59:03 -070041 socket_dir = "" # running VPP's socket directory
42 pid = None # running VPP's pid
43 returncode = None # indicates to the framework that VPP is running
44
45 @classmethod
46 def get_stats_sock_path(cls):
47 return cls.stats_sock
48
49 @classmethod
50 def get_api_sock_path(cls):
51 return cls.api_sock
52
53 @classmethod
Naveen Joy70335e82023-07-28 16:33:30 -070054 def get_memif_sock_path(cls):
55 return cls.memif_sock
56
57 @classmethod
Naveen Joyc872cec2022-08-30 13:59:03 -070058 def run_vpp(cls):
59 """VPP is already running -- skip this action."""
60 pass
61
62 @classmethod
63 def quit_vpp(cls):
64 """Indicate quitting to framework by setting returncode=1."""
65 cls.returncode = 1
66
67 @classmethod
68 def terminate(cls):
69 """Indicate termination to framework by setting returncode=1."""
70 cls.returncode = 1
71
72 @classmethod
73 def get_default_socket_dir(cls):
74 """Return running VPP's default socket directory.
75
76 Default socket dir is:
77 /var/run/user/${UID}/vpp (or)
78 /var/run/vpp, if VPP is started as a root user
79 """
80 if cls.is_running_vpp():
81 vpp_user_id = (
82 subprocess.check_output(["ps", "-o", "uid=", "-p", str(cls.pid)])
83 .decode("utf-8")
84 .strip()
85 )
86 if vpp_user_id == "0":
87 return "/var/run/vpp"
88 else:
89 return f"/var/run/user/{vpp_user_id}/vpp"
90 else:
91 print(
92 "Error: getting default socket dir, as "
93 "a running VPP process could not be found"
94 )
95 sys.exit(1)
96
97 @classmethod
98 def get_set_vpp_sock_files(cls):
99 """Look for *.sock files in the socket_dir and set cls attributes.
100
101 Returns a tuple: (api_sock_file, stats_sock_file)
102 Sets cls.api_sock and cls.stats_sock attributes
103 """
104 # Return if the sock files are already set
105 if cls.api_sock and cls.stats_sock:
106 return (cls.api_sock, cls.stats_sock)
107 # Find running VPP's sock files in the socket dir
108 if os.path.isdir(cls.socket_dir):
109 if not cls.is_running_vpp():
110 print(
111 "Error: The socket dir for a running VPP directory is, "
112 "set but a running VPP process could not be found"
113 )
114 sys.exit(1)
115 sock_files = glob(os.path.join(cls.socket_dir + "/" + "*.sock"))
116 for sock_file in sock_files:
117 if "api.sock" in sock_file:
118 cls.api_sock = os.path.abspath(sock_file)
119 elif "stats.sock" in sock_file:
120 cls.stats_sock = os.path.abspath(sock_file)
Naveen Joy70335e82023-07-28 16:33:30 -0700121 elif "memif.sock" in sock_file:
122 cls.memif_sock = os.path.abspath(sock_file)
Naveen Joyc872cec2022-08-30 13:59:03 -0700123 if not cls.api_sock:
124 print(
125 f"Error: Could not find a valid api.sock file "
126 f"in running VPP's socket directory {cls.socket_dir}"
127 )
128 sys.exit(1)
129 if not cls.stats_sock:
130 print(
131 f"Error: Could not find a valid stats.sock file "
132 f"in running VPP's socket directory {cls.socket_dir}"
133 )
134 sys.exit(1)
135 return (cls.api_sock, cls.stats_sock)
136 else:
137 print("Error: The socket dir for a running VPP directory is unset")
138 sys.exit(1)
139
140 @classmethod
141 def is_running_vpp(cls):
142 """Return True if VPP's pid is visible else False."""
143 vpp_pid = subprocess.Popen(
144 ["pgrep", "-d,", "-x", "vpp_main"],
145 stdout=subprocess.PIPE,
146 stderr=subprocess.PIPE,
147 universal_newlines=True,
148 )
149 stdout, stderr = vpp_pid.communicate()
150 cls.pid = int(stdout.split(",")[0]) if stdout else None
151 return bool(cls.pid)
152
153 @classmethod
154 def poll(cls):
155 """Return None to indicate that the process hasn't terminated."""
156 return cls.returncode
157
158
159if __name__ == "__main__":
160 RunningVPP.socket_dir = RunningVPP.get_default_socket_dir()
161 RunningVPP.get_set_vpp_sock_files()
162 print(f"Running VPP's sock files")
163 print(f"api_sock_file {RunningVPP.api_sock}")
164 print(f"stats_sock_file {RunningVPP.stats_sock}")