Skip to content

Commit

Permalink
add controllers that have zero pods (#41)
Browse files Browse the repository at this point in the history
  • Loading branch information
rbren authored Sep 29, 2022
1 parent ebf65cb commit e5e18ba
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 4 deletions.
42 changes: 40 additions & 2 deletions pkg/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,23 @@ import (
"github.com/fairwindsops/controller-utils/pkg/log"
)

type knownKind struct {
kind string
apiVersion string
}

var knownKinds = []knownKind{{
"Deployment", "apps/v1",
}, {
"CronJob", "batch/v1",
}, {
"Job", "batch/v1",
}, {
"DaemonSet", "apps/v1",
}, {
"StatefulSet", "apps/v1",
}}

// Workload represents a workload in the cluster. It contains the top level object and all of the pods.
type Workload struct {
TopController unstructured.Unstructured
Expand All @@ -48,14 +65,34 @@ func getAllPods(ctx context.Context, dynamicClient dynamic.Interface, restMapper
return pods.Items, nil
}

func prepCacheWithKnownControllers(ctx context.Context, dynamicClient dynamic.Interface, restMapper meta.RESTMapper, namespace string, objectCache map[string]unstructured.Unstructured) error {
for _, kind := range knownKinds {
err := cacheAllObjectsOfKind(ctx, kind.apiVersion, kind.kind, namespace, dynamicClient, restMapper, objectCache)
if err != nil {
log.GetLogger().V(3).Info("Unable to prime cache with objects of kind " + kind.kind)
}
}
return nil
}

// GetAllTopControllers returns the highest level owning object of all pods. If a namespace is provided than this is limited to that namespace.
func GetAllTopControllers(ctx context.Context, dynamicClient dynamic.Interface, restMapper meta.RESTMapper, namespace string) ([]Workload, error) {
workloadMap := map[string]Workload{}
objectCache := map[string]unstructured.Unstructured{}
err := prepCacheWithKnownControllers(ctx, dynamicClient, restMapper, namespace, objectCache)
if err != nil {
return nil, err
}
for _, controller := range objectCache {
key := getControllerKey(controller)
workloadMap[key] = Workload{
TopController: controller,
}
}
pods, err := getAllPods(ctx, dynamicClient, restMapper, namespace)
if err != nil {
return nil, err
}
workloadMap := map[string]Workload{}
objectCache := map[string]unstructured.Unstructured{}
// TODO avoid cycling over multiple pods with the same parent
for _, pod := range pods {
controller, err := GetTopController(ctx, dynamicClient, restMapper, pod, objectCache)
Expand Down Expand Up @@ -157,6 +194,7 @@ func GetTopController(ctx context.Context, dynamicClient dynamic.Interface, rest
}

func cacheAllObjectsOfKind(ctx context.Context, apiVersion, kind, namespace string, dynamicClient dynamic.Interface, restMapper meta.RESTMapper, objectCache map[string]unstructured.Unstructured) error {
fmt.Println("cache all", apiVersion, kind)
fqKind := schema.FromAPIVersionAndKind(apiVersion, kind)
mapping, err := restMapper.RESTMapping(fqKind.GroupKind(), fqKind.Version)
if err != nil {
Expand Down
16 changes: 14 additions & 2 deletions pkg/controller/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,16 @@ func setupFakeData(t *testing.T) (dynamicPkg.Interface, meta.RESTMapper, unstruc
},
},
}
depNoPods := unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": map[string]interface{}{
"name": "dep-no-pods",
"namespace": "test",
},
},
}
dynamic := fake.NewSimpleDynamicClientWithCustomListKinds(runtime.NewScheme(),
map[schema.GroupVersionResource]string{
{Group: "apps", Version: "v1", Resource: "replicasets"}: "ReplicaSetList",
Expand All @@ -129,6 +139,8 @@ func setupFakeData(t *testing.T) (dynamicPkg.Interface, meta.RESTMapper, unstruc
assert.NoError(t, err)
_, err = dynamic.Resource(mapping.Resource).Namespace("test").Create(context.TODO(), &dep, metav1.CreateOptions{})
assert.NoError(t, err)
_, err = dynamic.Resource(mapping.Resource).Namespace("test").Create(context.TODO(), &depNoPods, metav1.CreateOptions{})
assert.NoError(t, err)
return dynamic, restMapper, pod, rs, dep, pod2
}

Expand All @@ -151,8 +163,8 @@ func TestGetAllTopControllers(t *testing.T) {
dynamic, restMapper, _, _, _, _ := setupFakeData(t)
controllers, err := GetAllTopControllers(context.TODO(), dynamic, restMapper, "")
assert.NoError(t, err)
assert.Equal(t, 2, len(controllers))
assert.Equal(t, 3, len(controllers))
controllers, err = GetAllTopControllers(context.TODO(), dynamic, restMapper, "test")
assert.NoError(t, err)
assert.Equal(t, 1, len(controllers))
assert.Equal(t, 2, len(controllers))
}

0 comments on commit e5e18ba

Please sign in to comment.