Ctrl K
ComunidadGuías…

internal/rbac/read.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
package rbac

import (
	"context"
	"strings"
	"sync"

	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"

	"github.com/sophotechlabs/spinoza/internal/api"
	"github.com/sophotechlabs/spinoza/internal/safe"
)

const Group = "rbac.authorization.k8s.io"

type Lister interface {
	List(ctx context.Context, desc api.ResourceDescriptor) ([]*unstructured.Unstructured, error)
	Warm(ctx context.Context, descs []api.ResourceDescriptor)
}

var wanted = []string{"roles", "clusterroles", "rolebindings", "clusterrolebindings"}

func Read(ctx context.Context, lister Lister, descs map[string]api.ResourceDescriptor) Index {
	found, absent := kinds(descs)
	lister.Warm(ctx, found)
	held := Held{}
	trouble := []string{}
	var reading sync.Mutex
	var asking sync.WaitGroup
	for _, desc := range found {
		asking.Add(1)
		safe.Go("reading RBAC "+desc.Resource, func() {
			defer asking.Done()
			defer func() {
				caught := recover()
				if caught == nil {
					return
				}
				safe.Log("reading RBAC "+desc.Resource, caught)
				reading.Lock()
				trouble = append(trouble, desc.Resource+": spinoza could not finish reading this resource")
				reading.Unlock()
			}()
			objects, err := lister.List(ctx, desc)
			reading.Lock()
			defer reading.Unlock()
			if err != nil {
				trouble = append(trouble, desc.Resource+": "+err.Error())
				return
			}
			place(&held, desc.Resource, objects)
		})
	}
	asking.Wait()
	index := Build(held)
	index.Error = joined(trouble, absent)
	return index
}

func place(held *Held, resource string, objects []*unstructured.Unstructured) {
	switch resource {
	case "roles":
		held.Roles = objects
	case "clusterroles":
		held.ClusterRoles = objects
	case "rolebindings":
		held.Bindings = objects
	case "clusterrolebindings":
		held.ClusterBinds = objects
	default:
	}
}

func kinds(descs map[string]api.ResourceDescriptor) (found []api.ResourceDescriptor, absent []string) {
	for _, want := range wanted {
		desc, ok := matching(descs, want)
		if !ok {
			absent = append(absent, want)
			continue
		}
		found = append(found, desc)
	}
	return found, absent
}

func matching(descs map[string]api.ResourceDescriptor, resource string) (api.ResourceDescriptor, bool) {
	for _, desc := range descs {
		if desc.Group == Group && desc.Resource == resource {
			return desc, true
		}
	}
	return api.ResourceDescriptor{}, false
}

func joined(trouble, absent []string) string {
	parts := trouble
	if len(absent) > 0 {
		parts = append(parts, "not discovered: "+strings.Join(absent, ", "))
	}
	return strings.Join(parts, " · ")
}