github.com/nginxinc/kubernetes-ingress@v1.12.5/tests/suite/fixtures.py (about)

     1  """Describe project shared pytest fixtures."""
     2  
     3  import time
     4  import os, re
     5  import pytest
     6  import yaml
     7  import subprocess
     8  
     9  from kubernetes import config, client
    10  from kubernetes.client import (
    11      CoreV1Api,
    12      ExtensionsV1beta1Api,
    13      RbacAuthorizationV1Api,
    14      CustomObjectsApi,
    15      ApiextensionsV1Api,
    16      AppsV1Api,
    17  )
    18  from kubernetes.client.rest import ApiException
    19  
    20  from suite.custom_resources_utils import (
    21      create_virtual_server_from_yaml,
    22      delete_virtual_server,
    23      create_v_s_route_from_yaml,
    24      delete_v_s_route,
    25      create_crd_from_yaml,
    26      delete_crd,
    27      create_ts_from_yaml,
    28      create_gc_from_yaml,
    29      delete_ts,
    30      delete_gc,
    31  )
    32  from suite.kube_config_utils import ensure_context_in_config, get_current_context_name
    33  from suite.resources_utils import (
    34      create_namespace_with_name_from_yaml,
    35      delete_namespace,
    36      create_ns_and_sa_from_yaml,
    37      patch_rbac,
    38      create_example_app,
    39      wait_until_all_pods_are_ready,
    40      delete_common_app,
    41      ensure_connection_to_public_endpoint,
    42      create_service_with_name,
    43      create_deployment_with_name,
    44      delete_deployment,
    45      delete_service,
    46      replace_configmap_from_yaml,
    47      delete_testing_namespaces,
    48      get_first_pod_name,
    49  )
    50  from suite.resources_utils import (
    51      create_ingress_controller,
    52      delete_ingress_controller,
    53      configure_rbac,
    54      cleanup_rbac,
    55  )
    56  from suite.resources_utils import (
    57      create_service_from_yaml,
    58      get_service_node_ports,
    59      wait_for_public_ip,
    60  )
    61  from suite.resources_utils import (
    62      create_configmap_from_yaml,
    63      create_secret_from_yaml,
    64      configure_rbac_with_ap,
    65      create_items_from_yaml,
    66      delete_items_from_yaml,
    67  )
    68  from suite.yaml_utils import (
    69      get_first_host_from_yaml,
    70      get_paths_from_vs_yaml,
    71      get_paths_from_vsr_yaml,
    72      get_route_namespace_from_vs_yaml,
    73      get_name_from_yaml,
    74  )
    75  
    76  from settings import (
    77      ALLOWED_SERVICE_TYPES,
    78      ALLOWED_IC_TYPES,
    79      DEPLOYMENTS,
    80      TEST_DATA,
    81      ALLOWED_DEPLOYMENT_TYPES,
    82  )
    83  
    84  
    85  class KubeApis:
    86      """
    87      Encapsulate all the used kubernetes-client APIs.
    88  
    89      Attributes:
    90          v1: CoreV1Api
    91          extensions_v1_beta1: ExtensionsV1beta1Api
    92          rbac_v1: RbacAuthorizationV1Api
    93          api_extensions_v1: ApiextensionsV1Api
    94          custom_objects: CustomObjectsApi
    95      """
    96  
    97      def __init__(
    98          self,
    99          v1: CoreV1Api,
   100          extensions_v1_beta1: ExtensionsV1beta1Api,
   101          apps_v1_api: AppsV1Api,
   102          rbac_v1: RbacAuthorizationV1Api,
   103          api_extensions_v1: ApiextensionsV1Api,
   104          custom_objects: CustomObjectsApi,
   105      ):
   106          self.v1 = v1
   107          self.extensions_v1_beta1 = extensions_v1_beta1
   108          self.apps_v1_api = apps_v1_api
   109          self.rbac_v1 = rbac_v1
   110          self.api_extensions_v1 = api_extensions_v1
   111          self.custom_objects = custom_objects
   112  
   113  
   114  class PublicEndpoint:
   115      """
   116      Encapsulate the Public Endpoint info.
   117  
   118      Attributes:
   119          public_ip (str):
   120          port (int):
   121          port_ssl (int):
   122      """
   123  
   124      def __init__(self, public_ip, port=80, port_ssl=443, api_port=8080, metrics_port=9113, tcp_server_port=3333, udp_server_port=3334):
   125          self.public_ip = public_ip
   126          self.port = port
   127          self.port_ssl = port_ssl
   128          self.api_port = api_port
   129          self.metrics_port = metrics_port
   130          self.tcp_server_port = tcp_server_port
   131          self.udp_server_port = udp_server_port
   132  
   133  
   134  class IngressControllerPrerequisites:
   135      """
   136      Encapsulate shared items.
   137  
   138      Attributes:
   139          namespace (str): namespace name
   140          config_map (str): config_map name
   141          minorVer (int): k8s minor version
   142      """
   143  
   144      def __init__(self, config_map, namespace, minorVer):
   145          self.namespace = namespace
   146          self.config_map = config_map
   147          self.minorVer = minorVer
   148  
   149  
   150  @pytest.fixture(autouse=True)
   151  def print_name() -> None:
   152      """Print out a current test name."""
   153      test_name = f"{os.environ.get('PYTEST_CURRENT_TEST').split(':')[2]} :: {os.environ.get('PYTEST_CURRENT_TEST').split(':')[4].split(' ')[0]}"
   154      print(f"\n============================= {test_name} =============================")
   155  
   156  
   157  @pytest.fixture(scope="class")
   158  def test_namespace(kube_apis) -> str:
   159      """
   160      Create a test namespace.
   161  
   162      :param kube_apis: client apis
   163      :return: str
   164      """
   165      timestamp = round(time.time() * 1000)
   166      print("------------------------- Create Test Namespace -----------------------------------")
   167      namespace = create_namespace_with_name_from_yaml(
   168          kube_apis.v1, f"test-namespace-{str(timestamp)}", f"{TEST_DATA}/common/ns.yaml"
   169      )
   170      return namespace
   171  
   172  
   173  @pytest.fixture(scope="session", autouse=True)
   174  def delete_test_namespaces(kube_apis, request) -> None:
   175      """
   176      Delete all the testing namespaces.
   177  
   178      Testing namespaces are the ones starting with "test-namespace-"
   179  
   180      :param kube_apis: client apis
   181      :param request: pytest fixture
   182      :return: str
   183      """
   184  
   185      def fin():
   186          print(
   187              "------------------------- Delete All Test Namespaces -----------------------------------"
   188          )
   189          delete_testing_namespaces(kube_apis.v1)
   190  
   191      request.addfinalizer(fin)
   192  
   193  
   194  @pytest.fixture(scope="class")
   195  def ingress_controller(cli_arguments, kube_apis, ingress_controller_prerequisites, request) -> str:
   196      """
   197      Create Ingress Controller according to the context.
   198  
   199      :param cli_arguments: context
   200      :param kube_apis: client apis
   201      :param ingress_controller_prerequisites
   202      :param request: pytest fixture
   203      :return: IC name
   204      """
   205      namespace = ingress_controller_prerequisites.namespace
   206      name = "nginx-ingress"
   207      print("------------------------- Create IC without CRDs -----------------------------------")
   208      try:
   209          extra_args = request.param.get("extra_args", None)
   210          extra_args.append("-enable-custom-resources=false")
   211      except AttributeError:
   212          print("IC will start with CRDs disabled and without any additional cli-arguments")
   213          extra_args = ["-enable-custom-resources=false"]
   214      try:
   215          name = create_ingress_controller(
   216              kube_apis.v1, kube_apis.apps_v1_api, cli_arguments, namespace, extra_args
   217          )
   218      except ApiException as ex:
   219          # Finalizer doesn't start if fixture creation was incomplete, ensure clean up here
   220          print(f"Failed to complete IC fixture: {ex}\nClean up the cluster as much as possible.")
   221          delete_ingress_controller(
   222              kube_apis.apps_v1_api, name, cli_arguments["deployment-type"], namespace
   223          )
   224  
   225      def fin():
   226          print("Delete IC:")
   227          delete_ingress_controller(
   228              kube_apis.apps_v1_api, name, cli_arguments["deployment-type"], namespace
   229          )
   230  
   231      request.addfinalizer(fin)
   232  
   233      return name
   234  
   235  
   236  @pytest.fixture(scope="session")
   237  def ingress_controller_endpoint(
   238      cli_arguments, kube_apis, ingress_controller_prerequisites
   239  ) -> PublicEndpoint:
   240      """
   241      Create an entry point for the IC.
   242  
   243      :param cli_arguments: tests context
   244      :param kube_apis: client apis
   245      :param ingress_controller_prerequisites: common cluster context
   246      :return: PublicEndpoint
   247      """
   248      print("------------------------- Create Public Endpoint  -----------------------------------")
   249      namespace = ingress_controller_prerequisites.namespace
   250      if cli_arguments["service"] == "nodeport":
   251          public_ip = cli_arguments["node-ip"]
   252          print(f"The Public IP: {public_ip}")
   253          service_name = create_service_from_yaml(
   254              kube_apis.v1,
   255              namespace,
   256              f"{TEST_DATA}/common/service/nodeport-with-additional-ports.yaml",
   257          )
   258          port, port_ssl, api_port, metrics_port, tcp_server_port, udp_server_port = get_service_node_ports(
   259              kube_apis.v1, service_name, namespace
   260          )
   261          return PublicEndpoint(public_ip, port, port_ssl, api_port, metrics_port, tcp_server_port, udp_server_port)
   262      else:
   263          create_service_from_yaml(
   264              kube_apis.v1,
   265              namespace,
   266              f"{TEST_DATA}/common/service/loadbalancer-with-additional-ports.yaml",
   267          )
   268          public_ip = wait_for_public_ip(kube_apis.v1, namespace)
   269          print(f"The Public IP: {public_ip}")
   270          return PublicEndpoint(public_ip)
   271  
   272  
   273  @pytest.fixture(scope="session")
   274  def ingress_controller_prerequisites(
   275      cli_arguments, kube_apis, request
   276  ) -> IngressControllerPrerequisites:
   277      """
   278      Create RBAC, SA, IC namespace and default-secret.
   279  
   280      :param cli_arguments: tests context
   281      :param kube_apis: client apis
   282      :param request: pytest fixture
   283      :return: IngressControllerPrerequisites
   284      """
   285      print("------------------------- Create IC Prerequisites  -----------------------------------")
   286      rbac = configure_rbac(kube_apis.rbac_v1)
   287      namespace = create_ns_and_sa_from_yaml(kube_apis.v1, f"{DEPLOYMENTS}/common/ns-and-sa.yaml")
   288      k8sVersionBin = subprocess.run(["kubectl", "version"], capture_output=True)
   289      k8sVersion = (k8sVersionBin.stdout).decode("ascii")
   290      serverVersion = k8sVersion[k8sVersion.find("Server Version:") :].lstrip()
   291      minorSerVer = serverVersion[serverVersion.find("Minor") :].lstrip()[0:10]
   292      k8sMinorVersion = int("".join(filter(str.isdigit, minorSerVer)))
   293      if k8sMinorVersion >= 18:
   294          print("Create IngressClass resources:")
   295          subprocess.run(["kubectl", "apply", "-f", f"{DEPLOYMENTS}/common/ingress-class.yaml"])
   296          subprocess.run(
   297              [
   298                  "kubectl",
   299                  "apply",
   300                  "-f",
   301                  f"{TEST_DATA}/ingress-class/resource/custom-ingress-class-res.yaml",
   302              ]
   303          )
   304      config_map_yaml = f"{DEPLOYMENTS}/common/nginx-config.yaml"
   305      create_configmap_from_yaml(kube_apis.v1, namespace, config_map_yaml)
   306      with open(config_map_yaml) as f:
   307          config_map = yaml.safe_load(f)
   308      create_secret_from_yaml(
   309          kube_apis.v1, namespace, f"{DEPLOYMENTS}/common/default-server-secret.yaml"
   310      )
   311  
   312      def fin():
   313          print("Clean up prerequisites")
   314          delete_namespace(kube_apis.v1, namespace)
   315          if k8sMinorVersion >= 18:
   316              print("Delete IngressClass resources:")
   317              subprocess.run(["kubectl", "delete", "-f", f"{DEPLOYMENTS}/common/ingress-class.yaml"])
   318              subprocess.run(
   319                  [
   320                      "kubectl",
   321                      "delete",
   322                      "-f",
   323                      f"{TEST_DATA}/ingress-class/resource/custom-ingress-class-res.yaml",
   324                  ]
   325              )
   326          cleanup_rbac(kube_apis.rbac_v1, rbac)
   327  
   328      request.addfinalizer(fin)
   329  
   330      return IngressControllerPrerequisites(config_map, namespace, k8sMinorVersion)
   331  
   332  
   333  @pytest.fixture(scope="session")
   334  def kube_apis(cli_arguments) -> KubeApis:
   335      """
   336      Set up kubernets-client to operate in cluster.
   337  
   338      :param cli_arguments: a set of command-line arguments
   339      :return: KubeApis
   340      """
   341      context_name = cli_arguments["context"]
   342      kubeconfig = cli_arguments["kubeconfig"]
   343      config.load_kube_config(config_file=kubeconfig, context=context_name, persist_config=False)
   344      v1 = client.CoreV1Api()
   345      extensions_v1_beta1 = client.ExtensionsV1beta1Api()
   346      apps_v1_api = client.AppsV1Api()
   347      rbac_v1 = client.RbacAuthorizationV1Api()
   348      api_extensions_v1 = client.ApiextensionsV1Api()
   349      custom_objects = client.CustomObjectsApi()
   350      return KubeApis(
   351          v1, extensions_v1_beta1, apps_v1_api, rbac_v1, api_extensions_v1, custom_objects
   352      )
   353  
   354  
   355  @pytest.fixture(scope="session", autouse=True)
   356  def cli_arguments(request) -> {}:
   357      """
   358      Verify the CLI arguments.
   359  
   360      :param request: pytest fixture
   361      :return: {context, image, image-pull-policy, deployment-type, ic-type, service, node-ip, kubeconfig}
   362      """
   363      result = {"kubeconfig": request.config.getoption("--kubeconfig")}
   364      assert result["kubeconfig"] != "", "Empty kubeconfig is not allowed"
   365      print(f"\nTests will use this kubeconfig: {result['kubeconfig']}")
   366  
   367      result["context"] = request.config.getoption("--context")
   368      if result["context"] != "":
   369          ensure_context_in_config(result["kubeconfig"], result["context"])
   370          print(f"Tests will run against: {result['context']}")
   371      else:
   372          result["context"] = get_current_context_name(result["kubeconfig"])
   373          print(f"Tests will use a current context: {result['context']}")
   374  
   375      result["image"] = request.config.getoption("--image")
   376      assert result["image"] != "", "Empty image is not allowed"
   377      print(f"Tests will use the image: {result['image']}")
   378  
   379      result["image-pull-policy"] = request.config.getoption("--image-pull-policy")
   380      assert result["image-pull-policy"] != "", "Empty image-pull-policy is not allowed"
   381      print(f"Tests will run with the image-pull-policy: {result['image-pull-policy']}")
   382  
   383      result["deployment-type"] = request.config.getoption("--deployment-type")
   384      assert (
   385          result["deployment-type"] in ALLOWED_DEPLOYMENT_TYPES
   386      ), f"Deployment type {result['deployment-type']} is not allowed"
   387      print(f"Tests will use the IC deployment of type: {result['deployment-type']}")
   388  
   389      result["ic-type"] = request.config.getoption("--ic-type")
   390      assert result["ic-type"] in ALLOWED_IC_TYPES, f"IC type {result['ic-type']} is not allowed"
   391      print(f"Tests will run against the IC of type: {result['ic-type']}")
   392  
   393      result["service"] = request.config.getoption("--service")
   394      assert result["service"] in ALLOWED_SERVICE_TYPES, f"Service {result['service']} is not allowed"
   395      print(f"Tests will use Service of this type: {result['service']}")
   396      if result["service"] == "nodeport":
   397          node_ip = request.config.getoption("--node-ip", None)
   398          assert node_ip is not None and node_ip != "", f"Service 'nodeport' requires a node-ip"
   399          result["node-ip"] = node_ip
   400          print(f"Tests will use the node-ip: {result['node-ip']}")
   401      return result
   402  
   403  
   404  @pytest.fixture(scope="class")
   405  def crd_ingress_controller(
   406      cli_arguments, kube_apis, ingress_controller_prerequisites, ingress_controller_endpoint, request
   407  ) -> None:
   408      """
   409      Create an Ingress Controller with CRD enabled.
   410  
   411      :param cli_arguments: pytest context
   412      :param kube_apis: client apis
   413      :param ingress_controller_prerequisites
   414      :param ingress_controller_endpoint:
   415      :param request: pytest fixture to parametrize this method
   416          {type: complete|rbac-without-vs, extra_args: }
   417          'type' type of test pre-configuration
   418          'extra_args' list of IC cli arguments
   419      :return:
   420      """
   421      namespace = ingress_controller_prerequisites.namespace
   422      name = "nginx-ingress"
   423      vs_crd_name = get_name_from_yaml(f"{DEPLOYMENTS}/common/crds/k8s.nginx.org_virtualservers.yaml")
   424      vsr_crd_name = get_name_from_yaml(
   425          f"{DEPLOYMENTS}/common/crds/k8s.nginx.org_virtualserverroutes.yaml"
   426      )
   427      pol_crd_name = get_name_from_yaml(f"{DEPLOYMENTS}/common/crds/k8s.nginx.org_policies.yaml")
   428      ts_crd_name = get_name_from_yaml(
   429          f"{DEPLOYMENTS}/common/crds/k8s.nginx.org_transportservers.yaml"
   430      )
   431      gc_crd_name = get_name_from_yaml(
   432          f"{DEPLOYMENTS}/common/crds/k8s.nginx.org_globalconfigurations.yaml"
   433      )
   434  
   435      try:
   436          print("------------------------- Update ClusterRole -----------------------------------")
   437          if request.param["type"] == "rbac-without-vs":
   438              patch_rbac(kube_apis.rbac_v1, f"{TEST_DATA}/virtual-server/rbac-without-vs.yaml")
   439          print("------------------------- Register CRDs -----------------------------------")
   440          create_crd_from_yaml(
   441              kube_apis.api_extensions_v1,
   442              vs_crd_name,
   443              f"{DEPLOYMENTS}/common/crds/k8s.nginx.org_virtualservers.yaml",
   444          )
   445          create_crd_from_yaml(
   446              kube_apis.api_extensions_v1,
   447              vsr_crd_name,
   448              f"{DEPLOYMENTS}/common/crds/k8s.nginx.org_virtualserverroutes.yaml",
   449          )
   450          create_crd_from_yaml(
   451              kube_apis.api_extensions_v1,
   452              pol_crd_name,
   453              f"{DEPLOYMENTS}/common/crds/k8s.nginx.org_policies.yaml",
   454          )
   455          create_crd_from_yaml(
   456              kube_apis.api_extensions_v1,
   457              ts_crd_name,
   458              f"{DEPLOYMENTS}/common/crds/k8s.nginx.org_transportservers.yaml",
   459          )
   460          create_crd_from_yaml(
   461              kube_apis.api_extensions_v1,
   462              gc_crd_name,
   463              f"{DEPLOYMENTS}/common/crds/k8s.nginx.org_globalconfigurations.yaml",
   464          )
   465          print("------------------------- Create IC -----------------------------------")
   466          name = create_ingress_controller(
   467              kube_apis.v1,
   468              kube_apis.apps_v1_api,
   469              cli_arguments,
   470              namespace,
   471              request.param.get("extra_args", None),
   472          )
   473          ensure_connection_to_public_endpoint(
   474              ingress_controller_endpoint.public_ip,
   475              ingress_controller_endpoint.port,
   476              ingress_controller_endpoint.port_ssl,
   477          )
   478      except ApiException as ex:
   479          # Finalizer method doesn't start if fixture creation was incomplete, ensure clean up here
   480          print(f"Failed to complete CRD IC fixture: {ex}\nClean up the cluster as much as possible.")
   481          delete_crd(kube_apis.api_extensions_v1, vs_crd_name)
   482          delete_crd(kube_apis.api_extensions_v1, vsr_crd_name)
   483          delete_crd(kube_apis.api_extensions_v1, pol_crd_name)
   484          delete_crd(kube_apis.api_extensions_v1, ts_crd_name)
   485          delete_crd(kube_apis.api_extensions_v1, gc_crd_name)
   486          print("Restore the ClusterRole:")
   487          patch_rbac(kube_apis.rbac_v1, f"{DEPLOYMENTS}/rbac/rbac.yaml")
   488          print("Remove the IC:")
   489          delete_ingress_controller(
   490              kube_apis.apps_v1_api, name, cli_arguments["deployment-type"], namespace
   491          )
   492  
   493      def fin():
   494          delete_crd(kube_apis.api_extensions_v1, vs_crd_name)
   495          delete_crd(kube_apis.api_extensions_v1, vsr_crd_name)
   496          delete_crd(kube_apis.api_extensions_v1, pol_crd_name)
   497          delete_crd(kube_apis.api_extensions_v1, ts_crd_name)
   498          delete_crd(kube_apis.api_extensions_v1, gc_crd_name)
   499          print("Restore the ClusterRole:")
   500          patch_rbac(kube_apis.rbac_v1, f"{DEPLOYMENTS}/rbac/rbac.yaml")
   501          print("Remove the IC:")
   502          delete_ingress_controller(
   503              kube_apis.apps_v1_api, name, cli_arguments["deployment-type"], namespace
   504          )
   505  
   506      request.addfinalizer(fin)
   507  
   508  
   509  @pytest.fixture(scope="class")
   510  def crd_ingress_controller_with_ap(
   511      cli_arguments, kube_apis, ingress_controller_prerequisites, ingress_controller_endpoint, request
   512  ) -> None:
   513      """
   514      Create an Ingress Controller with AppProtect CRD enabled.
   515      :param cli_arguments: pytest context
   516      :param kube_apis: client apis
   517      :param ingress_controller_prerequisites
   518      :param ingress_controller_endpoint:
   519      :param request: pytest fixture to parametrize this method
   520          {extra_args: }
   521          'extra_args' list of IC arguments
   522      :return:
   523      """
   524      namespace = ingress_controller_prerequisites.namespace
   525      name = "nginx-ingress"
   526      try:
   527          print(
   528              "--------------------Create roles and bindings for AppProtect------------------------"
   529          )
   530          rbac = configure_rbac_with_ap(kube_apis.rbac_v1)
   531  
   532          print("------------------------- Register AP CRD -----------------------------------")
   533          ap_pol_crd_name = get_name_from_yaml(
   534              f"{DEPLOYMENTS}/common/crds/appprotect.f5.com_appolicies.yaml"
   535          )
   536          ap_log_crd_name = get_name_from_yaml(
   537              f"{DEPLOYMENTS}/common/crds/appprotect.f5.com_aplogconfs.yaml"
   538          )
   539          ap_uds_crd_name = get_name_from_yaml(
   540              f"{DEPLOYMENTS}/common/crds/appprotect.f5.com_apusersigs.yaml"
   541          )
   542          vs_crd_name = get_name_from_yaml(
   543              f"{DEPLOYMENTS}/common/crds/k8s.nginx.org_virtualservers.yaml"
   544          )
   545          vsr_crd_name = get_name_from_yaml(
   546              f"{DEPLOYMENTS}/common/crds/k8s.nginx.org_virtualserverroutes.yaml"
   547          )
   548          pol_crd_name = get_name_from_yaml(f"{DEPLOYMENTS}/common/crds/k8s.nginx.org_policies.yaml")
   549          ts_crd_name = get_name_from_yaml(
   550              f"{DEPLOYMENTS}/common/crds/k8s.nginx.org_transportservers.yaml"
   551          )
   552          create_crd_from_yaml(
   553              kube_apis.api_extensions_v1,
   554              ap_pol_crd_name,
   555              f"{DEPLOYMENTS}/common/crds/appprotect.f5.com_appolicies.yaml",
   556          )
   557          create_crd_from_yaml(
   558              kube_apis.api_extensions_v1,
   559              ap_log_crd_name,
   560              f"{DEPLOYMENTS}/common/crds/appprotect.f5.com_aplogconfs.yaml",
   561          )
   562          create_crd_from_yaml(
   563              kube_apis.api_extensions_v1,
   564              ap_uds_crd_name,
   565              f"{DEPLOYMENTS}/common/crds/appprotect.f5.com_apusersigs.yaml",
   566          )
   567          create_crd_from_yaml(
   568              kube_apis.api_extensions_v1,
   569              vs_crd_name,
   570              f"{DEPLOYMENTS}/common/crds/k8s.nginx.org_virtualservers.yaml",
   571          )
   572          create_crd_from_yaml(
   573              kube_apis.api_extensions_v1,
   574              vsr_crd_name,
   575              f"{DEPLOYMENTS}/common/crds/k8s.nginx.org_virtualserverroutes.yaml",
   576          )
   577          create_crd_from_yaml(
   578              kube_apis.api_extensions_v1,
   579              pol_crd_name,
   580              f"{DEPLOYMENTS}/common/crds/k8s.nginx.org_policies.yaml",
   581          )
   582          create_crd_from_yaml(
   583              kube_apis.api_extensions_v1,
   584              ts_crd_name,
   585              f"{DEPLOYMENTS}/common/crds/k8s.nginx.org_transportservers.yaml",
   586          )
   587  
   588          print("------------------------- Create IC -----------------------------------")
   589          name = create_ingress_controller(
   590              kube_apis.v1,
   591              kube_apis.apps_v1_api,
   592              cli_arguments,
   593              namespace,
   594              request.param.get("extra_args", None),
   595          )
   596          ensure_connection_to_public_endpoint(
   597              ingress_controller_endpoint.public_ip,
   598              ingress_controller_endpoint.port,
   599              ingress_controller_endpoint.port_ssl,
   600          )
   601      except Exception as ex:
   602          print(f"Failed to complete CRD IC fixture: {ex}\nClean up the cluster as much as possible.")
   603          delete_crd(
   604              kube_apis.api_extensions_v1,
   605              ap_pol_crd_name,
   606          )
   607          delete_crd(
   608              kube_apis.api_extensions_v1,
   609              ap_log_crd_name,
   610          )
   611          delete_crd(
   612              kube_apis.api_extensions_v1,
   613              ap_uds_crd_name,
   614          )
   615          delete_crd(
   616              kube_apis.api_extensions_v1,
   617              vs_crd_name,
   618          )
   619          delete_crd(
   620              kube_apis.api_extensions_v1,
   621              vsr_crd_name,
   622          )
   623          delete_crd(
   624              kube_apis.api_extensions_v1,
   625              pol_crd_name,
   626          )
   627          delete_crd(
   628              kube_apis.api_extensions_v1,
   629              ts_crd_name,
   630          )
   631          print("Remove ap-rbac")
   632          cleanup_rbac(kube_apis.rbac_v1, rbac)
   633          print("Remove the IC:")
   634          delete_ingress_controller(
   635              kube_apis.apps_v1_api, name, cli_arguments["deployment-type"], namespace
   636          )
   637  
   638      def fin():
   639          print("--------------Cleanup----------------")
   640          delete_crd(
   641              kube_apis.api_extensions_v1,
   642              ap_pol_crd_name,
   643          )
   644          delete_crd(
   645              kube_apis.api_extensions_v1,
   646              ap_log_crd_name,
   647          )
   648          delete_crd(
   649              kube_apis.api_extensions_v1,
   650              ap_uds_crd_name,
   651          )
   652          delete_crd(
   653              kube_apis.api_extensions_v1,
   654              vs_crd_name,
   655          )
   656          delete_crd(
   657              kube_apis.api_extensions_v1,
   658              vsr_crd_name,
   659          )
   660          delete_crd(
   661              kube_apis.api_extensions_v1,
   662              pol_crd_name,
   663          )
   664          delete_crd(
   665              kube_apis.api_extensions_v1,
   666              ts_crd_name,
   667          )
   668          print("Remove ap-rbac")
   669          cleanup_rbac(kube_apis.rbac_v1, rbac)
   670          print("Remove the IC:")
   671          delete_ingress_controller(
   672              kube_apis.apps_v1_api, name, cli_arguments["deployment-type"], namespace
   673          )
   674  
   675      request.addfinalizer(fin)
   676  
   677  
   678  class VirtualServerSetup:
   679      """
   680      Encapsulate  Virtual Server Example details.
   681  
   682      Attributes:
   683          public_endpoint (PublicEndpoint):
   684          namespace (str):
   685          vs_host (str):
   686          vs_name (str):
   687          backend_1_url (str):
   688          backend_2_url (str):
   689      """
   690  
   691      def __init__(self, public_endpoint: PublicEndpoint, namespace, vs_host, vs_name, vs_paths):
   692          self.public_endpoint = public_endpoint
   693          self.namespace = namespace
   694          self.vs_host = vs_host
   695          self.vs_name = vs_name
   696          self.backend_1_url = (
   697              f"http://{public_endpoint.public_ip}:{public_endpoint.port}{vs_paths[0]}"
   698          )
   699          self.backend_2_url = (
   700              f"http://{public_endpoint.public_ip}:{public_endpoint.port}{vs_paths[1]}"
   701          )
   702          self.backend_1_url_ssl = (
   703              f"https://{public_endpoint.public_ip}:{public_endpoint.port_ssl}{vs_paths[0]}"
   704          )
   705          self.backend_2_url_ssl = (
   706              f"https://{public_endpoint.public_ip}:{public_endpoint.port_ssl}{vs_paths[1]}"
   707          )
   708  
   709  
   710  @pytest.fixture(scope="class")
   711  def virtual_server_setup(
   712      request, kube_apis, ingress_controller_endpoint, test_namespace
   713  ) -> VirtualServerSetup:
   714      """
   715      Prepare Virtual Server Example.
   716  
   717      :param request: internal pytest fixture to parametrize this method:
   718          {example: virtual-server|virtual-server-tls|..., app_type: simple|split|...}
   719          'example' is a directory name in TEST_DATA,
   720          'app_type' is a directory name in TEST_DATA/common/app
   721      :param kube_apis: client apis
   722      :param crd_ingress_controller:
   723      :param ingress_controller_endpoint:
   724      :param test_namespace:
   725      :return: VirtualServerSetup
   726      """
   727      print(
   728          "------------------------- Deploy Virtual Server Example -----------------------------------"
   729      )
   730      vs_source = f"{TEST_DATA}/{request.param['example']}/standard/virtual-server.yaml"
   731      vs_name = create_virtual_server_from_yaml(kube_apis.custom_objects, vs_source, test_namespace)
   732      vs_host = get_first_host_from_yaml(vs_source)
   733      vs_paths = get_paths_from_vs_yaml(vs_source)
   734      if request.param["app_type"]:
   735          create_example_app(kube_apis, request.param["app_type"], test_namespace)
   736          wait_until_all_pods_are_ready(kube_apis.v1, test_namespace)
   737  
   738      def fin():
   739          print("Clean up Virtual Server Example:")
   740          delete_virtual_server(kube_apis.custom_objects, vs_name, test_namespace)
   741          if request.param["app_type"]:
   742              delete_common_app(kube_apis, request.param["app_type"], test_namespace)
   743  
   744      request.addfinalizer(fin)
   745  
   746      return VirtualServerSetup(
   747          ingress_controller_endpoint, test_namespace, vs_host, vs_name, vs_paths
   748      )
   749  
   750  
   751  class TransportServerSetup:
   752      """
   753      Encapsulate Transport Server Example details.
   754  
   755      Attributes:
   756          name (str):
   757          namespace (str):
   758      """
   759  
   760      def __init__(self, name, namespace, ingress_pod_name, ic_namespace, public_endpoint: PublicEndpoint, resource):
   761          self.name = name
   762          self.namespace = namespace
   763          self.ingress_pod_name = ingress_pod_name
   764          self.ic_namespace = ic_namespace
   765          self.public_endpoint = public_endpoint
   766          self.resource = resource
   767  
   768  
   769  @pytest.fixture(scope="class")
   770  def transport_server_setup(
   771          request, kube_apis, ingress_controller_prerequisites, test_namespace, ingress_controller_endpoint
   772  ) -> TransportServerSetup:
   773      """
   774      Prepare Transport Server Example.
   775  
   776      :param ingress_controller_endpoint:
   777      :param ingress_controller_prerequisites:
   778      :param request: internal pytest fixture to parametrize this method
   779      :param kube_apis: client apis
   780      :param test_namespace:
   781      :return: TransportServerSetup
   782      """
   783      print(
   784          "------------------------- Deploy Transport Server Example -----------------------------------"
   785      )
   786  
   787      # deploy global config
   788      global_config_file = (
   789          f"{TEST_DATA}/{request.param['example']}/standard/global-configuration.yaml"
   790      )
   791      gc_resource = create_gc_from_yaml(kube_apis.custom_objects, global_config_file, "nginx-ingress")
   792  
   793      # deploy service_file
   794      service_file = f"{TEST_DATA}/{request.param['example']}/standard/service_deployment.yaml"
   795      create_items_from_yaml(kube_apis, service_file, test_namespace)
   796  
   797      # deploy transport server
   798      transport_server_file = f"{TEST_DATA}/{request.param['example']}/standard/transport-server.yaml"
   799      ts_resource = create_ts_from_yaml(
   800          kube_apis.custom_objects, transport_server_file, test_namespace
   801      )
   802  
   803      wait_until_all_pods_are_ready(kube_apis.v1, test_namespace)
   804  
   805      def fin():
   806          print("Clean up TransportServer Example:")
   807          delete_ts(kube_apis.custom_objects, ts_resource, test_namespace)
   808          delete_items_from_yaml(kube_apis, service_file, test_namespace)
   809          delete_gc(kube_apis.custom_objects, gc_resource, "nginx-ingress")
   810  
   811      request.addfinalizer(fin)
   812  
   813      ic_pod_name = get_first_pod_name(kube_apis.v1, ingress_controller_prerequisites.namespace)
   814      ic_namespace = ingress_controller_prerequisites.namespace
   815  
   816      return TransportServerSetup(
   817          ts_resource['metadata']['name'],
   818          test_namespace,
   819          ic_pod_name,
   820          ic_namespace,
   821          ingress_controller_endpoint,
   822          ts_resource,
   823      )
   824  
   825  
   826  @pytest.fixture(scope="class")
   827  def v_s_route_app_setup(request, kube_apis, v_s_route_setup) -> None:
   828      """
   829      Prepare an example app for Virtual Server Route.
   830  
   831      1st namespace with backend1-svc and backend3-svc and deployment and 2nd namespace with backend2-svc and deployment.
   832  
   833      :param request: internal pytest fixture
   834      :param kube_apis: client apis
   835      :param v_s_route_setup:
   836      :return:
   837      """
   838      print(
   839          "---------------------- Deploy a VS Route Example Application ----------------------------"
   840      )
   841      svc_one = create_service_with_name(
   842          kube_apis.v1, v_s_route_setup.route_m.namespace, "backend1-svc"
   843      )
   844      svc_three = create_service_with_name(
   845          kube_apis.v1, v_s_route_setup.route_m.namespace, "backend3-svc"
   846      )
   847      deployment_one = create_deployment_with_name(
   848          kube_apis.apps_v1_api, v_s_route_setup.route_m.namespace, "backend1"
   849      )
   850      deployment_three = create_deployment_with_name(
   851          kube_apis.apps_v1_api, v_s_route_setup.route_m.namespace, "backend3"
   852      )
   853  
   854      svc_two = create_service_with_name(
   855          kube_apis.v1, v_s_route_setup.route_s.namespace, "backend2-svc"
   856      )
   857      deployment_two = create_deployment_with_name(
   858          kube_apis.apps_v1_api, v_s_route_setup.route_s.namespace, "backend2"
   859      )
   860  
   861      wait_until_all_pods_are_ready(kube_apis.v1, v_s_route_setup.route_m.namespace)
   862      wait_until_all_pods_are_ready(kube_apis.v1, v_s_route_setup.route_s.namespace)
   863  
   864      def fin():
   865          print("Clean up the Application:")
   866          delete_deployment(kube_apis.apps_v1_api, deployment_one, v_s_route_setup.route_m.namespace)
   867          delete_service(kube_apis.v1, svc_one, v_s_route_setup.route_m.namespace)
   868          delete_deployment(
   869              kube_apis.apps_v1_api, deployment_three, v_s_route_setup.route_m.namespace
   870          )
   871          delete_service(kube_apis.v1, svc_three, v_s_route_setup.route_m.namespace)
   872          delete_deployment(kube_apis.apps_v1_api, deployment_two, v_s_route_setup.route_s.namespace)
   873          delete_service(kube_apis.v1, svc_two, v_s_route_setup.route_s.namespace)
   874  
   875      request.addfinalizer(fin)
   876  
   877  
   878  class VirtualServerRoute:
   879      """
   880      Encapsulate  Virtual Server Route details.
   881  
   882      Attributes:
   883          namespace (str):
   884          name (str):
   885          paths ([]):
   886      """
   887  
   888      def __init__(self, namespace, name, paths):
   889          self.namespace = namespace
   890          self.name = name
   891          self.paths = paths
   892  
   893  
   894  class VirtualServerRouteSetup:
   895      """
   896      Encapsulate Virtual Server Example details.
   897  
   898      Attributes:
   899          public_endpoint (PublicEndpoint):
   900          namespace (str):
   901          vs_host (str):
   902          vs_name (str):
   903          route_m (VirtualServerRoute): route with multiple subroutes
   904          route_s (VirtualServerRoute): route with single subroute
   905      """
   906  
   907      def __init__(
   908          self,
   909          public_endpoint: PublicEndpoint,
   910          namespace,
   911          vs_host,
   912          vs_name,
   913          route_m: VirtualServerRoute,
   914          route_s: VirtualServerRoute,
   915      ):
   916          self.public_endpoint = public_endpoint
   917          self.namespace = namespace
   918          self.vs_host = vs_host
   919          self.vs_name = vs_name
   920          self.route_m = route_m
   921          self.route_s = route_s
   922  
   923  
   924  @pytest.fixture(scope="class")
   925  def v_s_route_setup(request, kube_apis, ingress_controller_endpoint) -> VirtualServerRouteSetup:
   926      """
   927      Prepare Virtual Server Route Example.
   928  
   929      1st namespace with VS and 1st addressed VSR and 2nd namespace with second addressed VSR.
   930  
   931      :param request: internal pytest fixture to parametrize this method:
   932          {example: virtual-server|virtual-server-tls|...}
   933          'example' is a directory name in TEST_DATA
   934      :param kube_apis: client apis
   935      :param crd_ingress_controller:
   936      :param ingress_controller_endpoint:
   937  
   938      :return: VirtualServerRouteSetup
   939      """
   940      vs_routes_ns = get_route_namespace_from_vs_yaml(
   941          f"{TEST_DATA}/{request.param['example']}/standard/virtual-server.yaml"
   942      )
   943      ns_1 = create_namespace_with_name_from_yaml(
   944          kube_apis.v1, vs_routes_ns[0], f"{TEST_DATA}/common/ns.yaml"
   945      )
   946      ns_2 = create_namespace_with_name_from_yaml(
   947          kube_apis.v1, vs_routes_ns[1], f"{TEST_DATA}/common/ns.yaml"
   948      )
   949      print("------------------------- Deploy Virtual Server -----------------------------------")
   950      vs_name = create_virtual_server_from_yaml(
   951          kube_apis.custom_objects,
   952          f"{TEST_DATA}/{request.param['example']}/standard/virtual-server.yaml",
   953          ns_1,
   954      )
   955      vs_host = get_first_host_from_yaml(
   956          f"{TEST_DATA}/{request.param['example']}/standard/virtual-server.yaml"
   957      )
   958  
   959      print(
   960          "------------------------- Deploy Virtual Server Routes -----------------------------------"
   961      )
   962      vsr_m_name = create_v_s_route_from_yaml(
   963          kube_apis.custom_objects,
   964          f"{TEST_DATA}/{request.param['example']}/route-multiple.yaml",
   965          ns_1,
   966      )
   967      vsr_m_paths = get_paths_from_vsr_yaml(
   968          f"{TEST_DATA}/{request.param['example']}/route-multiple.yaml"
   969      )
   970      route_m = VirtualServerRoute(ns_1, vsr_m_name, vsr_m_paths)
   971  
   972      vsr_s_name = create_v_s_route_from_yaml(
   973          kube_apis.custom_objects, f"{TEST_DATA}/{request.param['example']}/route-single.yaml", ns_2
   974      )
   975      vsr_s_paths = get_paths_from_vsr_yaml(
   976          f"{TEST_DATA}/{request.param['example']}/route-single.yaml"
   977      )
   978      route_s = VirtualServerRoute(ns_2, vsr_s_name, vsr_s_paths)
   979  
   980      def fin():
   981          print("Clean up the Virtual Server Route:")
   982          delete_v_s_route(kube_apis.custom_objects, vsr_m_name, ns_1)
   983          delete_v_s_route(kube_apis.custom_objects, vsr_s_name, ns_2)
   984          print("Clean up Virtual Server:")
   985          delete_virtual_server(kube_apis.custom_objects, vs_name, ns_1)
   986          print("Delete test namespaces")
   987          delete_namespace(kube_apis.v1, ns_1)
   988          delete_namespace(kube_apis.v1, ns_2)
   989  
   990      request.addfinalizer(fin)
   991  
   992      return VirtualServerRouteSetup(
   993          ingress_controller_endpoint, ns_1, vs_host, vs_name, route_m, route_s
   994      )
   995  
   996  
   997  @pytest.fixture(scope="function")
   998  def restore_configmap(request, kube_apis, ingress_controller_prerequisites, test_namespace) -> None:
   999      """
  1000      Return ConfigMap to the initial state after the test.
  1001  
  1002      :param request: internal pytest fixture
  1003      :param kube_apis: client apis
  1004      :param ingress_controller_prerequisites:
  1005      :param test_namespace: str
  1006      :return:
  1007      """
  1008  
  1009      def fin():
  1010          replace_configmap_from_yaml(
  1011              kube_apis.v1,
  1012              ingress_controller_prerequisites.config_map["metadata"]["name"],
  1013              ingress_controller_prerequisites.namespace,
  1014              f"{DEPLOYMENTS}/common/nginx-config.yaml",
  1015          )
  1016  
  1017      request.addfinalizer(fin)