Skip to content

Commit

Permalink
Merge pull request #2894 from fabriziopandini/e2e-dump-all-resources
Browse files Browse the repository at this point in the history
🏃[e2e]: dump all resources
  • Loading branch information
k8s-ci-robot authored Apr 10, 2020
2 parents efe6b70 + beea8d8 commit a9c8bf9
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 1 deletion.
4 changes: 3 additions & 1 deletion test/framework/convenience.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ import (
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
rbacv1 "k8s.io/api/rbac/v1"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
apiextensionsv1beta "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
Expand Down Expand Up @@ -110,6 +111,7 @@ func TryAddDefaultSchemes(scheme *runtime.Scheme) {
_ = controlplanev1.AddToScheme(scheme)

// Add the api extensions (CRD) to the scheme.
_ = apiextensionsv1beta.AddToScheme(scheme)
_ = apiextensionsv1.AddToScheme(scheme)

// Add rbac to the scheme.
Expand Down
123 changes: 123 additions & 0 deletions test/framework/discovery/discovery.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,27 @@ package discovery

import (
"context"
"fmt"
"io/ioutil"
"os"
"path"
"path/filepath"

"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.
Expand All @@ -49,6 +62,70 @@ func GetControllerDeployments(ctx context.Context, input GetControllerDeployment
return deployments
}

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

// GetCAPIResources reads all the CAPI resources in a namespace.
// This list includes all the types belonging to CAPI providers.
func GetCAPIResources(ctx context.Context, input GetCAPIResourcesInput) []*unstructured.Unstructured {
Expect(ctx).NotTo(BeNil(), "ctx is required for GetCAPIResources")
Expect(input.Lister).NotTo(BeNil(), "input.Deleter is required for GetCAPIResources")
Expect(input.Namespace).NotTo(BeEmpty(), "input.Namespace is required for GetCAPIResources")

types := getClusterAPITypes(ctx, input.Lister)

objList := []*unstructured.Unstructured{}
for i := range types {
typeMeta := types[i]
typeList := new(unstructured.UnstructuredList)
typeList.SetAPIVersion(typeMeta.APIVersion)
typeList.SetKind(typeMeta.Kind)

if err := input.Lister.List(ctx, typeList, client.InNamespace(input.Namespace)); err != nil {
if apierrors.IsNotFound(err) {
continue
}
ginkgo.Fail(fmt.Sprintf("failed to list %q resources: %v", typeList.GroupVersionKind(), err))
}
for i := range typeList.Items {
obj := typeList.Items[i]
objList = append(objList, &obj)
}
}

return objList
}

// 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 {
discoveredTypes := []metav1.TypeMeta{}

crdList := &apiextensionsv1.CustomResourceDefinitionList{}
err := lister.List(ctx, crdList, capiProviderOptions()...)
Expect(err).ToNot(HaveOccurred(), "failed to list CRDs for CAPI providers")

for _, crd := range crdList.Items {
for _, version := range crd.Spec.Versions {
if !version.Storage {
continue
}

discoveredTypes = append(discoveredTypes, metav1.TypeMeta{
Kind: crd.Spec.Names.Kind,
APIVersion: metav1.GroupVersion{
Group: crd.Spec.Group,
Version: version.Name,
}.String(),
})
}
}
return discoveredTypes
}

// GetClusterByNameInput is the input for GetClusterByName.
type GetClusterByNameInput struct {
Getter framework.Getter
Expand Down Expand Up @@ -108,6 +185,52 @@ func GetMachineDeploymentsByCluster(ctx context.Context, input GetMachineDeploym
return deployments
}

// DumpAllResourcesInput is the input for DumpAllResources.
type DumpAllResourcesInput struct {
Lister framework.Lister
Namespace string
LogPath string
}

// DumpAllResources dumps Cluster API related resources to YAML
// This dump includes all the types belonging to CAPI providers.
func DumpAllResources(ctx context.Context, input DumpAllResourcesInput) {
Expect(ctx).NotTo(BeNil(), "ctx is required for DumpAllResources")
Expect(input.Lister).NotTo(BeNil(), "input.Deleter is required for DumpAllResources")
Expect(input.Namespace).NotTo(BeEmpty(), "input.Namespace is required for DumpAllResources")

resources := GetCAPIResources(ctx, GetCAPIResourcesInput{
Lister: input.Lister,
Namespace: input.Namespace,
})

for i := range resources {
r := resources[i]
dumpObject(r, input.LogPath)
}
}

func dumpObject(resource runtime.Object, logPath string) {
resourceYAML, err := yaml.Marshal(resource)
Expect(err).ToNot(HaveOccurred(), "Failed to marshal %s", resource.GetObjectKind().GroupVersionKind().String())

metaObj, err := apimeta.Accessor(resource)
Expect(err).ToNot(HaveOccurred(), "Failed to get accessor for %s", resource.GetObjectKind().GroupVersionKind().String())

kind := resource.GetObjectKind().GroupVersionKind().Kind
namespace := metaObj.GetNamespace()
name := metaObj.GetName()

resourceFilePath := path.Join(logPath, namespace, kind, name+".yaml")
Expect(os.MkdirAll(filepath.Dir(resourceFilePath), 0755)).To(Succeed(), "Failed to create folder %s", filepath.Dir(resourceFilePath))

f, err := os.OpenFile(resourceFilePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
Expect(err).ToNot(HaveOccurred(), "Failed to open %s", resourceFilePath)
defer f.Close()

Expect(ioutil.WriteFile(f.Name(), resourceYAML, 0644)).To(Succeed(), "Failed to write %s", resourceFilePath)
}

// 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{
Expand Down
2 changes: 2 additions & 0 deletions test/framework/dump_resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import (
)

// DumpResources dump cluster API related resources to YAML
// Deprecated. Please use DumpAllResources instead
func DumpResources(mgmt ManagementCluster, resourcePath string, writer io.Writer) error {
resources := map[string]runtime.Object{
"Cluster": &clusterv1.ClusterList{},
Expand All @@ -53,6 +54,7 @@ func DumpResources(mgmt ManagementCluster, resourcePath string, writer io.Writer
}

// DumpProviderResources dump provider specific API related resources to YAML
// Deprecated. Please use DumpAllResources instead
func DumpProviderResources(mgmt ManagementCluster, resources map[string]runtime.Object, resourcePath string, writer io.Writer) error {
return dumpResources(mgmt, resources, resourcePath, writer)
}
Expand Down

0 comments on commit a9c8bf9

Please sign in to comment.