| 
11 | 11 | from subprocess import Popen  | 
12 | 12 | from threading import Thread  | 
13 | 13 | 
 
  | 
 | 14 | +from tenacity import Retrying, stop_after_attempt, wait_fixed  | 
 | 15 | + | 
14 | 16 | ECHO_SERVER_PORT = 5252  | 
15 | 17 | SERVER_ACCEPT_BACKLOG = 128  | 
16 | 18 | TEST_CONNECTION_COUNT = 50  | 
@@ -142,53 +144,57 @@ def check_guest_connections(vm, server_port_path, blob_path, blob_hash):  | 
142 | 144 |         ["socat", f"UNIX-LISTEN:{server_port_path},fork,backlog=5", "exec:'/bin/cat'"]  | 
143 | 145 |     )  | 
144 | 146 | 
 
  | 
145 |  | -    # Link the listening Unix socket into the VM's jail, so that  | 
146 |  | -    # Firecracker can connect to it.  | 
147 |  | -    attempt = 0  | 
148 |  | -    # But 1st, give socat a bit of time to create the socket  | 
149 |  | -    while not Path(server_port_path).exists() and attempt < 3:  | 
150 |  | -        time.sleep(0.2)  | 
151 |  | -        attempt += 1  | 
152 |  | -    vm.create_jailed_resource(server_port_path)  | 
153 |  | - | 
154 |  | -    # Increase maximum process count for the ssh service.  | 
155 |  | -    # Avoids: "bash: fork: retry: Resource temporarily unavailable"  | 
156 |  | -    # Needed to execute the bash script that tests for concurrent  | 
157 |  | -    # vsock guest initiated connections.  | 
158 |  | -    pids_max_file = "/sys/fs/cgroup/system.slice/ssh.service/pids.max"  | 
159 |  | -    ecode, _, _ = vm.ssh.run(f"echo 1024 > {pids_max_file}")  | 
160 |  | -    assert ecode == 0, "Unable to set max process count for guest ssh service."  | 
161 |  | - | 
162 |  | -    # Build the guest worker sub-command.  | 
163 |  | -    # `vsock_helper` will read the blob file from STDIN and send the echo  | 
164 |  | -    # server response to STDOUT. This response is then hashed, and the  | 
165 |  | -    # hash is compared against `blob_hash` (computed on the host). This  | 
166 |  | -    # comparison sets the exit status of the worker command.  | 
167 |  | -    worker_cmd = "hash=$("  | 
168 |  | -    worker_cmd += "cat {}".format(blob_path)  | 
169 |  | -    worker_cmd += " | /tmp/vsock_helper echo 2 {}".format(ECHO_SERVER_PORT)  | 
170 |  | -    worker_cmd += " | md5sum | cut -f1 -d\\ "  | 
171 |  | -    worker_cmd += ")"  | 
172 |  | -    worker_cmd += ' && [[ "$hash" = "{}" ]]'.format(blob_hash)  | 
173 |  | - | 
174 |  | -    # Run `TEST_CONNECTION_COUNT` concurrent workers, using the above  | 
175 |  | -    # worker sub-command.  | 
176 |  | -    # If any worker fails, this command will fail. If all worker sub-commands  | 
177 |  | -    # succeed, this will also succeed.  | 
178 |  | -    cmd = 'workers="";'  | 
179 |  | -    cmd += "for i in $(seq 1 {}); do".format(TEST_CONNECTION_COUNT)  | 
180 |  | -    cmd += "  ({})& ".format(worker_cmd)  | 
181 |  | -    cmd += '  workers="$workers $!";'  | 
182 |  | -    cmd += "done;"  | 
183 |  | -    cmd += "for w in $workers; do wait $w || (wait; exit 1); done"  | 
184 |  | - | 
185 |  | -    ecode, _, stderr = vm.ssh.run(cmd)  | 
186 |  | -    echo_server.terminate()  | 
187 |  | -    rc = echo_server.wait()  | 
188 |  | -    # socat exits with 128 + 15 (SIGTERM)  | 
189 |  | -    assert rc == 143  | 
190 |  | - | 
191 |  | -    assert ecode == 0, stderr  | 
 | 147 | +    try:  | 
 | 148 | +        # Give socat a bit of time to create the socket  | 
 | 149 | +        for attempt in Retrying(  | 
 | 150 | +            wait=wait_fixed(0.2),  | 
 | 151 | +            stop=stop_after_attempt(3),  | 
 | 152 | +            reraise=True,  | 
 | 153 | +        ):  | 
 | 154 | +            with attempt:  | 
 | 155 | +                assert Path(server_port_path).exists()  | 
 | 156 | + | 
 | 157 | +        # Link the listening Unix socket into the VM's jail, so that  | 
 | 158 | +        # Firecracker can connect to it.  | 
 | 159 | +        vm.create_jailed_resource(server_port_path)  | 
 | 160 | + | 
 | 161 | +        # Increase maximum process count for the ssh service.  | 
 | 162 | +        # Avoids: "bash: fork: retry: Resource temporarily unavailable"  | 
 | 163 | +        # Needed to execute the bash script that tests for concurrent  | 
 | 164 | +        # vsock guest initiated connections.  | 
 | 165 | +        vm.ssh.check_output(  | 
 | 166 | +            "echo 1024 > /sys/fs/cgroup/system.slice/ssh.service/pids.max"  | 
 | 167 | +        )  | 
 | 168 | + | 
 | 169 | +        # Build the guest worker sub-command.  | 
 | 170 | +        # `vsock_helper` will read the blob file from STDIN and send the echo  | 
 | 171 | +        # server response to STDOUT. This response is then hashed, and the  | 
 | 172 | +        # hash is compared against `blob_hash` (computed on the host). This  | 
 | 173 | +        # comparison sets the exit status of the worker command.  | 
 | 174 | +        worker_cmd = "hash=$("  | 
 | 175 | +        worker_cmd += "cat {}".format(blob_path)  | 
 | 176 | +        worker_cmd += " | /tmp/vsock_helper echo 2 {}".format(ECHO_SERVER_PORT)  | 
 | 177 | +        worker_cmd += " | md5sum | cut -f1 -d\\ "  | 
 | 178 | +        worker_cmd += ")"  | 
 | 179 | +        worker_cmd += ' && [[ "$hash" = "{}" ]]'.format(blob_hash)  | 
 | 180 | + | 
 | 181 | +        # Run `TEST_CONNECTION_COUNT` concurrent workers, using the above  | 
 | 182 | +        # worker sub-command.  | 
 | 183 | +        # If any worker fails, this command will fail. If all worker sub-commands  | 
 | 184 | +        # succeed, this will also succeed.  | 
 | 185 | +        cmd = 'workers="";'  | 
 | 186 | +        cmd += "for i in $(seq 1 {}); do".format(TEST_CONNECTION_COUNT)  | 
 | 187 | +        cmd += "  ({})& ".format(worker_cmd)  | 
 | 188 | +        cmd += '  workers="$workers $!";'  | 
 | 189 | +        cmd += "done;"  | 
 | 190 | +        cmd += "for w in $workers; do wait $w || (wait; exit 1); done"  | 
 | 191 | + | 
 | 192 | +        vm.ssh.check_output(cmd)  | 
 | 193 | +    finally:  | 
 | 194 | +        echo_server.terminate()  | 
 | 195 | +        rc = echo_server.wait()  | 
 | 196 | +        # socat exits with 128 + 15 (SIGTERM)  | 
 | 197 | +        assert rc == 143  | 
192 | 198 | 
 
  | 
193 | 199 | 
 
  | 
194 | 200 | def make_host_port_path(uds_path, port):  | 
 | 
0 commit comments