Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CPDEV-95906] IPIP Encapsulation check #568

Merged
merged 38 commits into from
Feb 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
31315d6
ipip encap
alexarefev Dec 6, 2023
cd7826d
vxlan encap
alexarefev Dec 6, 2023
44bb89a
sequence; doc update
alexarefev Dec 7, 2023
687e751
doc update
alexarefev Dec 7, 2023
4a794ec
rework
alexarefev Dec 7, 2023
dc14cac
fix
alexarefev Dec 11, 2023
0f8ceb1
WA
alexarefev Dec 11, 2023
14b06d0
WA
alexarefev Dec 11, 2023
c5d3bcf
IPv6 exception
alexarefev Dec 12, 2023
4a250c2
IPv6 exception
alexarefev Dec 12, 2023
40da614
Network calculation
alexarefev Dec 17, 2023
a13cfac
2 nodes fix
alexarefev Dec 17, 2023
ceaa8cf
2 nodes fix
alexarefev Dec 17, 2023
cd2c2c3
nothing
alexarefev Dec 17, 2023
55cfa4d
fix
alexarefev Dec 17, 2023
99a622e
New approach
alexarefev Jan 22, 2024
63a2f43
timeout
alexarefev Jan 23, 2024
93550f1
binaries
alexarefev Jan 23, 2024
b47cc0c
less complex
alexarefev Jan 24, 2024
33894af
reduce complexity
alexarefev Jan 24, 2024
de6aec3
sources
alexarefev Jan 24, 2024
71baed0
New approach; transmitter code
alexarefev Jan 29, 2024
2bd66ba
New approach; receiver code
alexarefev Jan 30, 2024
ca2f2c0
randomizing
alexarefev Jan 30, 2024
b679857
ui
alexarefev Jan 31, 2024
6416c5a
ui
alexarefev Jan 31, 2024
f898274
get rid of binaries
alexarefev Jan 31, 2024
eb81795
get rid of binaries
alexarefev Feb 1, 2024
b8a613c
check binary
alexarefev Feb 1, 2024
a5c3ddb
build ipip_check binary
alexarefev Feb 2, 2024
922625d
multi-stage dockerfile; verbose help
alexarefev Feb 2, 2024
80c4e54
golang verion
alexarefev Feb 5, 2024
b51db53
minor changes
alexarefev Feb 5, 2024
93442bc
ipip_check CI
alexarefev Feb 6, 2024
fcb68d5
ipip_check CI#2
alexarefev Feb 6, 2024
cc73bb1
mypy
alexarefev Feb 7, 2024
e5d4f61
small fix
alexarefev Feb 7, 2024
f58460d
gzip
alexarefev Feb 13, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
FROM python:3.12-slim-bullseye
# syntax=docker/dockerfile:1

# Build ipip_check binary
FROM golang:1.21 AS go-build

alexarefev marked this conversation as resolved.
Show resolved Hide resolved
WORKDIR /opt

COPY ./kubemarine/resources/scripts/source/ipip_check ./

RUN go mod download && \
GOOS=linux CGO_ENABLED=1 go build -ldflags="-linkmode external -extldflags='-static'" -o ipip_check -buildvcs=false && \
gzip ipip_check

FROM python:3.12-slim-bullseye AS python-build

ARG BUILD_TYPE

Expand All @@ -8,6 +21,7 @@ ENV PYTHONUNBUFFERED 1
ENV ANSIBLE_HOST_KEY_CHECKING False

COPY . /opt/kubemarine/
COPY --from=go-build /opt/ipip_check.gz /opt/kubemarine/kubemarine/resources/scripts/
WORKDIR /opt/kubemarine/

