|
7 | 7 | import os |
8 | 8 | import yaml |
9 | 9 |
|
| 10 | +from datetime import datetime |
10 | 11 | from kubernetes import client, config |
11 | 12 |
|
12 | 13 |
|
@@ -614,6 +615,71 @@ def test_infrastructure_roles(self): |
614 | 615 | "Origin": 2, |
615 | 616 | }) |
616 | 617 |
|
| 618 | + @timeout_decorator.timeout(TEST_TIMEOUT_SEC) |
| 619 | + def test_x_cluster_deletion(self): |
| 620 | + ''' |
| 621 | + Test deletion with configured protection |
| 622 | + ''' |
| 623 | + k8s = self.k8s |
| 624 | + cluster_label = 'application=spilo,cluster-name=acid-minimal-cluster' |
| 625 | + |
| 626 | + # configure delete protection |
| 627 | + patch_delete_annotations = { |
| 628 | + "data": { |
| 629 | + "delete_annotation_date_key": "delete-date", |
| 630 | + "delete_annotation_name_key": "delete-clustername" |
| 631 | + } |
| 632 | + } |
| 633 | + k8s.update_config(patch_delete_annotations) |
| 634 | + |
| 635 | + # this delete attempt should be omitted because of missing annotations |
| 636 | + k8s.api.custom_objects_api.delete_namespaced_custom_object( |
| 637 | + "acid.zalan.do", "v1", "default", "postgresqls", "acid-minimal-cluster") |
| 638 | + |
| 639 | + # check that pods and services are still there |
| 640 | + k8s.wait_for_running_pods(cluster_label, 2) |
| 641 | + k8s.wait_for_service(cluster_label) |
| 642 | + |
| 643 | + # recreate Postgres cluster resource |
| 644 | + k8s.create_with_kubectl("manifests/minimal-postgres-manifest.yaml") |
| 645 | + |
| 646 | + # wait a little before proceeding |
| 647 | + time.sleep(10) |
| 648 | + |
| 649 | + # add annotations to manifest |
| 650 | + deleteDate = datetime.today().strftime('%Y-%m-%d') |
| 651 | + pg_patch_delete_annotations = { |
| 652 | + "metadata": { |
| 653 | + "annotations": { |
| 654 | + "delete-date": deleteDate, |
| 655 | + "delete-clustername": "acid-minimal-cluster", |
| 656 | + } |
| 657 | + } |
| 658 | + } |
| 659 | + k8s.api.custom_objects_api.patch_namespaced_custom_object( |
| 660 | + "acid.zalan.do", "v1", "default", "postgresqls", "acid-minimal-cluster", pg_patch_delete_annotations) |
| 661 | + |
| 662 | + # wait a little before proceeding |
| 663 | + time.sleep(10) |
| 664 | + k8s.wait_for_running_pods(cluster_label, 2) |
| 665 | + k8s.wait_for_service(cluster_label) |
| 666 | + |
| 667 | + # now delete process should be triggered |
| 668 | + k8s.api.custom_objects_api.delete_namespaced_custom_object( |
| 669 | + "acid.zalan.do", "v1", "default", "postgresqls", "acid-minimal-cluster") |
| 670 | + |
| 671 | + # wait until cluster is deleted |
| 672 | + time.sleep(120) |
| 673 | + |
| 674 | + # check if everything has been deleted |
| 675 | + self.assertEqual(0, k8s.count_pods_with_label(cluster_label)) |
| 676 | + self.assertEqual(0, k8s.count_services_with_label(cluster_label)) |
| 677 | + self.assertEqual(0, k8s.count_endpoints_with_label(cluster_label)) |
| 678 | + self.assertEqual(0, k8s.count_statefulsets_with_label(cluster_label)) |
| 679 | + self.assertEqual(0, k8s.count_deployments_with_label(cluster_label)) |
| 680 | + self.assertEqual(0, k8s.count_pdbs_with_label(cluster_label)) |
| 681 | + self.assertEqual(0, k8s.count_secrets_with_label(cluster_label)) |
| 682 | + |
617 | 683 | def get_failover_targets(self, master_node, replica_nodes): |
618 | 684 | ''' |
619 | 685 | If all pods live on the same node, failover will happen to other worker(s) |
@@ -700,11 +766,12 @@ def __init__(self): |
700 | 766 | self.apps_v1 = client.AppsV1Api() |
701 | 767 | self.batch_v1_beta1 = client.BatchV1beta1Api() |
702 | 768 | self.custom_objects_api = client.CustomObjectsApi() |
| 769 | + self.policy_v1_beta1 = client.PolicyV1beta1Api() |
703 | 770 |
|
704 | 771 |
|
705 | 772 | class K8s: |
706 | 773 | ''' |
707 | | - Wraps around K8 api client and helper methods. |
| 774 | + Wraps around K8s api client and helper methods. |
708 | 775 | ''' |
709 | 776 |
|
710 | 777 | RETRY_TIMEOUT_SEC = 10 |
@@ -755,14 +822,6 @@ def wait_for_pod_start(self, pod_labels, namespace='default'): |
755 | 822 | if pods: |
756 | 823 | pod_phase = pods[0].status.phase |
757 | 824 |
|
758 | | - if pods and pod_phase != 'Running': |
759 | | - pod_name = pods[0].metadata.name |
760 | | - response = self.api.core_v1.read_namespaced_pod( |
761 | | - name=pod_name, |
762 | | - namespace=namespace |
763 | | - ) |
764 | | - print("Pod description {}".format(response)) |
765 | | - |
766 | 825 | time.sleep(self.RETRY_TIMEOUT_SEC) |
767 | 826 |
|
768 | 827 | def get_service_type(self, svc_labels, namespace='default'): |
@@ -824,6 +883,25 @@ def get_services(): |
824 | 883 | def count_pods_with_label(self, labels, namespace='default'): |
825 | 884 | return len(self.api.core_v1.list_namespaced_pod(namespace, label_selector=labels).items) |
826 | 885 |
|
| 886 | + def count_services_with_label(self, labels, namespace='default'): |
| 887 | + return len(self.api.core_v1.list_namespaced_service(namespace, label_selector=labels).items) |
| 888 | + |
| 889 | + def count_endpoints_with_label(self, labels, namespace='default'): |
| 890 | + return len(self.api.core_v1.list_namespaced_endpoints(namespace, label_selector=labels).items) |
| 891 | + |
| 892 | + def count_secrets_with_label(self, labels, namespace='default'): |
| 893 | + return len(self.api.core_v1.list_namespaced_secret(namespace, label_selector=labels).items) |
| 894 | + |
| 895 | + def count_statefulsets_with_label(self, labels, namespace='default'): |
| 896 | + return len(self.api.apps_v1.list_namespaced_stateful_set(namespace, label_selector=labels).items) |
| 897 | + |
| 898 | + def count_deployments_with_label(self, labels, namespace='default'): |
| 899 | + return len(self.api.apps_v1.list_namespaced_deployment(namespace, label_selector=labels).items) |
| 900 | + |
| 901 | + def count_pdbs_with_label(self, labels, namespace='default'): |
| 902 | + return len(self.api.policy_v1_beta1.list_namespaced_pod_disruption_budget( |
| 903 | + namespace, label_selector=labels).items) |
| 904 | + |
827 | 905 | def wait_for_pod_failover(self, failover_targets, labels, namespace='default'): |
828 | 906 | pod_phase = 'Failing over' |
829 | 907 | new_pod_node = '' |
|
0 commit comments