Skip to content

Commit

Permalink
e2e reorg helpers
Browse files Browse the repository at this point in the history
  • Loading branch information
fabriziopandini committed Apr 16, 2020
1 parent f38fd7d commit f972a2c
Show file tree
Hide file tree
Showing 21 changed files with 1,375 additions and 1,220 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// +build e2e

/*
Copyright 2020 The Kubernetes Authors.
Expand All @@ -16,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

package discovery
package framework

import (
"context"
Expand All @@ -26,45 +24,23 @@ import (
"path"
"path/filepath"

"github.com/onsi/ginkgo"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"

appsv1 "k8s.io/api/apps/v1"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
apimeta "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha3"
controlplanev1 "sigs.k8s.io/cluster-api/controlplane/kubeadm/api/v1alpha3"
"sigs.k8s.io/cluster-api/test/framework"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/yaml"
)

// Provides methods for discovering Cluster API objects existing in the management cluster.

// GetControllerDeploymentsInput is the input for GetControllerDeployments.
type GetControllerDeploymentsInput struct {
Lister framework.Lister
}

// GetControllerDeployments returns all the deployment for the cluster API controllers existing in a management cluster.
func GetControllerDeployments(ctx context.Context, input GetControllerDeploymentsInput) []*appsv1.Deployment {
deploymentList := &appsv1.DeploymentList{}
Expect(input.Lister.List(ctx, deploymentList, capiProviderOptions()...)).To(Succeed(), "Failed to list deployments for the cluster API controllers")

deployments := make([]*appsv1.Deployment, len(deploymentList.Items))
for i := range deploymentList.Items {
deployments[i] = &deploymentList.Items[i]
}
return deployments
}

// GetCAPIResourcesInput is the input for GetCAPIResources.
type GetCAPIResourcesInput struct {
Lister framework.Lister
Lister Lister
Namespace string
}

Expand All @@ -88,7 +64,7 @@ func GetCAPIResources(ctx context.Context, input GetCAPIResourcesInput) []*unstr
if apierrors.IsNotFound(err) {
continue
}
ginkgo.Fail(fmt.Sprintf("failed to list %q resources: %v", typeList.GroupVersionKind(), err))
Fail(fmt.Sprintf("failed to list %q resources: %v", typeList.GroupVersionKind(), err))
}
for i := range typeList.Items {
obj := typeList.Items[i]
Expand All @@ -101,7 +77,7 @@ func GetCAPIResources(ctx context.Context, input GetCAPIResourcesInput) []*unstr

// getClusterAPITypes returns the list of TypeMeta to be considered for the the move discovery phase.
// This list includes all the types belonging to CAPI providers.
func getClusterAPITypes(ctx context.Context, lister framework.Lister) []metav1.TypeMeta {
func getClusterAPITypes(ctx context.Context, lister Lister) []metav1.TypeMeta {
discoveredTypes := []metav1.TypeMeta{}

crdList := &apiextensionsv1.CustomResourceDefinitionList{}
Expand All @@ -126,68 +102,9 @@ func getClusterAPITypes(ctx context.Context, lister framework.Lister) []metav1.T
return discoveredTypes
}

// GetClusterByNameInput is the input for GetClusterByName.
type GetClusterByNameInput struct {
Getter framework.Getter
Name string
Namespace string
}

// GetClusterByName returns a Cluster object given his name
func GetClusterByName(ctx context.Context, input GetClusterByNameInput) *clusterv1.Cluster {
cluster := &clusterv1.Cluster{}
key := client.ObjectKey{
Namespace: input.Namespace,
Name: input.Name,
}
Expect(input.Getter.Get(ctx, key, cluster)).To(Succeed(), "Failed to get Cluster object %s/%s", input.Namespace, input.Name)
return cluster
}

// GetKubeadmControlPlaneByClusterInput is the input for GetKubeadmControlPlaneByCluster.
type GetKubeadmControlPlaneByClusterInput struct {
Lister framework.Lister
ClusterName string
Namespace string
}

// GetKubeadmControlPlaneByCluster returns the KubeadmControlPlane objects for a cluster.
// Important! this method relies on labels that are created by the CAPI controllers during the first reconciliation, so
// it is necessary to ensure this is already happened before calling it.
func GetKubeadmControlPlaneByCluster(ctx context.Context, input GetKubeadmControlPlaneByClusterInput) *controlplanev1.KubeadmControlPlane {
controlPlaneList := &controlplanev1.KubeadmControlPlaneList{}
Expect(input.Lister.List(ctx, controlPlaneList, byClusterOptions(input.ClusterName, input.Namespace)...)).To(Succeed(), "Failed to list KubeadmControlPlane object for Cluster %s/%s", input.Namespace, input.ClusterName)
Expect(len(controlPlaneList.Items)).ToNot(BeNumerically(">", 1), "Cluster %s/%s should not have more than 1 KubeadmControlPlane object", input.Namespace, input.ClusterName)
if len(controlPlaneList.Items) == 1 {
return &controlPlaneList.Items[0]
}
return nil
}

// GetMachineDeploymentsByClusterInput is the input for GetMachineDeploymentsByCluster.
type GetMachineDeploymentsByClusterInput struct {
Lister framework.Lister
ClusterName string
Namespace string
}

// GetMachineDeploymentsByCluster returns the MachineDeployments objects for a cluster.
// Important! this method relies on labels that are created by the CAPI controllers during the first reconciliation, so
// it is necessary to ensure this is already happened before calling it.
func GetMachineDeploymentsByCluster(ctx context.Context, input GetMachineDeploymentsByClusterInput) []*clusterv1.MachineDeployment {
deploymentList := &clusterv1.MachineDeploymentList{}
Expect(input.Lister.List(ctx, deploymentList, byClusterOptions(input.ClusterName, input.Namespace)...)).To(Succeed(), "Failed to list MachineDeployments object for Cluster %s/%s", input.Namespace, input.ClusterName)

deployments := make([]*clusterv1.MachineDeployment, len(deploymentList.Items))
for i := range deploymentList.Items {
deployments[i] = &deploymentList.Items[i]
}
return deployments
}

// DumpAllResourcesInput is the input for DumpAllResources.
type DumpAllResourcesInput struct {
Lister framework.Lister
Lister Lister
Namespace string
LogPath string
}
Expand Down Expand Up @@ -238,12 +155,20 @@ func capiProviderOptions() []client.ListOption {
}
}

// byClusterOptions returns a set of ListOptions that allows to identify all the objects belonging to a Cluster.
func byClusterOptions(name, namespace string) []client.ListOption {
return []client.ListOption{
client.InNamespace(namespace),
client.MatchingLabels{
clusterv1.ClusterLabelName: name,
},
// CreateRelatedResourcesInput is the input type for CreateRelatedResources.
type CreateRelatedResourcesInput struct {
Creator Creator
RelatedResources []runtime.Object
}

// CreateRelatedResources is used to create runtime.Objects.
func CreateRelatedResources(ctx context.Context, input CreateRelatedResourcesInput, intervals ...interface{}) {
By("creating related resources")
for i := range input.RelatedResources {
obj := input.RelatedResources[i]
By(fmt.Sprintf("creating a/an %s resource", obj.GetObjectKind().GroupVersionKind()))
Eventually(func() error {
return input.Creator.Create(ctx, obj)
}, intervals...).Should(Succeed())
}
}
72 changes: 0 additions & 72 deletions test/framework/apply.go

This file was deleted.

144 changes: 144 additions & 0 deletions test/framework/cluster_helpers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/*
Copyright 2020 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package framework

import (
"context"
"fmt"

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"

apierrors "k8s.io/apimachinery/pkg/api/errors"
"sigs.k8s.io/cluster-api/test/framework/options"
"sigs.k8s.io/controller-runtime/pkg/client"

"k8s.io/apimachinery/pkg/runtime"
clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha3"
)

// CreateClusterInput is the input for CreateCluster.
type CreateClusterInput struct {
Creator Creator
Cluster *clusterv1.Cluster
InfraCluster runtime.Object
}

// CreateCluster will create the Cluster and InfraCluster objects.
func CreateCluster(ctx context.Context, input CreateClusterInput, intervals ...interface{}) {
By("creating an InfrastructureCluster resource")
Expect(input.Creator.Create(ctx, input.InfraCluster)).To(Succeed())

// This call happens in an eventually because of a race condition with the
// webhook server. If the latter isn't fully online then this call will
// fail.
By("creating a Cluster resource linked to the InfrastructureCluster resource")
Eventually(func() error {
if err := input.Creator.Create(ctx, input.Cluster); err != nil {
fmt.Printf("%+v\n", err)
return err
}
return nil
}, intervals...).Should(Succeed())
}

// GetClusterByNameInput is the input for GetClusterByName.
type GetClusterByNameInput struct {
Getter Getter
Name string
Namespace string
}

// GetClusterByName returns a Cluster object given his name
func GetClusterByName(ctx context.Context, input GetClusterByNameInput) *clusterv1.Cluster {
cluster := &clusterv1.Cluster{}
key := client.ObjectKey{
Namespace: input.Namespace,
Name: input.Name,
}
Expect(input.Getter.Get(ctx, key, cluster)).To(Succeed(), "Failed to get Cluster object %s/%s", input.Namespace, input.Name)
return cluster
}

// WaitForClusterToProvisionInput is the input for WaitForClusterToProvision.
type WaitForClusterToProvisionInput struct {
Getter Getter
Cluster *clusterv1.Cluster
}

// WaitForClusterToProvision will wait for a cluster to have a phase status of provisioned.
func WaitForClusterToProvision(ctx context.Context, input WaitForClusterToProvisionInput, intervals ...interface{}) {
By("waiting for cluster to enter the provisioned phase")
Eventually(func() (string, error) {
cluster := &clusterv1.Cluster{}
key := client.ObjectKey{
Namespace: input.Cluster.GetNamespace(),
Name: input.Cluster.GetName(),
}
if err := input.Getter.Get(ctx, key, cluster); err != nil {
return "", err
}
return cluster.Status.Phase, nil
}, intervals...).Should(Equal(string(clusterv1.ClusterPhaseProvisioned)))
}

// DeleteClusterInput is the input for DeleteCluster.
type DeleteClusterInput struct {
Deleter Deleter
Cluster *clusterv1.Cluster
}

// DeleteCluster deletes the cluster and waits for everything the cluster owned to actually be gone.
func DeleteCluster(ctx context.Context, input DeleteClusterInput) {
if options.SkipResourceCleanup {
return
}
By(fmt.Sprintf("deleting cluster %s", input.Cluster.GetName()))
Expect(input.Deleter.Delete(ctx, input.Cluster)).To(Succeed())
}

// WaitForClusterDeletedInput is the input for WaitForClusterDeleted.
type WaitForClusterDeletedInput struct {
Getter Getter
Cluster *clusterv1.Cluster
}

// WaitForClusterDeleted waits until the cluster object has been deleted.
func WaitForClusterDeleted(ctx context.Context, input WaitForClusterDeletedInput, intervals ...interface{}) {
if options.SkipResourceCleanup {
return
}
By(fmt.Sprintf("waiting for cluster %s to be deleted", input.Cluster.GetName()))
Eventually(func() bool {
cluster := &clusterv1.Cluster{}
key := client.ObjectKey{
Namespace: input.Cluster.GetNamespace(),
Name: input.Cluster.GetName(),
}
return apierrors.IsNotFound(input.Getter.Get(ctx, key, cluster))
}, intervals...).Should(BeTrue())
}

// byClusterOptions returns a set of ListOptions that allows to identify all the objects belonging to a Cluster.
func byClusterOptions(name, namespace string) []client.ListOption {
return []client.ListOption{
client.InNamespace(namespace),
client.MatchingLabels{
clusterv1.ClusterLabelName: name,
},
}
}
Loading

0 comments on commit f972a2c

Please sign in to comment.