Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🏃[e2e] clusterctl e2e discovery #2820

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 126 additions & 0 deletions test/framework/discovery/discovery.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
// +build e2e

/*
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 discovery

import (
"context"

. "github.com/onsi/gomega"

appsv1 "k8s.io/api/apps/v1"
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"
)

// 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
}

// 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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this rely on the owner ref, instead of labels?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK ownerRef can't be used as a filter option for List.
Additionally, also ownerRef are set by CPAI controller during first reconciliation, so the same note will apply no matter of the change

// 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
}

// capiProviderOptions returns a set of ListOptions that allows to identify all the objects belonging to Cluster API providers.
func capiProviderOptions() []client.ListOption {
return []client.ListOption{
client.HasLabels{clusterv1.ProviderLabelName},
}
}

// 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,
},
}
}
33 changes: 33 additions & 0 deletions test/framework/management_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ import (

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
"sigs.k8s.io/controller-runtime/pkg/client"

"k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/cluster-api/test/framework/management/kind"
Expand Down Expand Up @@ -125,3 +128,33 @@ func InitManagementCluster(ctx context.Context, input *InitManagementClusterInpu

return managementCluster
}

// WaitForDeploymentsAvailableInput is the input for WaitForDeploymentsAvailable.
type WaitForDeploymentsAvailableInput struct {
Getter Getter
Deployment *appsv1.Deployment
}

// WaitForDeploymentsAvailable waits until the Deployment has status.Available = True, that signals that
// all the desired replicas are in place.
// This can be used to check if Cluster API controllers installed in the management cluster are working.
func WaitForDeploymentsAvailable(ctx context.Context, input WaitForDeploymentsAvailableInput, intervals ...interface{}) {
By(fmt.Sprintf("waiting for deployment %s/%s to be available", input.Deployment.GetNamespace(), input.Deployment.GetName()))
Eventually(func() bool {
deployment := &appsv1.Deployment{}
key := client.ObjectKey{
Namespace: input.Deployment.GetNamespace(),
Name: input.Deployment.GetName(),
}
if err := input.Getter.Get(ctx, key, deployment); err != nil {
return false
}
for _, c := range deployment.Status.Conditions {
if c.Type == appsv1.DeploymentAvailable && c.Status == corev1.ConditionTrue {
return true
}
}
return false

}, intervals...).Should(BeTrue(), "Deployment %s/%s failed to get status.Available = True condition")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this have been a fmt.Sprintf("Deployment %s/%s failed to get status.Available = True condition", input.Deployment.GetNamespace(), input.Deployment.GetName())

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wfernandes good catch!
fixed by #2864

}