podman

Форк
0
/
500-networking.bats 
1038 строк · 42.6 Кб
1
#!/usr/bin/env bats   -*- bats -*-
2
#
3
# Test podman local networking
4
#
5

6
load helpers
7
load helpers.network
8

9
@test "podman network - basic tests" {
10
    heading="NETWORK *ID *NAME *DRIVER"
11
    run_podman network ls
12
    assert "${lines[0]}" =~ "^$heading\$" "network ls header missing"
13
    run_podman network list
14
    assert "${lines[0]}" =~ "^$heading\$" "network list header missing"
15

16
    run_podman network ls --noheading
17
    assert "$output" !~ "$heading" "network ls --noheading shows header anyway"
18

19
    run_podman network ls -n
20
    assert "$output" !~ "$heading" "network ls -n shows header anyway"
21

22
    # check deterministic list order
23
    local net1=a-$(random_string 10)
24
    local net2=b-$(random_string 10)
25
    local net3=c-$(random_string 10)
26
    run_podman network create $net1
27
    run_podman network create $net2
28
    run_podman network create $net3
29

30
    run_podman network ls --quiet
31
    # just check that the order of the created networks is correct
32
    # we cannot do an exact match since developer and CI systems could contain more networks
33
    is "$output" ".*$net1.*$net2.*$net3.*podman.*" "networks sorted alphabetically"
34

35
    run_podman network rm $net1 $net2 $net3
36
}
37

38
# Copied from tsweeney's https://github.com/containers/podman/issues/4827
39
@test "podman networking: port on localhost" {
40
    random_1=$(random_string 30)
41
    random_2=$(random_string 30)
42

43
    HOST_PORT=$(random_free_port)
44
    SERVER=http://127.0.0.1:$HOST_PORT
45

46
    # Create a test file with random content
47
    INDEX1=$PODMAN_TMPDIR/hello.txt
48
    echo $random_1 > $INDEX1
49

50
    # Bind-mount this file with a different name to a container running httpd
51
    run_podman run -d --name myweb -p "$HOST_PORT:80" \
52
            -v $INDEX1:/var/www/index.txt:Z \
53
            -w /var/www \
54
            $IMAGE /bin/busybox-extras httpd -f -p 80
55
    cid=$output
56

57
    # In that container, create a second file, using exec and redirection
58
    run_podman exec -i myweb sh -c "cat > index2.txt" <<<"$random_2"
59
    # ...verify its contents as seen from container.
60
    run_podman exec -i myweb cat /var/www/index2.txt
61
    is "$output" "$random_2" "exec cat index2.txt"
62

63
    # Verify http contents: curl from localhost
64
    run curl -s -S $SERVER/index.txt
65
    is "$output" "$random_1" "curl 127.0.0.1:/index.txt"
66
    run curl -s -S $SERVER/index2.txt
67
    is "$output" "$random_2" "curl 127.0.0.1:/index2.txt"
68

69
    # Verify http contents: wget from a second container
70
    run_podman run --rm --net=host --http-proxy=false $IMAGE wget -qO - $SERVER/index.txt
71
    is "$output" "$random_1" "podman wget /index.txt"
72
    run_podman run --rm --net=host --http-proxy=false $IMAGE wget -qO - $SERVER/index2.txt
73
    is "$output" "$random_2" "podman wget /index2.txt"
74

75
    # Tests #4889 - two-argument form of "podman ports" was broken
76
    run_podman port myweb
77
    is "$output" "80/tcp -> 0.0.0.0:$HOST_PORT" "port <cid>"
78
    run_podman port myweb 80
79
    is "$output" "0.0.0.0:$HOST_PORT"  "port <cid> 80"
80
    run_podman port myweb 80/tcp
81
    is "$output" "0.0.0.0:$HOST_PORT"  "port <cid> 80/tcp"
82

83
    run_podman 125 port myweb 99/tcp
84
    is "$output" 'Error: failed to find published port "99/tcp"'
85

86
    # Clean up
87
    run_podman rm -f -t0 myweb
88
}
89

90
# Issue #5466 - port-forwarding doesn't work with this option and -d
91
@test "podman networking: port with --userns=keep-id for rootless or --uidmap=* for rootful" {
92
    skip_if_cgroupsv1 "run --uidmap fails on cgroups v1 (issue 15025, wontfix)"
93
    for cidr in "" "$(random_rfc1918_subnet).0/24"; do
94
        myport=$(random_free_port 52000-52999)
95
        if [[ -z $cidr ]]; then
96
            # regex to match that we are in 10.X subnet
97
            match="10\..*"
98
            # force bridge networking also for rootless
99
            # this ensures that rootless + bridge + userns + ports works
100
            network_arg="--network bridge"
101
        elif has_slirp4netns; then
102
            # Issue #9828 make sure a custom slirp4netns cidr also works
103
            network_arg="--network slirp4netns:cidr=$cidr"
104
            # slirp4netns interface ip is always .100
105
            match="${cidr%.*}.100"
106
        else
107
            echo "# [skipping subtest of $cidr - slirp4netns unavailable]" >&3
108
            continue
109
        fi
110

111
        # Container will exit as soon as 'nc' receives input
112
        # We use '-n -v' to give us log messages showing an incoming connection
113
        # and its IP address; the purpose of that is guaranteeing that the
114
        # remote IP is not 127.0.0.1 (podman PR #9052).
115
        # We could get more parseable output by using $NCAT_REMOTE_ADDR,
116
        # but busybox nc doesn't support that.
117
        userns="--userns=keep-id"
118
        is_rootless || userns="--uidmap=0:1111111:65536 --gidmap=0:1111111:65536"
119
        run_podman run -d ${userns} $network_arg -p 127.0.0.1:$myport:$myport \
120
                   $IMAGE nc -l -n -v -p $myport
121
        cid="$output"
122

123
        # check that podman stores the network info correctly when a userns is used (#14465)
124
        run_podman container inspect --format "{{.NetworkSettings.SandboxKey}}" $cid
125
        assert "$output" =~ ".*/netns/netns-.*" "Netns path should be set"
126

127
        wait_for_output "listening on .*:$myport .*" $cid
128

129
        # emit random string, and check it
130
        teststring=$(random_string 30)
131
        echo "$teststring" | nc 127.0.0.1 $myport
132

133
        run_podman logs $cid
134
        # Sigh. We can't check line-by-line, because 'nc' output order is
135
        # unreliable. We usually get the 'connect to' line before the random
136
        # string, but sometimes we get it after. So, just do substring checks.
137
        is "$output" ".*listening on \[::\]:$myport .*" "nc -v shows right port"
138

139
        # This is the truly important check: make sure the remote IP is not 127.X.
140
        is "$output" \
141
           ".*connect to \[::ffff:$match*\]:$myport from \[::ffff:$match\]:.*" \
142
           "nc -v shows remote IP address is not 127.0.0.1"
143
        is "$output" ".*${teststring}.*" "test string received on container"
144

145
        # Clean up
146
        run_podman wait $cid
147
        run_podman rm $cid
148
    done
149
}
150

