github.com/nginxinc/kubernetes-ingress@v1.12.5/tests/suite/test_prometheus_metrics.py (about) 1 import pytest 2 import requests 3 4 from kubernetes.client import V1ContainerPort 5 6 from suite.resources_utils import ( 7 ensure_connection_to_public_endpoint, 8 create_items_from_yaml, 9 create_example_app, 10 delete_common_app, 11 delete_items_from_yaml, 12 wait_until_all_pods_are_ready, 13 ensure_response_from_backend, 14 wait_before_test, 15 wait_until_all_pods_are_ready, 16 ensure_connection, 17 delete_secret, 18 create_secret_from_yaml, 19 ) 20 from suite.yaml_utils import get_first_ingress_host_from_yaml 21 from settings import TEST_DATA 22 23 24 class IngressSetup: 25 """ 26 Encapsulate the Smoke Example details. 27 28 Attributes: 29 public_endpoint (PublicEndpoint): 30 ingress_host (str): 31 """ 32 33 def __init__(self, req_url, ingress_host): 34 self.req_url = req_url 35 self.ingress_host = ingress_host 36 37 38 @pytest.fixture(scope="class") 39 def prometheus_secret_setup(request, kube_apis, test_namespace): 40 print("------------------------- Deploy Prometheus Secret -----------------------------------") 41 prometheus_secret_name = create_secret_from_yaml( 42 kube_apis.v1, "nginx-ingress", f"{TEST_DATA}/prometheus/secret.yaml" 43 ) 44 45 def fin(): 46 delete_secret(kube_apis.v1, prometheus_secret_name, "nginx-ingress") 47 48 request.addfinalizer(fin) 49 50 51 @pytest.fixture(scope="class") 52 def enable_exporter_port( 53 cli_arguments, kube_apis, ingress_controller_prerequisites, ingress_controller 54 ) -> None: 55 """ 56 Set containerPort for Prometheus Exporter. 57 58 :param cli_arguments: context 59 :param kube_apis: client apis 60 :param ingress_controller_prerequisites 61 :param ingress_controller: IC name 62 :return: 63 """ 64 namespace = ingress_controller_prerequisites.namespace 65 port = V1ContainerPort(9113, None, None, "prometheus", "TCP") 66 print("------------------------- Enable 9113 port in IC -----------------------------------") 67 body = kube_apis.apps_v1_api.read_namespaced_deployment(ingress_controller, namespace) 68 body.spec.template.spec.containers[0].ports.append(port) 69 70 if cli_arguments["deployment-type"] == "deployment": 71 kube_apis.apps_v1_api.patch_namespaced_deployment(ingress_controller, namespace, body) 72 else: 73 kube_apis.apps_v1_api.patch_namespaced_daemon_set(ingress_controller, namespace, body) 74 wait_until_all_pods_are_ready(kube_apis.v1, namespace) 75 76 77 @pytest.fixture(scope="class") 78 def ingress_setup(request, kube_apis, ingress_controller_endpoint, test_namespace) -> IngressSetup: 79 print("------------------------- Deploy Ingress Example -----------------------------------") 80 secret_name = create_secret_from_yaml( 81 kube_apis.v1, test_namespace, f"{TEST_DATA}/smoke/smoke-secret.yaml" 82 ) 83 create_items_from_yaml( 84 kube_apis, f"{TEST_DATA}/smoke/standard/smoke-ingress.yaml", test_namespace 85 ) 86 ingress_host = get_first_ingress_host_from_yaml( 87 f"{TEST_DATA}/smoke/standard/smoke-ingress.yaml" 88 ) 89 create_example_app(kube_apis, "simple", test_namespace) 90 wait_until_all_pods_are_ready(kube_apis.v1, test_namespace) 91 ensure_connection_to_public_endpoint( 92 ingress_controller_endpoint.public_ip, 93 ingress_controller_endpoint.port, 94 ingress_controller_endpoint.port_ssl, 95 ) 96 req_url = f"https://{ingress_controller_endpoint.public_ip}:{ingress_controller_endpoint.port_ssl}/backend1" 97 98 def fin(): 99 print("Clean up simple app") 100 delete_common_app(kube_apis, "simple", test_namespace) 101 delete_items_from_yaml( 102 kube_apis, f"{TEST_DATA}/smoke/standard/smoke-ingress.yaml", test_namespace 103 ) 104 delete_secret(kube_apis.v1, secret_name, test_namespace) 105 106 request.addfinalizer(fin) 107 108 return IngressSetup(req_url, ingress_host) 109 110 111 @pytest.mark.ingresses 112 @pytest.mark.smoke 113 class TestPrometheusExporter: 114 @pytest.mark.parametrize( 115 "ingress_controller, expected_metrics", 116 [ 117 pytest.param( 118 {"extra_args": ["-enable-prometheus-metrics"]}, 119 [ 120 'nginx_ingress_controller_nginx_reload_errors_total{class="nginx"} 0', 121 'nginx_ingress_controller_ingress_resources_total{class="nginx",type="master"} 0', 122 'nginx_ingress_controller_ingress_resources_total{class="nginx",type="minion"} 0', 123 'nginx_ingress_controller_ingress_resources_total{class="nginx",type="regular"} 1', 124 "nginx_ingress_controller_nginx_last_reload_milliseconds", 125 'nginx_ingress_controller_nginx_last_reload_status{class="nginx"} 1', 126 'nginx_ingress_controller_nginx_reload_errors_total{class="nginx"} 0', 127 'nginx_ingress_controller_nginx_reloads_total{class="nginx",reason="endpoints"}', 128 'nginx_ingress_controller_nginx_reloads_total{class="nginx",reason="other"}', 129 'nginx_ingress_controller_workqueue_depth{class="nginx",name="taskQueue"}', 130 'nginx_ingress_controller_workqueue_queue_duration_seconds_bucket{class="nginx",name="taskQueue",le=', 131 'nginx_ingress_controller_workqueue_queue_duration_seconds_sum{class="nginx",name="taskQueue"}', 132 'nginx_ingress_controller_workqueue_queue_duration_seconds_count{class="nginx",name="taskQueue"}', 133 ], 134 ) 135 ], 136 indirect=["ingress_controller"], 137 ) 138 def test_metrics( 139 self, 140 ingress_controller_endpoint, 141 ingress_controller, 142 enable_exporter_port, 143 expected_metrics, 144 ingress_setup, 145 ): 146 resp = requests.get(ingress_setup.req_url, headers={"host": ingress_setup.ingress_host}, verify=False) 147 assert resp.status_code == 200 148 req_url = f"http://{ingress_controller_endpoint.public_ip}:{ingress_controller_endpoint.metrics_port}/metrics" 149 ensure_connection(req_url, 200) 150 resp = requests.get(req_url) 151 assert resp.status_code == 200, f"Expected 200 code for /metrics but got {resp.status_code}" 152 resp_content = resp.content.decode("utf-8") 153 for item in expected_metrics: 154 assert item in resp_content 155 156 @pytest.mark.parametrize( 157 "ingress_controller, expected_metrics", 158 [ 159 pytest.param( 160 {"extra_args": ["-enable-prometheus-metrics", "-enable-latency-metrics"]}, 161 [ 162 'nginx_ingress_controller_upstream_server_response_latency_ms_bucket{class="nginx",code="200",pod_name=', 163 'nginx_ingress_controller_upstream_server_response_latency_ms_sum{class="nginx",code="200",pod_name=', 164 'nginx_ingress_controller_upstream_server_response_latency_ms_count{class="nginx",code="200",pod_name=', 165 'nginx_ingress_controller_ingress_resources_total{class="nginx",type="regular"} 1', 166 ], 167 ) 168 ], 169 indirect=["ingress_controller"], 170 ) 171 def test_latency_metrics( 172 self, 173 ingress_controller_endpoint, 174 ingress_controller, 175 enable_exporter_port, 176 expected_metrics, 177 ingress_setup, 178 ): 179 resp = requests.get(ingress_setup.req_url, headers={"host": ingress_setup.ingress_host}, verify=False) 180 assert resp.status_code == 200 181 req_url = f"http://{ingress_controller_endpoint.public_ip}:{ingress_controller_endpoint.metrics_port}/metrics" 182 ensure_connection(req_url, 200) 183 resp = requests.get(req_url) 184 assert resp.status_code == 200, f"Expected 200 code for /metrics but got {resp.status_code}" 185 resp_content = resp.content.decode("utf-8") 186 for item in expected_metrics: 187 assert item in resp_content 188 189 @pytest.mark.parametrize( 190 "ingress_controller, expected_metrics", 191 [ 192 pytest.param( 193 {"extra_args": ["-enable-prometheus-metrics", "-enable-latency-metrics", "-prometheus-tls-secret=nginx-ingress/prometheus-test-secret"]}, 194 [ 195 'nginx_ingress_controller_ingress_resources_total{class="nginx",type="master"} 0', 196 'nginx_ingress_controller_ingress_resources_total{class="nginx",type="minion"} 0', 197 ], 198 ) 199 ], 200 indirect=["ingress_controller"], 201 ) 202 def test_https_metrics( 203 self, 204 prometheus_secret_setup, 205 ingress_controller_endpoint, 206 ingress_controller, 207 enable_exporter_port, 208 expected_metrics, 209 ingress_setup, 210 ): 211 resp = {} 212 213 # assert http fails 214 req_url = f"http://{ingress_controller_endpoint.public_ip}:{ingress_controller_endpoint.metrics_port}/metrics" 215 try: 216 resp = requests.get(req_url, verify=False) 217 assert False, "Expected HTTP request to fail for a HTTPS endpoint but it succeeded" 218 except: 219 print("request fails as expected") 220 221 assert resp.status_code == 400, f"Expected 400 code for http request to /metrics but got {resp.status_code}" 222 223 # assert https succeeds 224 req_url = f"https://{ingress_controller_endpoint.public_ip}:{ingress_controller_endpoint.metrics_port}/metrics" 225 ensure_response_from_backend(req_url, ingress_setup.ingress_host) 226 resp = requests.get(req_url, verify=False) 227 228 assert resp.status_code == 200, f"Expected 200 code for /metrics but got {resp.status_code}" 229 230 resp_content = resp.content.decode("utf-8") 231 for item in expected_metrics: 232 assert item in resp_content