github.com/nginxinc/kubernetes-ingress@v1.12.5/tests/suite/custom_resources_utils.py (about) 1 """Describe methods to utilize the kubernetes-client.""" 2 import pytest 3 import time 4 import yaml 5 import logging 6 7 from pprint import pprint 8 from kubernetes.client import CustomObjectsApi, ApiextensionsV1Api, CoreV1Api 9 from kubernetes import client 10 from kubernetes.client.rest import ApiException 11 12 from suite.resources_utils import ensure_item_removal, get_file_contents 13 14 15 def create_crd(api_extensions_v1: ApiextensionsV1Api, body) -> None: 16 """ 17 Create a CRD based on a dict 18 19 :param api_extensions_v1: ApiextensionsV1Api 20 :param body: a dict 21 """ 22 try: 23 api_extensions_v1.create_custom_resource_definition(body) 24 except ApiException as api_ex: 25 raise api_ex 26 except Exception as ex: 27 # https://github.com/kubernetes-client/python/issues/376 28 if ex.args[0] == "Invalid value for `conditions`, must not be `None`": 29 print("There was an insignificant exception during the CRD creation. Continue...") 30 else: 31 pytest.fail(f"An unexpected exception {ex} occurred. Exiting...") 32 33 34 def create_crd_from_yaml( 35 api_extensions_v1: ApiextensionsV1Api, name, yaml_manifest 36 ) -> None: 37 """ 38 Create a specific CRD based on yaml file. 39 40 :param api_extensions_v1: ApiextensionsV1Api 41 :param name: CRD name 42 :param yaml_manifest: an absolute path to file 43 """ 44 print(f"Create a CRD with name: {name}") 45 with open(yaml_manifest) as f: 46 docs = yaml.safe_load_all(f) 47 for dep in docs: 48 if dep["metadata"]["name"] == name: 49 create_crd(api_extensions_v1, dep) 50 print("CRD was created") 51 52 53 def delete_crd(api_extensions_v1: ApiextensionsV1Api, name) -> None: 54 """ 55 Delete a CRD. 56 57 :param api_extensions_v1: ApiextensionsV1Api 58 :param name: 59 :return: 60 """ 61 print(f"Delete a CRD: {name}") 62 api_extensions_v1.delete_custom_resource_definition(name) 63 ensure_item_removal(api_extensions_v1.read_custom_resource_definition, name) 64 print(f"CRD was removed with name '{name}'") 65 66 67 def read_custom_resource(custom_objects: CustomObjectsApi, namespace, plural, name) -> object: 68 """ 69 Get CRD information (kubectl describe output) 70 71 :param custom_objects: CustomObjectsApi 72 :param namespace: The custom resource's namespace 73 :param plural: the custom resource's plural name 74 :param name: the custom object's name 75 :return: object 76 """ 77 print(f"Getting info for {name} in namespace {namespace}") 78 try: 79 response = custom_objects.get_namespaced_custom_object( 80 "k8s.nginx.org", "v1", namespace, plural, name 81 ) 82 pprint(response) 83 return response 84 85 except ApiException: 86 logging.exception(f"Exception occurred while reading CRD") 87 raise 88 89 90 def read_custom_resource_v1alpha1(custom_objects: CustomObjectsApi, namespace, plural, name) -> object: 91 """ 92 Get CRD information (kubectl describe output) 93 94 :param custom_objects: CustomObjectsApi 95 :param namespace: The custom resource's namespace 96 :param plural: the custom resource's plural name 97 :param name: the custom object's name 98 :return: object 99 """ 100 print(f"Getting info for v1alpha1 crd {name} in namespace {namespace}") 101 try: 102 response = custom_objects.get_namespaced_custom_object( 103 "k8s.nginx.org", "v1alpha1", namespace, plural, name 104 ) 105 pprint(response) 106 return response 107 108 except ApiException: 109 logging.exception(f"Exception occurred while reading CRD") 110 raise 111 112 113 def read_ts(custom_objects: CustomObjectsApi, namespace, name) -> object: 114 """ 115 Read TransportService resource. 116 """ 117 return read_custom_resource_v1alpha1(custom_objects, namespace, "transportservers", name) 118 119 def read_vs(custom_objects: CustomObjectsApi, namespace, name) -> object: 120 """ 121 Read VirtualServer resource. 122 """ 123 return read_custom_resource(custom_objects, namespace, "virtualservers", name) 124 125 def read_vsr(custom_objects: CustomObjectsApi, namespace, name) -> object: 126 """ 127 Read VirtualServerRoute resource. 128 """ 129 return read_custom_resource(custom_objects, namespace, "virtualserverroutes", name) 130 131 def read_policy(custom_objects: CustomObjectsApi, namespace, name) -> object: 132 """ 133 Read Policy resource. 134 """ 135 return read_custom_resource(custom_objects, namespace, "policies", name) 136 137 def read_ap_custom_resource(custom_objects: CustomObjectsApi, namespace, plural, name) -> object: 138 """ 139 Get AppProtect CRD information (kubectl describe output) 140 :param custom_objects: CustomObjectsApi 141 :param namespace: The custom resource's namespace 142 :param plural: the custom resource's plural name 143 :param name: the custom object's name 144 :return: object 145 """ 146 print(f"Getting info for {name} in namespace {namespace}") 147 try: 148 response = custom_objects.get_namespaced_custom_object( 149 "appprotect.f5.com", "v1beta1", namespace, plural, name 150 ) 151 return response 152 153 except ApiException: 154 logging.exception(f"Exception occurred while reading CRD") 155 raise 156 157 158 def create_policy_from_yaml(custom_objects: CustomObjectsApi, yaml_manifest, namespace) -> str: 159 """ 160 Create a Policy based on yaml file. 161 162 :param custom_objects: CustomObjectsApi 163 :param yaml_manifest: an absolute path to file 164 :param namespace: 165 :return: str 166 """ 167 print("Create a Policy:") 168 with open(yaml_manifest) as f: 169 dep = yaml.safe_load(f) 170 try: 171 custom_objects.create_namespaced_custom_object( 172 "k8s.nginx.org", "v1", namespace, "policies", dep 173 ) 174 print(f"Policy created with name '{dep['metadata']['name']}'") 175 return dep["metadata"]["name"] 176 except ApiException: 177 logging.exception(f"Exception occurred while creating Policy: {dep['metadata']['name']}") 178 raise 179 180 181 def create_ap_waf_policy_from_yaml( 182 custom_objects: CustomObjectsApi, 183 yaml_manifest, 184 namespace, 185 ap_namespace, 186 waf_enable, 187 log_enable, 188 appolicy, 189 aplogconf, 190 logdest, 191 ) -> None: 192 """ 193 Create a Policy based on yaml file. 194 195 :param custom_objects: CustomObjectsApi 196 :param yaml_manifest: an absolute path to file 197 :param namespace: namespace for test resources 198 :param ap_namespace: namespace for AppProtect resources 199 :param waf_enable: true/false 200 :param log_enable: true/false 201 :param appolicy: AppProtect policy name 202 :param aplogconf: Logconf name 203 :param logdest: AP log destination (syslog) 204 :return: None 205 """ 206 with open(yaml_manifest) as f: 207 dep = yaml.safe_load(f) 208 try: 209 dep["spec"]["waf"]["enable"] = waf_enable 210 dep["spec"]["waf"]["apPolicy"] = f"{ap_namespace}/{appolicy}" 211 dep["spec"]["waf"]["securityLog"]["enable"] = log_enable 212 dep["spec"]["waf"]["securityLog"]["apLogConf"] = f"{ap_namespace}/{aplogconf}" 213 dep["spec"]["waf"]["securityLog"]["logDest"] = f"{logdest}" 214 215 custom_objects.create_namespaced_custom_object( 216 "k8s.nginx.org", "v1", namespace, "policies", dep 217 ) 218 print(f"Policy created: {dep}") 219 except ApiException: 220 logging.exception(f"Exception occurred while creating Policy: {dep['metadata']['name']}") 221 raise 222 223 224 def delete_policy(custom_objects: CustomObjectsApi, name, namespace) -> None: 225 """ 226 Delete a Policy. 227 228 :param custom_objects: CustomObjectsApi 229 :param namespace: namespace 230 :param name: 231 :return: 232 """ 233 print(f"Delete a Policy: {name}") 234 235 custom_objects.delete_namespaced_custom_object( 236 "k8s.nginx.org", "v1", namespace, "policies", name 237 ) 238 ensure_item_removal( 239 custom_objects.get_namespaced_custom_object, 240 "k8s.nginx.org", 241 "v1", 242 namespace, 243 "policies", 244 name, 245 ) 246 print(f"Policy was removed with name '{name}'") 247 248 249 def create_virtual_server_from_yaml( 250 custom_objects: CustomObjectsApi, yaml_manifest, namespace 251 ) -> str: 252 """ 253 Create a VirtualServer based on yaml file. 254 255 :param custom_objects: CustomObjectsApi 256 :param yaml_manifest: an absolute path to file 257 :param namespace: 258 :return: str 259 """ 260 print("Create a VirtualServer:") 261 with open(yaml_manifest) as f: 262 dep = yaml.safe_load(f) 263 try: 264 custom_objects.create_namespaced_custom_object( 265 "k8s.nginx.org", "v1", namespace, "virtualservers", dep 266 ) 267 print(f"VirtualServer created with name '{dep['metadata']['name']}'") 268 return dep["metadata"]["name"] 269 except ApiException as ex: 270 logging.exception( 271 f"Exception: {ex} occurred while creating VirtualServer: {dep['metadata']['name']}" 272 ) 273 raise 274 275 276 def create_ts_from_yaml(custom_objects: CustomObjectsApi, yaml_manifest, namespace) -> dict: 277 """ 278 Create a TransportServer Resource based on yaml file. 279 280 :param custom_objects: CustomObjectsApi 281 :param yaml_manifest: an absolute path to file 282 :param namespace: 283 :return: a dictionary representing the resource 284 """ 285 return create_resource_from_yaml(custom_objects, yaml_manifest, namespace, "transportservers") 286 287 288 def create_gc_from_yaml(custom_objects: CustomObjectsApi, yaml_manifest, namespace) -> dict: 289 """ 290 Create a GlobalConfiguration Resource based on yaml file. 291 292 :param custom_objects: CustomObjectsApi 293 :param yaml_manifest: an absolute path to file 294 :param namespace: 295 :return: a dictionary representing the resource 296 """ 297 return create_resource_from_yaml(custom_objects, yaml_manifest, namespace, "globalconfigurations") 298 299 300 def create_resource_from_yaml(custom_objects: CustomObjectsApi, yaml_manifest, namespace, plural) -> dict: 301 """ 302 Create a Resource based on yaml file. 303 304 :param custom_objects: CustomObjectsApi 305 :param yaml_manifest: an absolute path to file 306 :param namespace: 307 :param plural: the plural of the resource 308 :return: a dictionary representing the resource 309 """ 310 311 with open(yaml_manifest) as f: 312 body = yaml.safe_load(f) 313 try: 314 print("Create a Custom Resource: " + body["kind"]) 315 group, version = body["apiVersion"].split("/") 316 custom_objects.create_namespaced_custom_object( 317 group, version, namespace, plural, body 318 ) 319 print(f"Custom resource {body['kind']} created with name '{body['metadata']['name']}'") 320 return body 321 except ApiException as ex: 322 logging.exception( 323 f"Exception: {ex} occurred while creating {body['kind']}: {body['metadata']['name']}" 324 ) 325 raise 326 327 328 def delete_ts(custom_objects: CustomObjectsApi, resource, namespace) -> None: 329 """ 330 Delete a TransportServer Resource. 331 332 :param custom_objects: CustomObjectsApi 333 :param namespace: namespace 334 :param resource: a dictionary representation of the resource yaml 335 :param namespace: 336 :return: 337 """ 338 return delete_resource(custom_objects, resource, namespace, "transportservers") 339 340 341 def delete_gc(custom_objects: CustomObjectsApi, resource, namespace) -> None: 342 """ 343 Delete a GlobalConfiguration Resource. 344 345 :param custom_objects: CustomObjectsApi 346 :param namespace: namespace 347 :param resource: a dictionary representation of the resource yaml 348 :param namespace: 349 :return: 350 """ 351 return delete_resource(custom_objects, resource, namespace, "globalconfigurations") 352 353 354 def delete_resource(custom_objects: CustomObjectsApi, resource, namespace, plural) -> None: 355 """ 356 Delete a Resource. 357 358 :param custom_objects: CustomObjectsApi 359 :param namespace: namespace 360 :param resource: a dictionary representation of the resource yaml 361 :param namespace: 362 :param plural: the plural of the resource 363 :return: 364 """ 365 366 name = resource['metadata']['name'] 367 kind = resource['kind'] 368 group, version = resource["apiVersion"].split("/") 369 370 print(f"Delete a '{kind}' with name '{name}'") 371 372 custom_objects.delete_namespaced_custom_object( 373 group, version, namespace, plural, name 374 ) 375 ensure_item_removal( 376 custom_objects.get_namespaced_custom_object, 377 group, 378 version, 379 namespace, 380 plural, 381 name, 382 ) 383 print(f"Resource '{kind}' was removed with name '{name}'") 384 385 386 def create_ap_logconf_from_yaml(custom_objects: CustomObjectsApi, yaml_manifest, namespace) -> str: 387 """ 388 Create a logconf for AppProtect based on yaml file. 389 :param custom_objects: CustomObjectsApi 390 :param yaml_manifest: an absolute path to file 391 :param namespace: 392 :return: str 393 """ 394 print("Create Ap logconf:") 395 with open(yaml_manifest) as f: 396 dep = yaml.safe_load(f) 397 custom_objects.create_namespaced_custom_object( 398 "appprotect.f5.com", "v1beta1", namespace, "aplogconfs", dep 399 ) 400 print(f"AP logconf created with name '{dep['metadata']['name']}'") 401 return dep["metadata"]["name"] 402 403 404 def create_ap_policy_from_yaml(custom_objects: CustomObjectsApi, yaml_manifest, namespace) -> str: 405 """ 406 Create a policy for AppProtect based on yaml file. 407 :param custom_objects: CustomObjectsApi 408 :param yaml_manifest: an absolute path to file 409 :param namespace: 410 :return: str 411 """ 412 print("Create AP Policy:") 413 with open(yaml_manifest) as f: 414 dep = yaml.safe_load(f) 415 custom_objects.create_namespaced_custom_object( 416 "appprotect.f5.com", "v1beta1", namespace, "appolicies", dep 417 ) 418 print(f"AP Policy created with name '{dep['metadata']['name']}'") 419 return dep["metadata"]["name"] 420 421 422 def create_ap_usersig_from_yaml(custom_objects: CustomObjectsApi, yaml_manifest, namespace) -> str: 423 """ 424 Create a UserSig for AppProtect based on yaml file. 425 :param custom_objects: CustomObjectsApi 426 :param yaml_manifest: an absolute path to file 427 :param namespace: 428 :return: str 429 """ 430 print("Create AP UserSig:") 431 with open(yaml_manifest) as f: 432 dep = yaml.safe_load(f) 433 custom_objects.create_namespaced_custom_object( 434 "appprotect.f5.com", "v1beta1", namespace, "apusersigs", dep 435 ) 436 print(f"AP UserSig created with name '{dep['metadata']['name']}'") 437 return dep["metadata"]["name"] 438 439 440 def delete_and_create_ap_policy_from_yaml( 441 custom_objects: CustomObjectsApi, name, yaml_manifest, namespace 442 ) -> None: 443 """ 444 Patch a AP Policy based on yaml manifest 445 :param custom_objects: CustomObjectsApi 446 :param name: 447 :param yaml_manifest: an absolute path to file 448 :param namespace: 449 :return: 450 """ 451 print(f"Update an AP Policy: {name}") 452 453 try: 454 delete_ap_policy(custom_objects, name, namespace) 455 create_ap_policy_from_yaml(custom_objects, yaml_manifest, namespace) 456 except ApiException: 457 logging.exception(f"Failed with exception while patching AP Policy: {name}") 458 raise 459 460 461 def delete_ap_usersig(custom_objects: CustomObjectsApi, name, namespace) -> None: 462 """ 463 Delete a AppProtect usersig. 464 :param custom_objects: CustomObjectsApi 465 :param namespace: namespace 466 :param name: 467 :return: 468 """ 469 print(f"Delete AP UserSig: {name}") 470 custom_objects.delete_namespaced_custom_object( 471 "appprotect.f5.com", "v1beta1", namespace, "apusersigs", name 472 ) 473 ensure_item_removal( 474 custom_objects.get_namespaced_custom_object, 475 "appprotect.f5.com", 476 "v1beta1", 477 namespace, 478 "apusersigs", 479 name, 480 ) 481 print(f"AP UserSig was removed with name: {name}") 482 483 484 def delete_ap_logconf(custom_objects: CustomObjectsApi, name, namespace) -> None: 485 """ 486 Delete a AppProtect logconf. 487 :param custom_objects: CustomObjectsApi 488 :param namespace: namespace 489 :param name: 490 :return: 491 """ 492 print(f"Delete AP logconf: {name}") 493 custom_objects.delete_namespaced_custom_object( 494 "appprotect.f5.com", "v1beta1", namespace, "aplogconfs", name 495 ) 496 ensure_item_removal( 497 custom_objects.get_namespaced_custom_object, 498 "appprotect.f5.com", 499 "v1beta1", 500 namespace, 501 "aplogconfs", 502 name, 503 ) 504 print(f"AP logconf was removed with name: {name}") 505 506 507 def delete_ap_policy(custom_objects: CustomObjectsApi, name, namespace) -> None: 508 """ 509 Delete a AppProtect policy. 510 :param custom_objects: CustomObjectsApi 511 :param namespace: namespace 512 :param name: 513 :return: 514 """ 515 print(f"Delete a AP policy: {name}") 516 custom_objects.delete_namespaced_custom_object( 517 "appprotect.f5.com", "v1beta1", namespace, "appolicies", name 518 ) 519 ensure_item_removal( 520 custom_objects.get_namespaced_custom_object, 521 "appprotect.f5.com", 522 "v1beta1", 523 namespace, 524 "appolicies", 525 name, 526 ) 527 time.sleep(3) 528 print(f"AP policy was removed with name: {name}") 529 530 531 def delete_virtual_server(custom_objects: CustomObjectsApi, name, namespace) -> None: 532 """ 533 Delete a VirtualServer. 534 535 :param custom_objects: CustomObjectsApi 536 :param namespace: namespace 537 :param name: 538 :return: 539 """ 540 print(f"Delete a VirtualServer: {name}") 541 542 custom_objects.delete_namespaced_custom_object( 543 "k8s.nginx.org", "v1", namespace, "virtualservers", name 544 ) 545 ensure_item_removal( 546 custom_objects.get_namespaced_custom_object, 547 "k8s.nginx.org", 548 "v1", 549 namespace, 550 "virtualservers", 551 name, 552 ) 553 print(f"VirtualServer was removed with name '{name}'") 554 555 556 def patch_virtual_server_from_yaml( 557 custom_objects: CustomObjectsApi, name, yaml_manifest, namespace 558 ) -> None: 559 """ 560 Patch a VS based on yaml manifest 561 :param custom_objects: CustomObjectsApi 562 :param name: 563 :param yaml_manifest: an absolute path to file 564 :param namespace: 565 :return: 566 """ 567 print(f"Update a VirtualServer: {name}") 568 with open(yaml_manifest) as f: 569 dep = yaml.safe_load(f) 570 571 try: 572 custom_objects.patch_namespaced_custom_object( 573 "k8s.nginx.org", "v1", namespace, "virtualservers", name, dep 574 ) 575 print(f"VirtualServer updated with name '{dep['metadata']['name']}'") 576 except ApiException: 577 logging.exception(f"Failed with exception while patching VirtualServer: {name}") 578 raise 579 580 581 def patch_ts( 582 custom_objects: CustomObjectsApi, name, yaml_manifest, namespace 583 ) -> None: 584 """ 585 Patch a TransportServer based on yaml manifest 586 """ 587 return patch_custom_resource_v1alpha1(custom_objects, name, yaml_manifest, namespace, "transportservers") 588 589 590 def patch_custom_resource_v1alpha1(custom_objects: CustomObjectsApi, name, yaml_manifest, namespace, plural) -> None: 591 """ 592 Patch a custom resource based on yaml manifest 593 """ 594 print(f"Update a Resource: {name}") 595 with open(yaml_manifest) as f: 596 dep = yaml.safe_load(f) 597 598 try: 599 custom_objects.patch_namespaced_custom_object( 600 "k8s.nginx.org", "v1alpha1", namespace, plural, name, dep 601 ) 602 except ApiException: 603 logging.exception(f"Failed with exception while patching custom resource: {name}") 604 raise 605 606 607 def delete_and_create_vs_from_yaml( 608 custom_objects: CustomObjectsApi, name, yaml_manifest, namespace 609 ) -> None: 610 """ 611 Perform delete and create for vs with same name based on yaml 612 613 :param custom_objects: CustomObjectsApi 614 :param name: 615 :param yaml_manifest: an absolute path to file 616 :param namespace: 617 :return: 618 """ 619 try: 620 delete_virtual_server(custom_objects, name, namespace) 621 create_virtual_server_from_yaml(custom_objects, yaml_manifest, namespace) 622 except ApiException: 623 logging.exception(f"Failed with exception while patching VirtualServer: {name}") 624 raise 625 626 627 def patch_virtual_server(custom_objects: CustomObjectsApi, name, namespace, body) -> str: 628 """ 629 Update a VirtualServer based on a dict. 630 631 :param custom_objects: CustomObjectsApi 632 :param name: 633 :param body: dict 634 :param namespace: 635 :return: str 636 """ 637 print("Update a VirtualServer:") 638 custom_objects.patch_namespaced_custom_object( 639 "k8s.nginx.org", "v1", namespace, "virtualservers", name, body 640 ) 641 print(f"VirtualServer updated with a name '{body['metadata']['name']}'") 642 return body["metadata"]["name"] 643 644 645 def patch_v_s_route_from_yaml( 646 custom_objects: CustomObjectsApi, name, yaml_manifest, namespace 647 ) -> None: 648 """ 649 Update a VirtualServerRoute based on yaml manifest 650 651 :param custom_objects: CustomObjectsApi 652 :param name: 653 :param yaml_manifest: an absolute path to file 654 :param namespace: 655 :return: 656 """ 657 print(f"Update a VirtualServerRoute: {name}") 658 with open(yaml_manifest) as f: 659 dep = yaml.safe_load(f) 660 try: 661 custom_objects.patch_namespaced_custom_object( 662 "k8s.nginx.org", "v1", namespace, "virtualserverroutes", name, dep 663 ) 664 print(f"VirtualServerRoute updated with name '{dep['metadata']['name']}'") 665 except ApiException: 666 logging.exception(f"Failed with exception while patching VirtualServerRoute: {name}") 667 raise 668 669 670 def get_vs_nginx_template_conf( 671 v1: CoreV1Api, vs_namespace, vs_name, pod_name, pod_namespace 672 ) -> str: 673 """ 674 Get contents of /etc/nginx/conf.d/vs_{namespace}_{vs_name}.conf in the pod. 675 676 :param v1: CoreV1Api 677 :param vs_namespace: 678 :param vs_name: 679 :param pod_name: 680 :param pod_namespace: 681 :return: str 682 """ 683 file_path = f"/etc/nginx/conf.d/vs_{vs_namespace}_{vs_name}.conf" 684 return get_file_contents(v1, file_path, pod_name, pod_namespace) 685 686 687 def create_v_s_route_from_yaml(custom_objects: CustomObjectsApi, yaml_manifest, namespace) -> str: 688 """ 689 Create a VirtualServerRoute based on a yaml file. 690 691 :param custom_objects: CustomObjectsApi 692 :param yaml_manifest: an absolute path to a file 693 :param namespace: 694 :return: str 695 """ 696 print("Create a VirtualServerRoute:") 697 with open(yaml_manifest) as f: 698 dep = yaml.safe_load(f) 699 700 custom_objects.create_namespaced_custom_object( 701 "k8s.nginx.org", "v1", namespace, "virtualserverroutes", dep 702 ) 703 print(f"VirtualServerRoute created with a name '{dep['metadata']['name']}'") 704 return dep["metadata"]["name"] 705 706 707 def patch_v_s_route(custom_objects: CustomObjectsApi, name, namespace, body) -> str: 708 """ 709 Update a VirtualServerRoute based on a dict. 710 711 :param custom_objects: CustomObjectsApi 712 :param name: 713 :param body: dict 714 :param namespace: 715 :return: str 716 """ 717 print("Update a VirtualServerRoute:") 718 custom_objects.patch_namespaced_custom_object( 719 "k8s.nginx.org", "v1", namespace, "virtualserverroutes", name, body 720 ) 721 print(f"VirtualServerRoute updated with a name '{body['metadata']['name']}'") 722 return body["metadata"]["name"] 723 724 725 def delete_v_s_route(custom_objects: CustomObjectsApi, name, namespace) -> None: 726 """ 727 Delete a VirtualServerRoute. 728 729 :param custom_objects: CustomObjectsApi 730 :param namespace: namespace 731 :param name: 732 :return: 733 """ 734 print(f"Delete a VirtualServerRoute: {name}") 735 custom_objects.delete_namespaced_custom_object( 736 "k8s.nginx.org", "v1", namespace, "virtualserverroutes", name, 737 ) 738 ensure_item_removal( 739 custom_objects.get_namespaced_custom_object, 740 "k8s.nginx.org", 741 "v1", 742 namespace, 743 "virtualserverroutes", 744 name, 745 ) 746 print(f"VirtualServerRoute was removed with the name '{name}'") 747 748 749 def generate_item_with_upstream_options(yaml_manifest, options) -> dict: 750 """ 751 Generate a VS/VSR item with an upstream option. 752 753 Update all the upstreams in VS/VSR 754 :param yaml_manifest: an absolute path to a file 755 :param options: dict 756 :return: dict 757 """ 758 with open(yaml_manifest) as f: 759 dep = yaml.safe_load(f) 760 for upstream in dep["spec"]["upstreams"]: 761 upstream.update(options) 762 return dep