151
@test "podman pod manages /etc/hosts correctly" {
152
    local pod_name=pod-$(random_string 10)
153
    local infra_name=infra-$(random_string 10)
154
    local con1_name=con1-$(random_string 10)
155
    local con2_name=con2-$(random_string 10)
156
    run_podman pod create --name $pod_name  --infra-name $infra_name
157
    pid="$output"
158
    run_podman run --pod $pod_name --name $con1_name $IMAGE cat /etc/hosts
159
    is "$output" ".*\s$pod_name $infra_name.*" "Pod hostname in /etc/hosts"
160
    is "$output" ".*127.0.0.1\s$con1_name.*" "Container1 name in /etc/hosts"
161
    # get the length of the hosts file
162
    old_lines=${#lines[@]}
163

164
    # since the first container should be cleaned up now we should only see the
165
    # new host entry and the old one should be removed (lines check)
166
    run_podman run --pod $pod_name --name $con2_name $IMAGE cat /etc/hosts
167
    is "$output" ".*\s$pod_name $infra_name.*" "Pod hostname in /etc/hosts"
168
    is "$output" ".*127.0.0.1\s$con2_name.*" "Container2 name in /etc/hosts"
169
    is "${#lines[@]}" "$old_lines" "Number of hosts lines is equal"
170

171
    run_podman run --pod $pod_name  $IMAGE sh -c  "hostname && cat /etc/hostname"
172
    is "${lines[0]}" "$pod_name" "hostname is the pod hostname"
173
    is "${lines[1]}" "$pod_name" "/etc/hostname contains correct pod hostname"
174

175
    run_podman pod rm -f -t0 $pod_name
176
    is "$output" "$pid" "Only ID in output (no extra errors)"
177

178
    # Clean up
179
    run_podman rmi $(pause_image)
180
}
181

182
@test "podman run with slirp4ns assigns correct addresses to /etc/hosts" {
183
    has_slirp4netns || skip "slirp4netns unavailable"
184

185
    CIDR="$(random_rfc1918_subnet)"
186
    IP=$(hostname -I | cut -f 1 -d " ")
187
    local conname=con-$(random_string 10)
188
    run_podman run --rm --network slirp4netns:cidr="${CIDR}.0/24" \
189
                --name $conname --hostname $conname $IMAGE cat /etc/hosts
190
    is "$output"   ".*${IP}	host.containers.internal"   "host.containers.internal should be host address"
191
    is "$output"   ".*${CIDR}.100	$conname $conname"   "$conname should be the cidr+100 address"
192

193
    if is_rootless; then
194
    # check the slirp ip also works correct with userns
195
        run_podman run --rm --userns keep-id --network slirp4netns:cidr="${CIDR}.0/24" \
196
                --name $conname --hostname $conname $IMAGE cat /etc/hosts
197
        is "$output"   ".*${IP}	host.containers.internal"   "host.containers.internal should be host address"
198
        is "$output"   ".*${CIDR}.100	$conname $conname"   "$conname should be the cidr+100 address"
199
    fi
200
}
201

202
@test "podman run with slirp4ns adds correct dns address to resolv.conf" {
203
    has_slirp4netns || skip "slirp4netns unavailable"
204

205
    CIDR="$(random_rfc1918_subnet)"
206
    run_podman run --rm --network slirp4netns:cidr="${CIDR}.0/24" \
207
                $IMAGE cat /etc/resolv.conf
208
    assert "$output" =~ "nameserver ${CIDR}.3" "resolv.conf should have slirp4netns cidr+3 as first nameserver"
209
    no_userns_out="$output"
210

211
    if is_rootless; then
212
    # check the slirp ip also works correct with userns
213
        run_podman run --rm --userns keep-id --network slirp4netns:cidr="${CIDR}.0/24" \
214
                $IMAGE cat /etc/resolv.conf
215
        assert "$output" =~ "nameserver ${CIDR}.3" "resolv.conf should have slirp4netns cidr+3 as first nameserver with userns"
216
        assert "$output" == "$no_userns_out" "resolv.conf should look the same for userns"
217
    fi
218

219
}
220

221
@test "podman run with slirp4ns assigns correct ip address container" {
222
    has_slirp4netns || skip "slirp4netns unavailable"
223

224
    CIDR="$(random_rfc1918_subnet)"
225
    run_podman run --rm --network slirp4netns:cidr="${CIDR}.0/24" \
226
                $IMAGE sh -c "ip address | grep ${CIDR}"
227
    is "$output"   ".*inet ${CIDR}.100/24 \+"   "container should have slirp4netns cidr+100 assigned to interface"
228
}
229

230
# "network create" now works rootless, with the help of a special container
231
@test "podman network create" {
232
    myport=$(random_free_port)
233

234
    local mynetname=testnet-$(random_string 10)
235
    local mysubnet=$(random_rfc1918_subnet)
236

237
    run_podman network create --subnet "${mysubnet}.0/24" $mynetname
238
    is "$output" "$mynetname" "output of 'network create'"
239

240
    # (Assert that output is formatted, not a one-line blob: #8011)
241
    run_podman network inspect $mynetname
242
    assert "${#lines[*]}" -ge 5 "Output from 'pod inspect'; see #8011"
243

244
    run_podman run --rm --network $mynetname $IMAGE ip a
245
    is "$output" ".* inet ${mysubnet}\.2/24 brd ${mysubnet}\.255 " \
246
       "sdfsdf"
247

248
    run_podman run -d --network $mynetname -p 127.0.0.1:$myport:$myport \
249
               $IMAGE nc -l -n -v -p $myport
250
    cid="$output"
251

252
    # FIXME: debugging for #11871
253
    run_podman exec $cid cat /etc/resolv.conf
254
    if is_rootless && ! is_remote; then
255
        run_podman unshare --rootless-cni cat /etc/resolv.conf
256
    fi
257
    ps uxww
258

259
    # check that dns is working inside the container
260
    run_podman exec $cid nslookup google.com
261

262
    # emit random string, and check it
263
    teststring=$(random_string 30)
264
    echo "$teststring" | nc 127.0.0.1 $myport
265

266
    run_podman logs $cid
267
    # Sigh. We can't check line-by-line, because 'nc' output order is
268
    # unreliable. We usually get the 'connect to' line before the random
269
    # string, but sometimes we get it after. So, just do substring checks.
270
    is "$output" ".*listening on \[::\]:$myport .*" "nc -v shows right port"
271

272
    # This is the truly important check: make sure the remote IP is
273
    # in the 172.X range, not 127.X.
274
    is "$output" \
275
       ".*connect to \[::ffff:172\..*\]:$myport from \[::ffff:172\..*\]:.*" \
276
       "nc -v shows remote IP address in 172.X space (not 127.0.0.1)"
277
    is "$output" ".*${teststring}.*" "test string received on container"
278

279
    # Cannot create network with the same name
280
    run_podman 125 network create $mynetname
281
    is "$output" "Error: network name $mynetname already used: network already exists" \
282
       "Trying to create an already-existing network"
283

284
    run_podman rm -t 0 -f $cid
285
    run_podman network rm $mynetname
286
    run_podman 1 network rm $mynetname
287
}
288

289
@test "podman network reload" {
290
    skip_if_remote "podman network reload does not have remote support"
291

292
    random_1=$(random_string 30)
293
    HOST_PORT=$(random_free_port)
294
    SERVER=http://127.0.0.1:$HOST_PORT
295

296
    # Create a test file with random content
297
    INDEX1=$PODMAN_TMPDIR/hello.txt
298
    echo $random_1 > $INDEX1
299

300
    # use default network
301
    local netname=podman
302

303
    # Bind-mount this file with a different name to a container running httpd
304
    run_podman run -d --name myweb -p "$HOST_PORT:80" \
305
            --network $netname \
306
            -v $INDEX1:/var/www/index.txt:Z \
307
            -w /var/www \
308
            $IMAGE /bin/busybox-extras httpd -f -p 80
309
    cid=$output
310

311
    run_podman inspect $cid --format "{{(index .NetworkSettings.Networks \"$netname\").IPAddress}}"
312
    ip1="$output"
313
    run_podman inspect $cid --format "{{(index .NetworkSettings.Networks \"$netname\").MacAddress}}"
314
    mac1="$output"
315

316
    # Verify http contents: curl from localhost
317
    run curl -s -S $SERVER/index.txt
318
    is "$output" "$random_1" "curl 127.0.0.1:/index.txt"
319

320
    # rootless cannot modify iptables
321
    if ! is_rootless; then
322
        # flush the port forwarding iptable rule here
323
        chain="CNI-HOSTPORT-DNAT"
324
        if is_netavark; then
325
            chain="NETAVARK-HOSTPORT-DNAT"
326
        fi
327
        run iptables -t nat -F "$chain"
328

329
        # check that we cannot curl (timeout after 5 sec)
330
        run timeout 5 curl -s $SERVER/index.txt
331
        assert $status -eq 124 "curl did not time out"
332
    fi
333

334
    # reload the network to recreate the iptables rules
335
    run_podman network reload $cid
336
    is "$output" "$cid" "Output does match container ID"
337

338
    # check that we still have the same mac and ip
339
    run_podman inspect $cid --format "{{(index .NetworkSettings.Networks \"$netname\").IPAddress}}"
340
    is "$output" "$ip1" "IP address changed after podman network reload"
341
    run_podman inspect $cid --format "{{(index .NetworkSettings.Networks \"$netname\").MacAddress}}"
342
    is "$output" "$mac1" "MAC address changed after podman network reload"
343

344
    # check that we can still curl
345
    run curl -s $SERVER/index.txt
346
    is "$output" "$random_1" "curl 127.0.0.1:/index.txt"
347

348
    # create second network
349
    netname2=testnet-$(random_string 10)
350
    run_podman network create --ipv6 $netname2
351
    is "$output" "$netname2" "output of 'network create'"
352

353
    # connect the container to the second network
354
    run_podman network connect $netname2 $cid
355

356
    run_podman inspect $cid --format "{{(index .NetworkSettings.Networks \"$netname2\").IPAddress}}"
357
    ip2="$output"
358
    run_podman inspect $cid --format "{{(index .NetworkSettings.Networks \"$netname2\").GlobalIPv6Address}}"
359
    is "$output" "fd.*:.*" "IPv6 address should start with fd..."
360
    ipv6="$output"
361
    run_podman inspect $cid --format "{{(index .NetworkSettings.Networks \"$netname2\").MacAddress}}"
362
    mac2="$output"
363

364
    # make sure --all is working and that this
365
    # cmd also works if the iptables still exists
366
    run_podman network reload --all
367
    is "$output" "$cid" "Output does match container ID"
368

369
    # check that both network keep there ip and mac
370
    run_podman inspect $cid --format "{{(index .NetworkSettings.Networks \"$netname\").IPAddress}}"
371
    is "$output" "$ip1" "IP address changed after podman network reload ($netname)"
372
    run_podman inspect $cid --format "{{(index .NetworkSettings.Networks \"$netname\").MacAddress}}"
373
    is "$output" "$mac1" "MAC address changed after podman network reload ($netname)"
374
    run_podman inspect $cid --format "{{(index .NetworkSettings.Networks \"$netname2\").IPAddress}}"
375
    is "$output" "$ip2" "IP address changed after podman network reload ($netname2)"
376
    run_podman inspect $cid --format "{{(index .NetworkSettings.Networks \"$netname2\").GlobalIPv6Address}}"
377
    is "$output" "$ipv6" "IPv6 address changed after podman network reload ($netname2)"
378
    run_podman inspect $cid --format "{{(index .NetworkSettings.Networks \"$netname2\").MacAddress}}"
379
    is "$output" "$mac2" "MAC address changed after podman network reload ($netname2)"
380

381
    # check that we can still curl
382
    run curl -s -S $SERVER/index.txt
383
    is "$output" "$random_1" "curl 127.0.0.1:/index.txt"
384

385
    # clean up the container
386
    run_podman rm -t 0 -f $cid
387

388
    # test that we cannot remove the default network
389
    run_podman 125 network rm -t 0 -f $netname
390
    is "$output" "Error: default network $netname cannot be removed" "Remove default network"
391

392
    run_podman network rm -t 0 -f $netname2
393
}
394

395
@test "podman rootless cni adds /usr/sbin to PATH" {
396
    is_rootless || skip "only meaningful for rootless"
397

398
    local mynetname=testnet-$(random_string 10)
399
    run_podman --noout network create $mynetname
400
    is "$output" "" "output should be empty"
401

402
    # Test that rootless cni adds /usr/sbin to $PATH
403
    # iptables is located under /usr/sbin and is needed for the CNI plugins.
404
    # Debian doesn't add /usr/sbin to $PATH for rootless users so we have to add it.
405
    PATH=/usr/local/bin:/usr/bin run_podman run --rm --network $mynetname $IMAGE ip addr
406
    is "$output" ".*eth0.*" "Interface eth0 not found in ip addr output"
407

408
    run_podman --noout network rm -t 0 -f $mynetname
409
    is "$output" "" "output should be empty"
410
}
411

412
@test "podman ipv6 in /etc/resolv.conf" {
413
    ipv6_regex='([0-9A-Fa-f]{0,4}:){2,7}([0-9A-Fa-f]{0,4})(%\w+)?'
414

415
    # Make sure to read the correct /etc/resolv.conf file in case of systemd-resolved.
416
    resolve_file=$(readlink -f /etc/resolv.conf)
417
    if [[ "$resolve_file" == "/run/systemd/resolve/stub-resolv.conf" ]]; then
418
        resolve_file="/run/systemd/resolve/resolv.conf"
419
    fi
420

421
    # If the host doesn't have an ipv6 in resolv.conf skip this test.
422
    # We should never modify resolv.conf on the host.
423
    if ! grep -E "$ipv6_regex" "$resolve_file"; then
424
        skip "This test needs an ipv6 nameserver in $resolve_file"
425
    fi
426

427
    if has_slirp4netns; then
428
        # ipv4 slirp
429
        run_podman run --rm --network slirp4netns:enable_ipv6=false $IMAGE cat /etc/resolv.conf
430
        assert "$output" !~ "$ipv6_regex" "resolv.conf should not contain ipv6 nameserver"
431

432
        # ipv6 slirp
433
        run_podman run --rm --network slirp4netns:enable_ipv6=true $IMAGE cat /etc/resolv.conf
434
        assert "$output" =~ "$ipv6_regex" "resolv.conf should contain ipv6 nameserver"
435
    fi
436

437
    # ipv4 cni
438
    local mysubnet=$(random_rfc1918_subnet)
439
    local netname=testnet-$(random_string 10)
440

441
    run_podman network create --subnet $mysubnet.0/24 $netname
442
    is "$output" "$netname" "output of 'network create'"
443

444
    run_podman run --rm --network $netname $IMAGE cat /etc/resolv.conf
445
    assert "$output" !~ "$ipv6_regex" "resolv.conf should not contain ipv6 nameserver"
446

447
    run_podman network rm -t 0 -f $netname
448

449
    # ipv6 cni
450
    mysubnet=fd00:4:4:4:4::/64
451
    netname=testnet-$(random_string 10)
452

453
    run_podman network create --subnet $mysubnet $netname
454
    is "$output" "$netname" "output of 'network create'"
455

456
    run_podman run --rm --network $netname $IMAGE cat /etc/resolv.conf
457
    assert "$output" =~ "$ipv6_regex" "resolv.conf should contain ipv6 nameserver"
458

459
    run_podman network rm -t 0 -f $netname
460
}
461

462
# Test for https://github.com/containers/podman/issues/10052
463
# bats test_tags=distro-integration
464
@test "podman network connect/disconnect with port forwarding" {
465
    random_1=$(random_string 30)
466
    HOST_PORT=$(random_free_port)
467
    SERVER=http://127.0.0.1:$HOST_PORT
468

469
    # Create a test file with random content
470
    INDEX1=$PODMAN_TMPDIR/hello.txt
471
    echo $random_1 > $INDEX1
472

473
    local netname=testnet-$(random_string 10)
474
    run_podman network create $netname
475
    is "$output" "$netname" "output of 'network create'"
476

477
    local netname2=testnet2-$(random_string 10)
478
    run_podman network create $netname2
479
    is "$output" "$netname2" "output of 'network create'"
480

481
    # First, run a container in background to ensure that the rootless cni ns
482
    # is not destroyed after network disconnect.
483
    run_podman run -d --network $netname $IMAGE top
484
    background_cid=$output
485

486
    local hostname=host-$(random_string 10)
487
    # Run a httpd container on first network with exposed port
488
    run_podman run -d -p "$HOST_PORT:80" \
489
            --hostname $hostname \
490
            --network $netname \
491
            -v $INDEX1:/var/www/index.txt:Z \
492
            -w /var/www \
493
            $IMAGE /bin/busybox-extras httpd -f -p 80
494
    cid=$output
495

496
    # Verify http contents: curl from localhost. This is the first time
497
    # connecting, so, allow retries until httpd starts.
498
    run curl --retry 2 --retry-connrefused -s $SERVER/index.txt
499
    is "$output" "$random_1" "curl $SERVER/index.txt"
500

501
    run_podman inspect $cid --format "{{(index .NetworkSettings.Networks \"$netname\").IPAddress}}"
502
    ip="$output"
503
    run_podman inspect $cid --format "{{(index .NetworkSettings.Networks \"$netname\").MacAddress}}"
504
    mac="$output"
505

506
    # check network alias for container short id
507
    run_podman inspect $cid --format "{{(index .NetworkSettings.Networks \"$netname\").Aliases}}"
508
    is "$output" "[${cid:0:12} $hostname]" "short container id and hostname in network aliases"
509

510
    # check /etc/hosts for our entry
511
    run_podman exec $cid cat /etc/hosts
512
    is "$output" ".*$ip.*" "hosts contain expected ip"
513

514
    run_podman network disconnect $netname $cid
515
    is "$output" "" "Output should be empty (no errors)"
516

517
    # check /etc/hosts again, the entry should be gone now
518
    run_podman exec $cid cat /etc/hosts
519
    assert "$output" !~ "$ip" "IP ($ip) should no longer be in /etc/hosts"
520

521
    # check that we cannot curl (timeout after 3 sec). Fails with inconsistent
522
    # curl exit codes, so, just check for nonzero.
523
    run curl --max-time 3 -s -S $SERVER/index.txt
524
    assert $status -ne 0 \
525
           "curl did not fail, it should have timed out or failed with non zero exit code"
526

527
    run_podman network connect $netname $cid
528
    is "$output" "" "Output should be empty (no errors)"
529

530
    # curl should work again
531
    run curl --max-time 3 -s -S $SERVER/index.txt
532
    is "$output" "$random_1" "curl 127.0.0.1:/index.txt should work again"
533

534
    # check that we have a new ip and mac
535
    # if the ip is still the same this whole test turns into a nop
536
    run_podman inspect $cid --format "{{(index .NetworkSettings.Networks \"$netname\").IPAddress}}"
537
    new_ip="$output"
538
    assert "$new_ip" != "$ip" \
539
           "IP address did not change after podman network disconnect/connect"
540

541
    run_podman inspect $cid --format "{{(index .NetworkSettings.Networks \"$netname\").MacAddress}}"
542
    assert "$output" != "$mac" \
543
           "MAC address did not change after podman network disconnect/connect"
544

545
    # check /etc/hosts for the new entry
546
    run_podman exec $cid cat /etc/hosts
547
    is "$output" ".*$new_ip.*" "hosts contain expected new ip"
548

549
    # Disconnect/reconnect of a container *with no ports* should succeed quietly
550
    run_podman network disconnect $netname $background_cid
551
    is "$output" "" "disconnect of container with no open ports"
552
    run_podman network connect $netname $background_cid
553
    is "$output" "" "(re)connect of container with no open ports"
554

555
    # FIXME FIXME FIXME: #11825: bodhi tests are failing, remote+rootless only,
556
    # with "dnsmasq: failed to create inotify". This error has never occurred
557
    # in CI, and Ed has been unable to reproduce it on 1minutetip. This next
558
    # line is a suggestion from Paul Holzinger for trying to shed light on
559
    # the system context before the failure. This output will be invisible
560
    # if the test passes.
561
    for foo in /proc/\*/fd/*; do readlink -f $foo; done |grep '^/proc/.*inotify' |cut -d/ -f3 | xargs -I '{}' -- ps --no-headers -o '%p %U %a' -p '{}' |uniq -c |sort -n
562

563
    # connect a second network
564
    run_podman network connect $netname2 $cid
565
    is "$output" "" "Output should be empty (no errors)"
566

567
    # check network2 alias for container short id
568
    run_podman inspect $cid --format "{{(index .NetworkSettings.Networks \"$netname2\").Aliases}}"
569
    is "$output" "[${cid:0:12} $hostname]" "short container id and hostname in network2 aliases"
570

571
    # curl should work
572
    run curl --max-time 3 -s -S $SERVER/index.txt
573
    is "$output" "$random_1" "curl 127.0.0.1:/index.txt should work"
574

575
    # disconnect the first network
576
    run_podman network disconnect $netname $cid
577

578
    # curl should still work
579
    run curl --max-time 3 -s -S $SERVER/index.txt
580
    is "$output" "$random_1" "curl 127.0.0.1:/index.txt should still work"
581

582
    # clean up
583
    run_podman rm -t 0 -f $cid $background_cid
584
    run_podman network rm -t 0 -f $netname $netname2
585
}
586

587
@test "podman network after restart" {
588
    random_1=$(random_string 30)
589

590
    HOST_PORT=$(random_free_port)
591
    SERVER=http://127.0.0.1:$HOST_PORT
592

593
    # Create a test file with random content
594
    INDEX1=$PODMAN_TMPDIR/hello.txt
595
    echo $random_1 > $INDEX1
596

597
    local netname=testnet-$(random_string 10)
598
    run_podman network create $netname
599
    is "$output" "$netname" "output of 'network create'"
600

601
    local -a networks=("$netname")
602
    if has_slirp4netns; then
603
        networks+=("slirp4netns")
604
    fi
605
    for network in "${networks[@]}"; do
606
        # Start container with the restart always policy
607
        run_podman run -d --name myweb -p "$HOST_PORT:80" \
608
                --restart always \
609
                --network $network \
610
                -v $INDEX1:/var/www/index.txt:Z \
611
                -w /var/www \
612
                $IMAGE /bin/busybox-extras httpd -f -p 80
613
        cid=$output
614

615
        # Tests #10310: podman will restart slirp4netns on container restart
616
        run_podman container inspect --format "{{.State.Pid}}" $cid
617
        pid=$output
618

619
        # Kill the process; podman restart policy will bring up a new container.
620
        # -9 is crucial: busybox httpd ignores all other signals.
621
        kill -9 $pid
622
        # Wait for process to exit
623
        retries=30
624
        while kill -0 $pid; do
625
            sleep 0.5
626
            retries=$((retries - 1))
627
            assert $retries -gt 0 "Process $pid (container $cid) refused to die"
628
        done
629

630
        # Wait for container to restart
631
        retries=20
632
        while :;do
633
            run_podman container inspect --format "{{.State.Pid}}" $cid
634
            # pid is 0 as long as the container is not running
635
            if [[ $output -ne 0 ]]; then
636
                assert "$output" != "$pid" \
637
                       "This should never happen! Restarted container has same PID as killed one!"
638
                break
639
            fi
640
            sleep 0.5
641
            retries=$((retries - 1))
642
            assert $retries -gt 0 "Timed out waiting for container to restart"
643
        done
644

645
        # Verify http contents again: curl from localhost
646
        # Use retry since it can take a moment until the new container is ready
647
        local curlcmd="curl --retry 2 --retry-connrefused -s $SERVER/index.txt"
648
        echo "$_LOG_PROMPT $curlcmd"
649
        run $curlcmd
650
        echo "$output"
651
        assert "$status" == 0 "curl exit status"
652
        assert "$output" = "$random_1" "curl $SERVER/index.txt after auto restart"
653

654
        run_podman 0+w restart -t1 $cid
655
        if ! is_remote; then
656
            require_warning "StopSignal SIGTERM failed to stop container .* in 1 seconds, resorting to SIGKILL" \
657
                            "podman restart issues warning"
658
        fi
659

660
        # Verify http contents again: curl from localhost
661
        # Use retry since it can take a moment until the new container is ready
662
        echo "$_LOG_PROMPT $curlcmd"
663
        run $curlcmd
664
        echo "$output"
665
        assert "$status" == 0 "curl exit status"
666
        assert "$output" = "$random_1" "curl $SERVER/index.txt after podman restart"
667

668
        run_podman rm -t 0 -f $cid
669
    done
670

671
    # Clean up network
672
    run_podman network rm -t 0 -f $netname
673
}
674

675
@test "podman run CONTAINERS_CONF_OVERRIDE dns options" {
676
    skip_if_remote "CONTAINERS_CONF_OVERRIDE redirect does not work on remote"
677
    # Test on the CLI and via containers.conf
678
    containersconf=$PODMAN_TMPDIR/containers.conf
679

680
    searchIP="100.100.100.100"
681
    cat >$containersconf <<EOF
682
[containers]
683
  dns_searches  = [ "example.com"]
684
  dns_servers = [
685
    "1.1.1.1",
686
    "$searchIP",
687
    "1.0.0.1",
688
    "8.8.8.8",
689
]
690
EOF
691

692
    local nl="
693
"
694

695
    CONTAINERS_CONF_OVERRIDE=$containersconf run_podman run --rm $IMAGE cat /etc/resolv.conf
696
    is "$output" "search example.com.*" "correct search domain"
697
    is "$output" ".*nameserver 1.1.1.1${nl}nameserver $searchIP${nl}nameserver 1.0.0.1${nl}nameserver 8.8.8.8" "nameserver order is correct"
698

699
    # create network with dns
700
    local netname=testnet-$(random_string 10)
701
    local subnet=$(random_rfc1918_subnet)
702
    run_podman network create --subnet "$subnet.0/24"  $netname
703
    # custom server overwrites the network dns server
704
    CONTAINERS_CONF_OVERRIDE=$containersconf run_podman run --network $netname --rm $IMAGE cat /etc/resolv.conf
705
    is "$output" "search example.com.*" "correct search domain"
706
    local store=$output
707
    if is_netavark; then
708
        assert "$store" == "search example.com${nl}nameserver $subnet.1" "only integrated dns nameserver is set"
709
    else
710
        assert "$store" == "search example.com
711
nameserver 1.1.1.1
712
nameserver $searchIP
713
nameserver 1.0.0.1
714
nameserver 8.8.8.8" "nameserver order is correct"
715
    fi
716
    # we should use the integrated dns server
717
    run_podman run --network $netname --rm $IMAGE cat /etc/resolv.conf
718
    assert "$output" =~ "search dns.podman.*" "correct search domain"
719
    assert "$output" =~ ".*nameserver $subnet.1.*" \
720
           "integrated dns nameserver is set"
721

722
    # host network should keep localhost nameservers
723
    if grep 127.0.0. /etc/resolv.conf >/dev/null; then
724
        run_podman run --network host --rm $IMAGE cat /etc/resolv.conf
725
        assert "$output" =~ ".*nameserver 127\.0\.0.*" \
726
               "resolv.conf contains localhost nameserver"
727
    fi
728
    # host net + dns still works
729
    run_podman run --network host --dns 1.1.1.1 --rm $IMAGE cat /etc/resolv.conf
730
    assert "$output" =~ ".*nameserver 1\.1\.1\.1.*" \
731
           "resolv.conf contains 1.1.1.1 nameserver"
732
}
733

734
@test "podman run port forward range" {
735
    # we run a long loop of tests lets run all combinations before bailing out
736
    defer-assertion-failures
737

738
    local -a netmodes=("bridge")
739
    # As of podman 5.0, slirp4netns is optional
740
    if has_slirp4netns; then
741
        netmodes+=("slirp4netns:port_handler=slirp4netns" "slirp4netns:port_handler=rootlesskit")
742
    fi
743
    # pasta only works rootless
744
    if is_rootless; then
745
        if has_pasta; then
746
            netmodes+=("pasta")
747
        else
748
            echo "# WARNING: pasta unavailable!" >&3
749
        fi
750
    fi
751

752
    for netmode in "${netmodes[@]}"; do
753
        local range=$(random_free_port_range 3)
754
        # die() inside $(...) does not actually stop us.
755
        assert "$range" != "" "Could not find free port range"
756

757
        local port="${range%-*}"
758
        local end_port="${range#*-}"
759
        local random=$(random_string)
760

761
        run_podman run --network $netmode -p "$range:$range" -d $IMAGE sleep inf
762
        cid="$output"
763
        for port in $(seq $port $end_port); do
764
            run_podman exec -d $cid nc -l -p $port -e /bin/cat
765

766
            # we have to rety ncat as it can flake as we exec in the background so nc -l
767
            # might not have bound the port yet, retry seems simpler than checking if the
768
            # port is bound in the container, https://github.com/containers/podman/issues/21561.
769
            retries=5
770
            while [[ $retries -gt 0 ]]; do
771
                # -w 1 adds a 1 second timeout. For some reason, ubuntu's ncat
772
                # doesn't close the connection on EOF, and other options to
773
                # change this are not portable across distros. -w seems to work.
774
                run nc -w 1 127.0.0.1 $port <<<$random
775
                if [[ $status -eq 0 ]]; then
776
                    break
777
                fi
778
                sleep 0.5
779
                retries=$((retries -1))
780
            done
781
            is "$output" "$random" "ncat got data back (netmode=$netmode port=$port)"
782
        done
783

784
        run_podman rm -f -t0 $cid
785
    done
786
}
787

788
@test "podman run CONTAINERS_CONF_OVERRIDE /etc/hosts options" {
789
    skip_if_remote "CONTAINERS_CONF_OVERRIDE redirect does not work on remote"
790

791
    containersconf=$PODMAN_TMPDIR/containers.conf
792
    basehost=$PODMAN_TMPDIR/host
793

794
    ip1="$(random_rfc1918_subnet).$((RANDOM % 256))"
795
    name1=host1$(random_string)
796
    ip2="$(random_rfc1918_subnet).$((RANDOM % 256))"
797
    name2=host2$(random_string)
798

799
    cat >$basehost <<EOF
800
$ip1 $name1
801
$ip2 $name2 #some comment
802
EOF
803

804
    containersinternal_ip="$(random_rfc1918_subnet).$((RANDOM % 256))"
805
    cat >$containersconf <<EOF
806
[containers]
807
  base_hosts_file = "$basehost"
808
  host_containers_internal_ip = "$containersinternal_ip"
809
EOF
810

811
    ip3="$(random_rfc1918_subnet).$((RANDOM % 256))"
812
    name3=host3$(random_string)
813

814
    CONTAINERS_CONF_OVERRIDE=$containersconf run_podman run --rm --add-host $name3:$ip3 $IMAGE cat /etc/hosts
815
    is "$output" ".*$ip3[[:blank:]]$name3.*" "--add-host entry in /etc/host"
816
    is "$output" ".*$ip1[[:blank:]]$name1.*" "first base entry in /etc/host"
817
    is "$output" ".*$ip2[[:blank:]]$name2.*" "second base entry in /etc/host"
818
    is "$output" ".*127.0.0.1[[:blank:]]localhost.*" "ipv4 localhost entry added"
819
    is "$output" ".*::1[[:blank:]]localhost.*" "ipv6 localhost entry added"
820
    is "$output" ".*$containersinternal_ip[[:blank:]]host\.containers\.internal.*" "host.containers.internal ip from config in /etc/host"
821
    is "${#lines[@]}" "7" "expect 7 host entries in /etc/hosts"
822

823
    # now try again with container name and hostname == host entry name
824
    # in this case podman should not add its own entry thus we only have 5 entries (-1 for the removed --add-host)
825
    CONTAINERS_CONF_OVERRIDE=$containersconf run_podman run --rm --name $name1 --hostname $name1 $IMAGE cat /etc/hosts
826
    is "$output" ".*$ip1[[:blank:]]$name1.*" "first base entry in /etc/host"
827
    is "$output" ".*$ip2[[:blank:]]$name2.*" "second base entry in /etc/host"
828
    is "$output" ".*$containersinternal_ip[[:blank:]]host\.containers\.internal.*" "host.containers.internal ip from config in /etc/host"
829
    is "${#lines[@]}" "5" "expect 5 host entries in /etc/hosts"
830
}
831

832
@test "podman run /etc/* permissions" {
833
    skip_if_cgroupsv1 "run --uidmap fails on cgroups v1 (issue 15025, wontfix)"
834
    userns="--userns=keep-id"
835
    if ! is_rootless; then
836
        userns="--uidmap=0:1111111:65536 --gidmap=0:1111111:65536"
837
    fi
838
    # check with and without userns
839
    for userns in "" "$userns"; do
840
        # check the /etc/hosts /etc/hostname /etc/resolv.conf are owned by root
841
        run_podman run $userns --rm $IMAGE stat -c %u:%g /etc/hosts /etc/resolv.conf /etc/hostname
842
        is "${lines[0]}" "0\:0" "/etc/hosts owned by root"
843
        is "${lines[1]}" "0\:0" "/etc/resolv.conf owned by root"
844
        is "${lines[2]}" "0\:0" "/etc/hosts owned by root"
845
    done
846
}
847

848
@test "podman network rm --force bogus" {
849
    run_podman 1 network rm bogus
850
    is "$output" "Error: unable to find network with name or ID bogus: network not found" "Should print error"
851
    run_podman network rm -t -1 --force bogus
852
    is "$output" "" "Should print no output"
853

854
    run_podman network create testnet
855
    run_podman network rm --force bogus testnet
856
    assert "$output" = "testnet" "rm network"
857
    run_podman network ls -q
858
    assert "$output" = "podman" "only podman network listed"
859
}
860

861
@test "podman network rm --dns-option " {
862
    dns_opt=dns$(random_string)
863
    run_podman run --rm --dns-opt=${dns_opt} $IMAGE cat /etc/resolv.conf
864
    is "$output" ".*options ${dns_opt}" "--dns-opt was added"
865

866
    dns_opt=dns$(random_string)
867
    run_podman run --rm --dns-option=${dns_opt} $IMAGE cat /etc/resolv.conf
868
    is "$output" ".*options ${dns_opt}" "--dns-option was added"
869
}
870

871
@test "podman rootless netns works when XDG_RUNTIME_DIR includes symlinks" {
872
    # regression test for https://github.com/containers/podman/issues/14606
873
    is_rootless || skip "only meaningful for rootless"
874

875
    # Create a tmpdir symlink pointing to /run, and use it briefly
876
    ln -s /run $PODMAN_TMPDIR/run
877
    local tmp_run=$PODMAN_TMPDIR/run/user/$(id -u)
878
    test -d $tmp_run || skip "/run/user/MYUID unavailable"
879

880
    # This 'run' would previously fail with:
881
    #    IPAM error: failed to open database ....
882
    XDG_RUNTIME_DIR=$tmp_run run_podman run --network bridge --rm $IMAGE ip a
883
    assert "$output" =~ "eth0"
884
}
885

886
@test "podman inspect list networks " {
887
    run_podman create $IMAGE
888
    cid=${output}
889
    run_podman inspect --format '{{ .NetworkSettings.Networks }}' $cid
890
    if is_rootless; then
891
        is "$output" "map\[pasta:.*" "NeworkSettings should contain one network named pasta"
892
    else
893
        is "$output" "map\[podman:.*" "NeworkSettings should contain one network named podman"
894
    fi
895
    run_podman rm $cid
896

897
    for network in "host" "none"; do
898
        run_podman create --network=$network $IMAGE
899
        cid=${output}
900
        run_podman inspect --format '{{ .NetworkSettings.Networks }}' $cid
901
        is "$output" "map\[$network:.*" "NeworkSettings should contain one network named $network"
902
        run_podman inspect --format '{{ .NetworkSettings.SandboxKey }}' $cid
903
        assert "$output" == "" "SandboxKey for network=$network should be empty when not running"
904
        run_podman rm $cid
905
    done
906

907
    run_podman run -d --network=none $IMAGE top
908
    cid=${output}
909
    run_podman inspect --format '{{ .NetworkSettings.SandboxKey }}' $cid
910
    assert "$output" =~ "^/proc/[0-9]+/ns/net\$" "SandboxKey for network=none when running"
911
    run_podman rm -f -t0 $cid
912

913
    # Check with ns:/PATH
914
    if ! is_rootless; then
915
        netns=netns$(random_string)
916
        ip netns add $netns
917
        run_podman create --network=ns:/var/run/netns/$netns $IMAGE
918
        cid=${output}
919
        run_podman inspect --format '{{ .NetworkSettings.Networks }}' $cid
920
        is "$output" 'map[]' "NeworkSettings should be empty"
921
        run_podman rm $cid
922
     fi
923
}
924

925
# Test for https://github.com/containers/podman/issues/18615
926
@test "podman network cleanup --userns + --restart" {
927
    skip_if_cgroupsv1 "run --uidmap fails on cgroups v1 (issue 15025, wontfix)"
928

929
    local net1=a-$(random_string 10)
930
    # use /29 subnet to limit available ip space, a 29 gives 5 usable addresses (6 - 1 for the gw)
931
    local subnet="$(random_rfc1918_subnet).0/29"
932
    run_podman network create --subnet $subnet $net1
933
    local cname=con1-$(random_string 10)
934
    local cname2=
935
    local cname3=
936

937
    local netns_count=
938
    if ! is_rootless; then
939
        netns_count=$(ls /run/netns | wc -l)
940
    fi
941

942
    # This will cause 7 containers runs with the restart policy (one more than the on failure limit)
943
    # Since they run sequentially they should run fine without allocating all ips.
944
    run_podman 1 run --name $cname --network $net1 --restart on-failure:6 --userns keep-id $IMAGE false
945

946
    # Previously this would fail as the container would run out of ips after 5 restarts.
947
    run_podman inspect --format "{{.RestartCount}}" $cname
948
    assert "$output" == "6" "RestartCount for failing container with bridge network"
949

950
    # Now make sure we can still run a container with free ips.
951
    run_podman run --rm --network $net1 $IMAGE true
952

953
    # And now because of all the fun we have to check the same with slirp4netns and pasta because
954
    # that uses slightly different code paths. Note this would deadlock before the fix.
955
    # https://github.com/containers/podman/issues/21477
956
    if has_slirp4netns; then
957
        cname2=con2-$(random_string 10)
958
        run_podman 1 run --name $cname2 --network slirp4netns --restart on-failure:2 --userns keep-id $IMAGE false
959
        run_podman inspect --format "{{.RestartCount}}" $cname2
960
        assert "$output" == "2" "RestartCount for failing container with slirp4netns"
961
    fi
962

963
    if is_rootless; then
964
        # pasta can only run rootless
965
        cname3=con3-$(random_string 10)
966
        run_podman 1 run --name $cname3 --network pasta --restart on-failure:2 --userns keep-id $IMAGE false
967
        run_podman inspect --format "{{.RestartCount}}" $cname3
968
        assert "$output" == "2" "RestartCount for failing container with pasta"
969
    else
970
        # This is racy if other programs modify /run/netns while the test is running.
971
        # However I think the risk is minimal and I think checking for this is important.
972
        assert "$(ls /run/netns | wc -l)" == "$netns_count" "/run/netns has no leaked netns files"
973
    fi
974

975
    run_podman rm -f -t0 $cname $cname2 $cname3
976
    run_podman network rm $net1
977
}
978

979
# Issue #20448 - /etc/hostname with --uts=host must show "uname -n"
980
@test "podman --uts=host must use 'uname -n' for /etc/hostname" {
981
    run_podman info --format '{{.Host.Hostname}}'
982
    hostname="$output"
983
    run_podman run --rm --uts=host $IMAGE cat /etc/hostname
984
    assert "$output" = $hostname "/etc/hostname with --uts=host must be equal to 'uname -n'"
985

986
    run_podman run --rm --net=host --uts=host $IMAGE cat /etc/hostname
987
    assert "$output" = $hostname "/etc/hostname with --uts=host --net=host must be equal to 'uname -n'"
988
}
989

990
@test "podman network inspect running containers" {
991
    local cname1=c1-$(random_string 10)
992
    local cname2=c2-$(random_string 10)
993
    local cname3=c3-$(random_string 10)
994

995
    local netname=net-$(random_string 10)
996
    local subnet=$(random_rfc1918_subnet)
997

998
    run_podman network create --subnet "${subnet}.0/24" $netname
999

1000
    run_podman network inspect --format "{{json .Containers}}" $netname
1001
    assert "$output" == "{}" "no containers on the network"
1002

1003
    run_podman create --name $cname1 --network $netname $IMAGE top
1004
    cid1="$output"
1005
    run_podman create --name $cname2 --network $netname $IMAGE top
1006
    cid2="$output"
1007

1008
    # containers should only be part of the output when they are running
1009
    run_podman network inspect --format "{{json .Containers}}" $netname
1010
    assert "$output" == "{}" "no running containers on the network"
1011

1012
    # start the containers to setup the network info
1013
    run_podman start $cname1 $cname2
1014

1015
    # also run a third container on different network (should not be part of inspect then)
1016
    run_podman run -d --name $cname3 --network podman $IMAGE top
1017
    cid3="$output"
1018

1019
    # Map ordering is not deterministic so we check each container one by one
1020
    local expect="\{\"name\":\"$cname1\",\"interfaces\":\{\"eth0\":\{\"subnets\":\[\{\"ipnet\":\"${subnet}.2/24\"\,\"gateway\":\"${subnet}.1\"\}\],\"mac_address\":\"[0-9a-f]{2}:.*\"\}\}\}"
1021
    run_podman network inspect --format "{{json (index .Containers \"$cid1\")}}" $netname
1022
    assert "$output" =~ "$expect" "container 1 on the network"
1023

1024
    local expect="\{\"name\":\"$cname2\",\"interfaces\":\{\"eth0\":\{\"subnets\":\[\{\"ipnet\":\"${subnet}.3/24\"\,\"gateway\":\"${subnet}.1\"\}\],\"mac_address\":\"[0-9a-f]{2}:.*\"\}\}\}"
1025
    run_podman network inspect --format "{{json (index .Containers \"$cid2\")}}" $netname
1026
    assert "$output" =~ "$expect" "container 2 on the network"
1027

1028
    # container 3 should not be part of the inspect, index does not error if the key does not
1029
    # exists so just make sure the cid3 and cname3 are not in the json.
1030
    run_podman network inspect --format "{{json .Containers}}" $netname
1031
    assert "$output" !~ "$cid3" "container 3 on the network (cid)"
1032
    assert "$output" !~ "$cname3" "container 3 on the network (name)"
1033

1034
    run_podman rm -f -t0 $cname1 $cname2 $cname3
1035
    run_podman network rm $netname
1036
}
1037

1038
# vim: filetype=sh
1039

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.