RUN apt update && \
Expand Down
6 changes: 5 additions & 1 deletion documentation/Installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ The actual information about the supported versions can be found in `compatibili
* Opened TCP-ports:
* Internal communication:
* 22 : SSH
* 53 : CoreDNS (TCP & UDP), if access is needed from services bound to the host network.
* 53 : CoreDNS, if access is needed from services bound to the host network.
* 80 (or 20080, if balancers are presented): HTTP
* 179 : Calico BGP
* 443 (or 20443, if balancers are presented): HTTPS
Expand All @@ -201,6 +201,10 @@ The actual information about the supported versions can be found in `compatibili
* 80
* 443
* 6443 : Kubernetes API server, if necessary to access externally. For example, using the [helm](#helm) plugin.
* Opened UDP-ports:
* Internal communication:
* 53 : CoreDNS, if access is needed from services bound to the host network.
* 4789 : Calico VxLAN encapsulation, if that type of encapsulation is enabled
* Enabled additional protocols:
* **VRRP**: protocol is using by keepalived to manage vIP between nodes with role **balancer**. IP protocol number - 112
* **IPIP**: protocol is using for communication between kubernetes nodes of several clusters in Active-Active scheme only. Make shure **IPIP** protocol is added to all Security Groups in OpenStack and allowed on all intermediate network devices. IP protocol number - 4
Expand Down
7 changes: 7 additions & 0 deletions documentation/Kubecheck.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ This section provides information about the Kubecheck functionality.
- [010 ServiceSubnet](#010-servicesubnet)
- [011 TCP & UDP Ports](#011-tcp--udp-ports)
- [016 VRRP IPs](#016-vrrp-ips)
- [017 IP in IP Encapsulation](#017-ip-in-ip-encapsulation)
- [012 Thirdparties Availability](#012-thirdparties-availability)
- [013 Package Repositories](#013-package-repositories)
- [014 Package Availability](#014-package-availability)
Expand Down Expand Up @@ -323,6 +324,12 @@ This test checks the connectivity between nodes for the predefined set of ports

This test checks the connectivity between nodes and the VRRP IPs when they are assigned to the balancer nodes.

##### 017 IP in IP Encapsulation

*Task*: `network.ipip_connectivity`

This test checks the connectivity between nodes by IP in IP encapsulation.

##### 012 Thirdparties Availability

*Task*: `software.thirdparties.availability`
Expand Down
117 changes: 117 additions & 0 deletions kubemarine/procedures/check_iaas.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import re
import sys
import uuid
import string
from collections import OrderedDict
import time
from contextlib import contextmanager, nullcontext, AbstractContextManager
Expand Down Expand Up @@ -1240,6 +1241,121 @@ def vips_connectivity(cluster: KubernetesCluster) -> None:
tc.success(results='Connected')


def ipip_connectivity(cluster: KubernetesCluster) -> None:
with TestCase(cluster, '017', 'Network', 'IP in IP Encapsulation', default_results='Connected') as tc,\
suspend_firewalld(cluster):

skipped_msgs = nodes_require_python(cluster)
failed_nodes: Set[str] = set()

# Check encapsulation for 'Calico' CNI
if not cluster.inventory['plugins']['calico']['install']:
skipped_msgs.append("Calico is not set as CNI for the cluster")
raise TestWarn("Check cannot be completed", hint='\n'.join(skipped_msgs))

# Check encapsulation for clusters with two or more nodes
group = cluster.make_group_from_roles(['control-plane', 'worker'])
if group.nodes_amount() == 1:
koryaga marked this conversation as resolved.
Show resolved Hide resolved
skipped_msgs.append("Too few nodes, check is skipped")
raise TestWarn("Check cannot be completed", hint='\n'.join(skipped_msgs))

enc_type = cluster.inventory['plugins']['calico']['mode']
if enc_type == "ipip":
# Check if IPv6 addresses are used
connect_to_ip = group.get_ordered_members_configs_list()[0]['internal_address']
if type(ipaddress.ip_address(connect_to_ip)) is not ipaddress.IPv4Address:
skipped_msgs.append("IPv6 is not supported by IP in IP encapsulation")
raise TestWarn("Check cannot be completed", hint='\n'.join(skipped_msgs))
ip = cluster.inventory['services']['kubeadm']['networking']['podSubnet'].split('/')[0]
if type(ipaddress.ip_address(ip)) is not ipaddress.IPv4Address:
skipped_msgs.append("IPv6 is not supported by IP in IP encapsulation")
raise TestWarn("Check cannot be completed", hint='\n'.join(skipped_msgs))
failed_nodes = check_ipip_tunnel(group)
else:
skipped_msgs.append("Encapsulation IPIP is disabled")
raise TestWarn("Check cannot be completed", hint='\n'.join(skipped_msgs))

if failed_nodes:
raise TestFailure(f"Check firewall settings, IP in IP traffic is not allowed between nodes.",
hint='\n'.join(failed_nodes))


def check_ipip_tunnel(group: NodeGroup) -> Set[str]:

group_to_rollback = group
cluster = group.cluster

# Copy binaries to the nodes
random_port = str(random.randint(50000, 65535))
failed_nodes: Set[str] = set()
recv_cmd: Dict[str, str] = {}
trns_cmd: Dict[str, str] = {}

binary_check_path = utils.get_internal_resource_path('./resources/scripts/ipip_check.gz')
ipip_check = "/tmp/%s" % uuid.uuid4().hex
# Random message
random.seed()
msg = ''.join(random.choices(string.ascii_letters + string.digits, k=15))
# Random IP from class E
int_ip = random.randint(4026531841, 4294967294)
fake_addr = str(ipaddress.IPv4Address(int_ip))
# That is used as number of packets for transmitter
timeout = int(cluster.inventory['globals']['timeout_download'])
for node in group.get_ordered_members_configs_list():
host = node['internal_address']
# Transmitter start command
# Transmitter starts first and sends IPIP packets every 1 second until the timeout comes or
# the process is killed by terminating command
trns_item_cmd: List[str] = []
for node_item in group.get_ordered_members_configs_list():
if node_item['internal_address'] != host:
trns_item_cmd.append(f"nohup {ipip_check} -mode client -src {host} -int {fake_addr} "
f"-ext {node_item['internal_address']} -dport {random_port} "
f"-msg {msg} -timeout {timeout} > /dev/null 2>&1 & echo $! >> {ipip_check}.pid")
trns_cmd[host] = '& sudo '.join(trns_item_cmd)
# Receiver start command
# Receiver starts after the transmitter and try to get IPIP packets within 3 seconds from eache node
recv_cmd[host] = f"{ipip_check} -mode server -ext {host} -int {fake_addr} -dport {random_port} " \
f"-msg {msg} -timeout 3 2> /dev/null"

try:
collector = CollectorCallback(group.cluster)
cluster.log.debug("Copy binaries to the nodes")
group.put(binary_check_path, f"{ipip_check}.gz")
group.sudo(f"gzip -d {ipip_check}.gz")
group.sudo(f"sudo chmod +x {ipip_check}")
# Run transmitters
cluster.log.debug("Run transmitters")
with group.new_executor() as exe:
for node_exe in exe.group.get_ordered_members_list():
host_int = node_exe.get_config()['internal_address']
node_exe.sudo(f"{trns_cmd[host_int]}")
# Run receivers and get results
cluster.log.debug("Run receivers")
with group.new_executor() as exe:
for node_exe in exe.group.get_ordered_members_list():
host_int = node_exe.get_config()['internal_address']
node_exe.sudo(f"{recv_cmd[host_int]}", warn=True, callback=collector)

for host, item in collector.result.items():
node_name = cluster.get_node_name(host)
item_list: Set[str] = set()
if len(item.stdout) > 0:
for log_item in item.stdout.split("\n")[:-1]:
item_list.add(log_item)
for node in group.get_ordered_members_configs_list():
if node['internal_address'] not in item_list and node['connect_to'] != host:
failed_nodes.add(f"{node['name']} -> {node_name}")

return failed_nodes
finally:
# Delete binaries ang logs
cluster.log.debug("Delete binaries")
with group_to_rollback.new_executor() as exe:
for node_exe in exe.group.get_ordered_members_list():
node_exe.sudo(f"pkill -9 -P $(cat {ipip_check}.pid | xargs | tr ' ' ','); " \
f"sudo rm -f {ipip_check} {ipip_check}.pid", warn=True)

def make_reports(context: dict) -> None:
if not context['execution_arguments'].get('disable_csv_report', False):
context['testsuite'].save_csv(context['execution_arguments']['csv_report'], context['execution_arguments']['csv_report_delimiter'])
Expand All @@ -1262,6 +1378,7 @@ def make_reports(context: dict) -> None:
'service_subnet_connectivity': service_subnet_connectivity,
'ports_connectivity': ports_connectivity,
'vips_connectivity': vips_connectivity,
'ipip_connectivity': ipip_connectivity,
},
'hardware': {
'members_amount': {
Expand Down
5 changes: 5 additions & 0 deletions kubemarine/resources/scripts/source/ipip_check/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module ipip_check

go 1.19

require github.com/google/gopacket v1.1.19
14 changes: 14 additions & 0 deletions kubemarine/resources/scripts/source/ipip_check/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
Loading
Loading