mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-03 19:58:17 +00:00 
			
		
		
		
	Merge pull request #110237 from ii/create-apiservice-lifecycle-test
Write APIService lifecycle test + 4 Endpoints
This commit is contained in:
		@@ -33,12 +33,15 @@ import (
 | 
				
			|||||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
						metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
 | 
						"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
 | 
				
			||||||
	unstructuredv1 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
 | 
						unstructuredv1 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
 | 
				
			||||||
 | 
						"k8s.io/apimachinery/pkg/labels"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/runtime/schema"
 | 
						"k8s.io/apimachinery/pkg/runtime/schema"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/types"
 | 
						"k8s.io/apimachinery/pkg/types"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/intstr"
 | 
						"k8s.io/apimachinery/pkg/util/intstr"
 | 
				
			||||||
 | 
						utilrand "k8s.io/apimachinery/pkg/util/rand"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/wait"
 | 
						"k8s.io/apimachinery/pkg/util/wait"
 | 
				
			||||||
	"k8s.io/client-go/discovery"
 | 
						"k8s.io/client-go/discovery"
 | 
				
			||||||
	clientset "k8s.io/client-go/kubernetes"
 | 
						clientset "k8s.io/client-go/kubernetes"
 | 
				
			||||||
 | 
						"k8s.io/client-go/util/retry"
 | 
				
			||||||
	apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1"
 | 
						apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1"
 | 
				
			||||||
	aggregatorclient "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset"
 | 
						aggregatorclient "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset"
 | 
				
			||||||
	rbacv1helpers "k8s.io/kubernetes/pkg/apis/rbac/v1"
 | 
						rbacv1helpers "k8s.io/kubernetes/pkg/apis/rbac/v1"
 | 
				
			||||||
@@ -55,6 +58,9 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	aggregatorServicePort = 7443
 | 
						aggregatorServicePort = 7443
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						apiServiceRetryPeriod  = 1 * time.Second
 | 
				
			||||||
 | 
						apiServiceRetryTimeout = 1 * time.Minute
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var _ = SIGDescribe("Aggregator", func() {
 | 
					var _ = SIGDescribe("Aggregator", func() {
 | 
				
			||||||
@@ -103,6 +109,121 @@ var _ = SIGDescribe("Aggregator", func() {
 | 
				
			|||||||
		TestSampleAPIServer(f, aggrclient, imageutils.GetE2EImage(imageutils.APIServer))
 | 
							TestSampleAPIServer(f, aggrclient, imageutils.GetE2EImage(imageutils.APIServer))
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ginkgo.It("should manage the lifecycle of an APIService", func() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ns := f.Namespace.Name
 | 
				
			||||||
 | 
							framework.Logf("ns: %v", ns)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							subDomain := "e2e-" + utilrand.String(5)
 | 
				
			||||||
 | 
							apiServiceGroup := subDomain + ".example.com"
 | 
				
			||||||
 | 
							label := map[string]string{"e2e": subDomain}
 | 
				
			||||||
 | 
							labelSelector := labels.SelectorFromSet(label).String()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							apiServiceName := "v1alpha1." + apiServiceGroup
 | 
				
			||||||
 | 
							apiServiceClient := aggrclient.ApiregistrationV1().APIServices()
 | 
				
			||||||
 | 
							certCtx := setupServerCert(ns, "e2e-api")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ginkgo.By(fmt.Sprintf("Create APIService %s", apiServiceName))
 | 
				
			||||||
 | 
							_, err := apiServiceClient.Create(context.TODO(), &apiregistrationv1.APIService{
 | 
				
			||||||
 | 
								ObjectMeta: metav1.ObjectMeta{
 | 
				
			||||||
 | 
									Name:   apiServiceName,
 | 
				
			||||||
 | 
									Labels: label,
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								Spec: apiregistrationv1.APIServiceSpec{
 | 
				
			||||||
 | 
									Service: &apiregistrationv1.ServiceReference{
 | 
				
			||||||
 | 
										Namespace: ns,
 | 
				
			||||||
 | 
										Name:      "e2e-api",
 | 
				
			||||||
 | 
										Port:      pointer.Int32Ptr(aggregatorServicePort),
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									Group:                apiServiceGroup,
 | 
				
			||||||
 | 
									Version:              "v1alpha1",
 | 
				
			||||||
 | 
									CABundle:             certCtx.signingCert,
 | 
				
			||||||
 | 
									GroupPriorityMinimum: 2000,
 | 
				
			||||||
 | 
									VersionPriority:      200,
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							}, metav1.CreateOptions{})
 | 
				
			||||||
 | 
							framework.ExpectNoError(err, "creating apiService %s, namespace %s", apiServiceName, ns)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							_, err = apiServiceClient.List(context.TODO(), metav1.ListOptions{LabelSelector: labelSelector})
 | 
				
			||||||
 | 
							framework.ExpectNoError(err, "failed to list API Services")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ginkgo.By("Confirm that the generated APIService has been created")
 | 
				
			||||||
 | 
							err = wait.PollImmediate(apiServiceRetryPeriod, apiServiceRetryTimeout, checkApiServiceListQuantity(aggrclient, labelSelector, 1))
 | 
				
			||||||
 | 
							framework.ExpectNoError(err, "failed to count the required APIServices")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ginkgo.By(fmt.Sprintf("Update status for APIService %s", apiServiceName))
 | 
				
			||||||
 | 
							var statusToUpdate, updatedStatus *apiregistrationv1.APIService
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							updatedStatusConditions := apiregistrationv1.APIServiceCondition{
 | 
				
			||||||
 | 
								Type:    "StatusUpdate",
 | 
				
			||||||
 | 
								Status:  "True",
 | 
				
			||||||
 | 
								Reason:  "E2E",
 | 
				
			||||||
 | 
								Message: "Set from e2e test",
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							err = retry.RetryOnConflict(retry.DefaultRetry, func() error {
 | 
				
			||||||
 | 
								statusToUpdate, err = apiServiceClient.Get(context.TODO(), apiServiceName, metav1.GetOptions{})
 | 
				
			||||||
 | 
								framework.ExpectNoError(err, "Unable to retrieve api service %s", apiServiceName)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								statusToUpdate.Status.Conditions = append(statusToUpdate.Status.Conditions, updatedStatusConditions)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								updatedStatus, err = apiServiceClient.UpdateStatus(context.TODO(), statusToUpdate, metav1.UpdateOptions{})
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
							framework.ExpectNoError(err, "Failed to update status. %v", err)
 | 
				
			||||||
 | 
							framework.Logf("updatedStatus.Conditions: %#v", updatedStatus.Status.Conditions)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ginkgo.By("Confirm that the generated APIService has an updated status")
 | 
				
			||||||
 | 
							err = wait.PollImmediate(apiServiceRetryPeriod, apiServiceRetryTimeout, checkApiServiceStatus(aggrclient, apiServiceName, updatedStatusConditions))
 | 
				
			||||||
 | 
							framework.ExpectNoError(err, "failed to locate the required APIService status")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ginkgo.By(fmt.Sprintf("Patching status for APIService %s", apiServiceName))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							patchedStatusConditions := apiregistrationv1.APIServiceCondition{
 | 
				
			||||||
 | 
								Type:    "StatusPatched",
 | 
				
			||||||
 | 
								Status:  "True",
 | 
				
			||||||
 | 
								Reason:  "E2E",
 | 
				
			||||||
 | 
								Message: "Set from e2e test",
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							payload := []byte(`{"status":{"conditions":[{"type":"StatusPatched","status":"True","reason":"E2E","message":"Set from e2e test"}]}}`)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							patchedApiService, err := apiServiceClient.Patch(context.TODO(), apiServiceName, types.MergePatchType, payload, metav1.PatchOptions{}, "status")
 | 
				
			||||||
 | 
							framework.ExpectNoError(err, "Failed to patch status. %v", err)
 | 
				
			||||||
 | 
							framework.Logf("Patched status conditions: %#v", patchedApiService.Status.Conditions)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ginkgo.By("Confirm that the generated APIService has a patched status")
 | 
				
			||||||
 | 
							err = wait.PollImmediate(apiServiceRetryPeriod, apiServiceRetryTimeout, checkApiServiceStatus(aggrclient, apiServiceName, patchedStatusConditions))
 | 
				
			||||||
 | 
							framework.ExpectNoError(err, "failed to locate the required APIService status")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ginkgo.By(fmt.Sprintf("Replace APIService %s", apiServiceName))
 | 
				
			||||||
 | 
							var updatedApiService *apiregistrationv1.APIService
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							err = retry.RetryOnConflict(retry.DefaultRetry, func() error {
 | 
				
			||||||
 | 
								patchedApiService, err = apiServiceClient.Get(context.TODO(), apiServiceName, metav1.GetOptions{})
 | 
				
			||||||
 | 
								framework.ExpectNoError(err, "Unable to get APIService %s", apiServiceName)
 | 
				
			||||||
 | 
								patchedApiService.Labels = map[string]string{
 | 
				
			||||||
 | 
									apiServiceGroup: "updated",
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								updatedApiService, err = apiServiceClient.Update(context.TODO(), patchedApiService, metav1.UpdateOptions{})
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
							framework.ExpectNoError(err)
 | 
				
			||||||
 | 
							framework.ExpectEqual(updatedApiService.Labels[apiServiceGroup], "updated", "updated object should have the applied label")
 | 
				
			||||||
 | 
							framework.Logf("Found updated apiService label for %q", apiServiceName)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ginkgo.By(fmt.Sprintf("DeleteCollection APIService %s via labelSelector: %s", apiServiceName, labelSelector))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							err = aggrclient.ApiregistrationV1().APIServices().DeleteCollection(context.TODO(),
 | 
				
			||||||
 | 
								metav1.DeleteOptions{GracePeriodSeconds: pointer.Int64(1)},
 | 
				
			||||||
 | 
								metav1.ListOptions{LabelSelector: labelSelector})
 | 
				
			||||||
 | 
							framework.ExpectNoError(err, "Unable to delete apiservice %s", apiServiceName)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ginkgo.By("Confirm that the generated APIService has been deleted")
 | 
				
			||||||
 | 
							err = wait.PollImmediate(apiServiceRetryPeriod, apiServiceRetryTimeout, checkApiServiceListQuantity(aggrclient, labelSelector, 0))
 | 
				
			||||||
 | 
							framework.ExpectNoError(err, "failed to count the required APIServices")
 | 
				
			||||||
 | 
							framework.Logf("APIService %s has been deleted.", apiServiceName)
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func cleanTest(client clientset.Interface, aggrclient *aggregatorclient.Clientset, namespace string) {
 | 
					func cleanTest(client clientset.Interface, aggrclient *aggregatorclient.Clientset, namespace string) {
 | 
				
			||||||
@@ -583,3 +704,42 @@ func generateFlunderName(base string) string {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	return fmt.Sprintf("%s-%d", base, id)
 | 
						return fmt.Sprintf("%s-%d", base, id)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func checkApiServiceListQuantity(aggrclient *aggregatorclient.Clientset, label string, quantity int) func() (bool, error) {
 | 
				
			||||||
 | 
						return func() (bool, error) {
 | 
				
			||||||
 | 
							var err error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							framework.Logf("Requesting list of APIServices to confirm quantity")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							list, err := aggrclient.ApiregistrationV1().APIServices().List(context.TODO(), metav1.ListOptions{LabelSelector: label})
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return false, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if len(list.Items) != quantity {
 | 
				
			||||||
 | 
								return false, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							framework.Logf("Found %d APIService with label %q", quantity, label)
 | 
				
			||||||
 | 
							return true, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func checkApiServiceStatus(aggrclient *aggregatorclient.Clientset, apiServiceName string, statusConditions apiregistrationv1.APIServiceCondition) func() (bool, error) {
 | 
				
			||||||
 | 
						return func() (bool, error) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							framework.Logf("Get APIService %q to confirm status", apiServiceName)
 | 
				
			||||||
 | 
							currentApiService, err := aggrclient.ApiregistrationV1().APIServices().Get(context.TODO(), apiServiceName, metav1.GetOptions{})
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return false, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for _, cond := range currentApiService.Status.Conditions {
 | 
				
			||||||
 | 
								if cond.Type == statusConditions.Type && cond.Reason == statusConditions.Reason && cond.Message == statusConditions.Message {
 | 
				
			||||||
 | 
									framework.Logf("APIService %q has the required status conditions", apiServiceName)
 | 
				
			||||||
 | 
									return true, nil
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return false, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user