diff --git a/docs/book/src/developer/providers/migrations/v1.5-to-v1.6.md b/docs/book/src/developer/providers/migrations/v1.5-to-v1.6.md index a464b924052c..838bcade9bf4 100644 --- a/docs/book/src/developer/providers/migrations/v1.5-to-v1.6.md +++ b/docs/book/src/developer/providers/migrations/v1.5-to-v1.6.md @@ -34,7 +34,7 @@ maintainers of providers and consumers of our Go API. ### Other - `clusterctl move` can be blocked temporarily by a provider when an object to be moved is annotated with `clusterctl.cluster.x-k8s.io/block-move`. - `mdbook releaselink` has been changed to require a `repo` tag when used in markdown files for generating a book with `mdbook`. - +- Workload cluster Node yaml is now being collected during e2e tests to assist with troubleshooting test failures. ### Suggested changes for providers - In order to reduce dependencies for API package consumers, CAPI has diverged from the default kubebuilder scheme builder. This new pattern may also be useful for reducing dependencies in provider API packages. For more information [see the implementers guide.](../implementers-guide/create_api.md#registering-apis-in-the-scheme) diff --git a/test/e2e/common.go b/test/e2e/common.go index 0e4990ed82bd..167481b57dfd 100644 --- a/test/e2e/common.go +++ b/test/e2e/common.go @@ -25,6 +25,7 @@ import ( . "github.com/onsi/ginkgo/v2" "github.com/onsi/gomega/types" corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/klog/v2" "sigs.k8s.io/controller-runtime/pkg/client" @@ -79,13 +80,24 @@ func dumpSpecResourcesAndCleanup(ctx context.Context, specName string, clusterPr LogPath: filepath.Join(artifactFolder, "clusters", clusterProxy.GetName(), "resources"), }) - // If the cluster still exists, dump kube-system pods of the workload cluster before deleting the cluster. + // If the cluster still exists, dump kube-system pods and nodes of the workload cluster before deleting the cluster. if err := clusterProxy.GetClient().Get(ctx, client.ObjectKeyFromObject(cluster), &clusterv1.Cluster{}); err == nil { - Byf("Dumping kube-system Pods of Cluster %s", klog.KObj(cluster)) - framework.DumpKubeSystemPodsForCluster(ctx, framework.DumpKubeSystemPodsForClusterInput{ + Byf("Dumping kube-system Pods and Nodes of Cluster %s", klog.KObj(cluster)) + framework.DumpResourcesForCluster(ctx, framework.DumpResourcesForClusterInput{ Lister: clusterProxy.GetWorkloadCluster(ctx, cluster.Namespace, cluster.Name).GetClient(), Cluster: cluster, LogPath: filepath.Join(artifactFolder, "clusters", cluster.Name, "resources"), + Resources: []framework.DumpVersionAndKind{ + { + APIVersion: corev1.SchemeGroupVersion.String(), + Kind: "Pod", + Namespace: metav1.NamespaceSystem, + }, + { + APIVersion: corev1.SchemeGroupVersion.String(), + Kind: "Node", + }, + }, }) } diff --git a/test/framework/alltypes_helpers.go b/test/framework/alltypes_helpers.go index d5ce38bb5f5c..ce1147786131 100644 --- a/test/framework/alltypes_helpers.go +++ b/test/framework/alltypes_helpers.go @@ -26,7 +26,6 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - corev1 "k8s.io/api/core/v1" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" apimeta "k8s.io/apimachinery/pkg/api/meta" @@ -132,38 +131,47 @@ func DumpAllResources(ctx context.Context, input DumpAllResourcesInput) { } } -// DumpKubeSystemPodsForClusterInput is the input for DumpKubeSystemPodsForCluster. -type DumpKubeSystemPodsForClusterInput struct { - Lister Lister - LogPath string - Cluster *clusterv1.Cluster +// DumpVersionAndKind specifies a version and kind which will be dumped +type DumpVersionAndKind struct { + APIVersion string + Kind string + Namespace string } -// DumpKubeSystemPodsForCluster dumps kube-system Pods to YAML. -func DumpKubeSystemPodsForCluster(ctx context.Context, input DumpKubeSystemPodsForClusterInput) { - Expect(ctx).NotTo(BeNil(), "ctx is required for DumpAllResources") - Expect(input.Lister).NotTo(BeNil(), "input.Lister is required for DumpAllResources") - Expect(input.Cluster).NotTo(BeNil(), "input.Cluster is required for DumpAllResources") - - // Note: We intentionally retrieve Pods as Unstructured because we need the Pods as Unstructured for dumpObject. - podList := new(unstructured.UnstructuredList) - podList.SetAPIVersion(corev1.SchemeGroupVersion.String()) - podList.SetKind("Pod") - var listErr error - _ = wait.PollUntilContextTimeout(ctx, retryableOperationInterval, retryableOperationTimeout, true, func(ctx context.Context) (bool, error) { - if listErr = input.Lister.List(ctx, podList, client.InNamespace(metav1.NamespaceSystem)); listErr != nil { - return false, nil //nolint:nilerr - } - return true, nil - }) - if listErr != nil { - // NB. we are treating failures in collecting kube-system pods as a non-blocking operation (best effort) - fmt.Printf("Failed to list Pods in kube-system for Cluster %s: %v\n", klog.KObj(input.Cluster), listErr) - return - } +// DumpResourcesForClusterInput is the input for DumpResourcesForClusterInput. +type DumpResourcesForClusterInput struct { + Lister Lister + LogPath string + Cluster *clusterv1.Cluster + Resources []DumpVersionAndKind +} - for i := range podList.Items { - dumpObject(&podList.Items[i], input.LogPath) +// DumpResourcesForCluster dumps specified resources to yaml. +func DumpResourcesForCluster(ctx context.Context, input DumpResourcesForClusterInput) { + Expect(ctx).NotTo(BeNil(), "ctx is required for DumpResourcesForCluster") + Expect(input.Lister).NotTo(BeNil(), "input.Lister is required for DumpResourcesForCluster") + Expect(input.Cluster).NotTo(BeNil(), "input.Cluster is required for DumpResourcesForCluster") + + for _, resource := range input.Resources { + // Note: We intentionally retrieve resources as Unstructured because we need the resources as Unstructured for dumpObject. + resourceList := new(unstructured.UnstructuredList) + resourceList.SetAPIVersion(resource.APIVersion) + resourceList.SetKind(resource.Kind) + var listErr error + _ = wait.PollUntilContextTimeout(ctx, retryableOperationInterval, retryableOperationTimeout, true, func(ctx context.Context) (bool, error) { + if listErr = input.Lister.List(ctx, resourceList, client.InNamespace(resource.Namespace)); listErr != nil { + return false, nil //nolint:nilerr + } + return true, nil + }) + if listErr != nil { + // NB. we are treating failures in collecting resources as a non-blocking operation (best effort) + fmt.Printf("Failed to list %s for Cluster %s: %v\n", resource.Kind, klog.KObj(input.Cluster), listErr) + continue + } + for i := range resourceList.Items { + dumpObject(&resourceList.Items[i], input.LogPath) + } } }