Skip to content

Commit 006976e

Browse files
committed
Merge remote-tracking branch 'origin/main' into prometheus-alerts
2 parents 6ef9be8 + 2ee16b2 commit 006976e

File tree

5 files changed

+157
-1
lines changed

5 files changed

+157
-1
lines changed

requirements.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
grafana-client==4.1.*
22
opensearch-py==2.5.*
3+
packaging==24.*
34
prometheus-api-client==0.5.*
45
pylint==3.3.*
6+
pytest-subtests==0.12.*
57
pytest-testinfra==10.1.*
68
requests==2.31.*
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Copyright (c) 2024 StackHPC Ltd.
2+
3+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
4+
# not use this file except in compliance with the License. You may obtain
5+
# a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12+
# License for the specific language governing permissions and limitations
13+
# under the License.
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
# Copyright (c) 2024 StackHPC Ltd.
2+
3+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
4+
# not use this file except in compliance with the License. You may obtain
5+
# a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12+
# License for the specific language governing permissions and limitations
13+
# under the License.
14+
15+
import json
16+
import os
17+
from packaging.version import parse
18+
import pytest
19+
20+
21+
@pytest.fixture
22+
def docker_info(host, scope="session"):
23+
"""Pytest fixture that provides the output of 'docker info'."""
24+
with host.sudo("stack"):
25+
docker_info = host.check_output("docker info --format json")
26+
return json.loads(docker_info)
27+
28+
29+
def test_docker_version(host):
30+
"""Check that Docker is accessible and optionally check version."""
31+
# An optional inclusive minimum version.
32+
min_version = os.environ.get("DOCKER_VERSION_MIN")
33+
# An optional exclusive maximum version.
34+
max_version = os.environ.get("DOCKER_VERSION_MAX")
35+
with host.sudo("stack"):
36+
client_version = parse(host.docker.client_version())
37+
server_version = parse(host.docker.server_version())
38+
if min_version:
39+
min_version = parse(min_version)
40+
assert client_version >= min_version
41+
assert server_version >= min_version
42+
if max_version:
43+
max_version = parse(max_version)
44+
assert client_version < max_version
45+
assert server_version < max_version
46+
47+
48+
def test_docker_containers(subtests, host):
49+
"""Check that Docker containers are healthy."""
50+
with host.sudo("stack"):
51+
docker_containers = host.docker.get_containers()
52+
for container in docker_containers:
53+
# Use the subtests fixture to create a dynamically parametrised test
54+
# based on the containers on the system.
55+
with subtests.test(msg="container=" + container.name):
56+
state = container.inspect()["State"]
57+
assert state["Running"]
58+
assert not state["Restarting"]
59+
assert not state["Dead"]
60+
assert not state["OOMKilled"]
61+
if "Health" in state:
62+
assert state["Health"]["Status"] == "healthy"
63+
if "HostConfig" in state:
64+
assert state["HostConfig"]["LogConfig"]["Type"] == "json-file"
65+
assert "max-file" in state["HostConfig"]["LogConfig"]["Config"]
66+
assert "max-size" in state["HostConfig"]["LogConfig"]["Config"]
67+
68+
69+
def test_docker_driver(docker_info):
70+
"""Check that Docker is using the overlay2 storage driver."""
71+
assert docker_info["Driver"] == "overlay2"
72+
73+
74+
def test_no_bridge_network_exists(host):
75+
"""Check that no bridge network exists."""
76+
with host.sudo("stack"):
77+
docker_networks = host.check_output("docker network ls --format json")
78+
for network in docker_networks.splitlines():
79+
network = json.loads(network)
80+
assert network["Name"] != "bridge"
81+
assert network["Driver"] != "bridge"
82+
83+
84+
def test_ip_forwarding_disabled(docker_info):
85+
"""Check that IP forwarding is disabled."""
86+
assert not docker_info["IPv4Forwarding"]
87+
88+
89+
def test_iptables_disabled(host):
90+
"""Check that IPTables manipulation is disabled."""
91+
# (MaxN) "docker system info" for version 27.4.1 will report "true" for "BridgeNfIptables" and "BridgeNfIp6tables"
92+
# regardless of the setting of "iptables" in /etc/docker/daemon.json,
93+
# however correct creation of iptables rules will follow this setting - so test on the iptables rules instead.
94+
iptables_chains = host.check_output("iptables -L")
95+
assert "FORWARD" in iptables_chains
96+
assert "DOCKER" not in iptables_chains
97+
98+
def test_live_restore_enabled(docker_info):
99+
"""Check that live restore is enabled."""
100+
assert docker_info["LiveRestoreEnabled"]
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Copyright (c) 2024 StackHPC Ltd.
2+
3+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
4+
# not use this file except in compliance with the License. You may obtain
5+
# a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12+
# License for the specific language governing permissions and limitations
13+
# under the License.
14+
15+
import os
16+
import pytest
17+
18+
19+
def test_selinux(host):
20+
"""Check that SELinux is enabled and permissive on supported systems."""
21+
# Adapted from Kayobe host configure tests:
22+
# https://opendev.org/openstack/kayobe/src/commit/5333596afd6b93151e8e5a58257944b892d90060/playbooks/kayobe-overcloud-host-configure-base/tests/test_overcloud_host_configure.py#L350
23+
if host.system_info.distribution in {"debian", "ubuntu"}:
24+
pytest.skip(reason="SELinux is not supported on Debian or Ubuntu")
25+
# Desired state: enforcing, permissive or disabled
26+
expected_mode = os.environ["SELINUX_STATE"]
27+
assert expected_mode in {"enforcing", "permissive", "disabled"}
28+
expected_status = "disabled" if expected_mode == "disabled" else "enabled"
29+
selinux = host.check_output("sestatus")
30+
selinux = selinux.splitlines()
31+
# Remove duplicate whitespace characters in output
32+
selinux = [" ".join(x.split()) for x in selinux]
33+
34+
assert f"SELinux status: {expected_status}" in selinux
35+
if expected_status == "enabled":
36+
assert f"Current mode: {expected_mode}" in selinux
37+
assert f"Mode from config file: {expected_mode}" in selinux

stackhpc_cloud_tests/monitoring/test_opensearch.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,11 @@ def test_opensearch_dashboards_status():
6868
dashboard_username = os.environ["OPENSEARCH_DASHBOARDS_USERNAME"]
6969
dashboard_password = os.environ["OPENSEARCH_DASHBOARDS_PASSWORD"]
7070
dashboard_url += "/api/status"
71-
result = requests.get(dashboard_url, auth=(dashboard_username, dashboard_password))
71+
dashboard_cacert = os.environ.get("OPENSEARCH_DASHBOARDS_CACERT")
72+
kwargs = {}
73+
if dashboard_cacert:
74+
kwargs["verify"] = dashboard_cacert
75+
result = requests.get(dashboard_url, auth=(dashboard_username, dashboard_password), **kwargs)
7276
assert result.ok
7377
result = result.json()
7478
assert result["status"]["overall"]["state"] == "green"

0 commit comments

Comments
 (0)