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