Skip to content

Commit

Permalink
custom boards
Browse files Browse the repository at this point in the history
  • Loading branch information
Frank Jogeleit committed Dec 21, 2023
1 parent b0b481b commit 2f8eb92
Show file tree
Hide file tree
Showing 31 changed files with 519 additions and 326 deletions.
1 change: 1 addition & 0 deletions backend/cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ func newRunCMD() *cobra.Command {
cmd.Flags().IntVar(&c.Server.Port, "port", 8080, "PolicyReporter UI port")
cmd.Flags().BoolVar(&c.Server.CORS, "dev", false, "Enable CORS Header for development")
cmd.Flags().BoolVar(&c.UI.Disabled, "no-ui", false, "Disable the embedded frontend")
cmd.Flags().BoolVar(&c.Cluster, "cluster", false, "use kube config to connect to cluster")
flag.Parse()

return cmd
Expand Down
36 changes: 29 additions & 7 deletions backend/pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,35 @@ type Server struct {
OverwriteHost bool `mapstructure:"overwriteHost"`
}

type Source struct {
Name string `mapstructure:"name"`
Excludes struct {
NamespaceKinds []string `mapstructure:"namespaceKinds"`
ClusterKinds []string `mapstructure:"clusterKinds"`
} `mapstructure:"excludes"`
}

type CustomBoard struct {
Name string `mapstructure:"name"`
Namespaces struct {
Selector map[string]string `mapstructure:"selector"`
List []string `mapstructure:"list"`
} `mapstructure:"namespaces"`
Sources struct {
List []string `mapstructure:"list"`
} `mapstructure:"sources"`
}

// Config structure
type Config struct {
KubeConfig clientcmd.ConfigOverrides
Namespace string `mapstructure:"namespace"`
Clusters []Cluster `mapstructure:"clusters"`
Server Server `mapstructure:"server"`
UI UI `mapstructure:"ui"`
Logging logging.Config `mapstructure:"logging"`
Redis redis.Config `mapstructure:"redis"`
KubeConfig clientcmd.ConfigOverrides
Namespace string `mapstructure:"namespace"`
Clusters []Cluster `mapstructure:"clusters"`
Sources []Source `mapstructure:"sources"`
Server Server `mapstructure:"server"`
UI UI `mapstructure:"ui"`
Logging logging.Config `mapstructure:"logging"`
Redis redis.Config `mapstructure:"redis"`
CustomBoards []CustomBoard `mapstructure:"customBoards"`
Cluster bool `mapstructure:"cluster"`
}
10 changes: 10 additions & 0 deletions backend/pkg/config/mapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"github.com/gosimple/slug"

"github.com/kyverno/policy-reporter-ui/pkg/server/api"
"github.com/kyverno/policy-reporter-ui/pkg/utils"
)

func MapConfig(c *Config) api.Config {
Expand Down Expand Up @@ -33,5 +34,14 @@ func MapConfig(c *Config) api.Config {
Resources: c.UI.DefaultFilter.Resources,
ClusterResources: c.UI.DefaultFilter.ClusterResources,
},
Sources: utils.Map(c.Sources, func(s Source) api.Source {
return api.Source{
Name: s.Name,
Excludes: api.Excludes{
NamespaceKinds: s.Excludes.NamespaceKinds,
ClusterKinds: s.Excludes.ClusterKinds,
},
}
}),
}
}
87 changes: 83 additions & 4 deletions backend/pkg/config/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,17 @@ import (

"github.com/gin-contrib/cors"
"github.com/gin-gonic/gin"
"github.com/gosimple/slug"
"go.uber.org/zap"
k8s "k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"

"github.com/kyverno/policy-reporter-ui/pkg/kubernetes/namespaces"
"github.com/kyverno/policy-reporter-ui/pkg/kubernetes/secrets"
"github.com/kyverno/policy-reporter-ui/pkg/logging"
"github.com/kyverno/policy-reporter-ui/pkg/proxy"
"github.com/kyverno/policy-reporter-ui/pkg/server"
"github.com/kyverno/policy-reporter-ui/pkg/server/api"
"github.com/kyverno/policy-reporter-ui/pkg/utils"
)

Expand All @@ -29,7 +32,11 @@ type Resolver struct {
kubeConfig string
devMode bool

secrets secrets.Client
secrets secrets.Client
namespaces namespaces.Client

k8sConfig *rest.Config
clientset *k8s.Clientset
}

func (r *Resolver) ExternalProxies(ctx context.Context, cluster Cluster) (map[string]*httputil.ReverseProxy, error) {
Expand Down Expand Up @@ -123,20 +130,65 @@ func (r *Resolver) LoadSecret(ctx context.Context, secretRef string) (secrets.Va
return values, nil
}

func (r *Resolver) InitSecretClient() error {
func (r *Resolver) K8sConfig() (*rest.Config, error) {
if r.k8sConfig != nil {
return r.k8sConfig, nil
}

var k8sConfig *rest.Config
var err error

if r.config.KubeConfig.CurrentContext != "" {
if r.config.Cluster {
k8sConfig, err = utils.RestConfig(r.config.KubeConfig)
} else {
k8sConfig, err = rest.InClusterConfig()
}
if err != nil {
return err
return nil, err
}

r.k8sConfig = k8sConfig

return r.k8sConfig, nil
}

func (r *Resolver) Clientset() (*k8s.Clientset, error) {
if r.clientset != nil {
return r.clientset, nil
}

k8sConfig, err := r.K8sConfig()
if err != nil {
return nil, err
}

clientset, err := k8s.NewForConfig(k8sConfig)
if err != nil {
return nil, err
}

r.clientset = clientset

return r.clientset, nil
}

func (r *Resolver) NamespaceClient() (namespaces.Client, error) {
if r.namespaces != nil {
return r.namespaces, nil
}

clientset, err := r.Clientset()
if err != nil {
return nil, err
}

r.namespaces = namespaces.NewClient(clientset.CoreV1().Namespaces())

return r.namespaces, nil
}

func (r *Resolver) InitSecretClient() error {
clientset, err := r.Clientset()
if err != nil {
return err
}
Expand Down Expand Up @@ -174,6 +226,33 @@ func (r *Resolver) Server(ctx context.Context) *server.Server {

serv.RegisterAPI(MapConfig(r.config))

if len(r.config.CustomBoards) > 0 {
client, err := r.NamespaceClient()
if err != nil {
zap.L().Error("failed to create namespace client", zap.Error(err))

return serv
}

configs := make(map[string]api.CustomBoard, len(r.config.CustomBoards))
for _, c := range r.config.CustomBoards {
id := slug.Make(c.Name)

configs[id] = api.CustomBoard{
Name: c.Name,
ID: id,
Namespaces: api.Namespaces{
Selector: c.Namespaces.Selector,
List: c.Namespaces.List,
},
Sources: api.Sources{
List: c.Sources.List,
}}
}

serv.RegisterCustomBoards(client, configs)
}

return serv
}

Expand Down
30 changes: 3 additions & 27 deletions backend/pkg/kubernetes/secrets/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@ import (
"context"
"strconv"

"github.com/kyverno/policy-reporter-ui/pkg/kubernetes"
"go.uber.org/zap"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
v1 "k8s.io/client-go/kubernetes/typed/core/v1"
"k8s.io/client-go/util/retry"
)

type Values struct {
Expand All @@ -30,31 +29,8 @@ type k8sClient struct {
}

func (c *k8sClient) Get(ctx context.Context, name string) (Values, error) {
var secret *corev1.Secret

err := retry.OnError(retry.DefaultRetry, func(err error) bool {
if _, ok := err.(errors.APIStatus); !ok {
return true
}

if ok := errors.IsTimeout(err); ok {
return true
}

if ok := errors.IsServerTimeout(err); ok {
return true
}

if ok := errors.IsServiceUnavailable(err); ok {
return true
}

return false
}, func() error {
var err error
secret, err = c.client.Get(ctx, name, metav1.GetOptions{})

return err
secret, err := kubernetes.Retry(func() (*corev1.Secret, error) {
return c.client.Get(ctx, name, metav1.GetOptions{})
})

values := Values{}
Expand Down
30 changes: 0 additions & 30 deletions backend/pkg/server/api/handler.go

This file was deleted.

8 changes: 8 additions & 0 deletions backend/pkg/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/gosimple/slug"

"github.com/kyverno/policy-reporter-ui/pkg/kubernetes/namespaces"
"github.com/kyverno/policy-reporter-ui/pkg/server/api"
)

Expand Down Expand Up @@ -48,6 +49,13 @@ func (s *Server) RegisterCluster(name string, proxies map[string]*httputil.Rever
}
}

func (s *Server) RegisterCustomBoards(client namespaces.Client, configs map[string]api.CustomBoard) {
handler := api.NewCustomBoardHandler(client, configs)

s.api.GET("custom-board/list", handler.List)
s.api.GET("custom-board/:id/details", handler.Details)
}

func (s *Server) RegisterAPI(c api.Config) {
s.api.GET("config", api.ConfigHandler(c))
}
Expand Down
9 changes: 1 addition & 8 deletions frontend/app.vue
Original file line number Diff line number Diff line change
@@ -1,18 +1,11 @@
<template>
<NuxtLayout :key="cluster">
<NuxtPage :sources="sources" />
<NuxtPage />
</NuxtLayout>
</template>

<script lang="ts" setup>
import { useAPI } from "~/modules/core/composables/api";
import { cluster } from "~/modules/core/api";
const { data: sources } = useAPI(
(api) => api.sources().then((source) => source.map(s => s.name)),
{ default: () => [] }
);
</script>

<style>
Expand Down
66 changes: 66 additions & 0 deletions frontend/composables/infinite.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import type { Ref, UnwrapRef } from "vue";
import type { UnwrapRefSimple } from "@vue/reactivity";

export const useInfinite = <T>(list: Ref<T[] | null>) => {
const loaded = ref<T[]>([])
const index = ref(1)

watch(list, (l) => {
if (!list.value?.length) return

loaded.value = (l || []).slice(0, 1) as UnwrapRefSimple<T>[]
}, { immediate: true })

const load = ({ done }: any) => {
const sum = (list.value || []).length
if (!sum) { return done('ok') }

if (sum === 1) { return done('empty') }

const last = index.value
const next = index.value + 2 > sum ? sum : index.value + 2
loaded.value = [...loaded.value, ...(list.value || []).slice(last, next)] as UnwrapRefSimple<T>[]

index.value = next
if (next === sum) {
done('empty')
} else {
done('ok')
}
}


return { load, loaded }
}

export const useInfiniteScroll = <T>(list: T[]) => {
const loaded = ref<T[]>([])
const index = ref(1)

watch(list, (l) => {
if (!list.length) return

loaded.value = (l || []).slice(0, 1) as UnwrapRefSimple<T>[]
}, { immediate: true })

const load = ({ done }: any) => {
const sum = (list || []).length
if (!sum) { return done('ok') }

if (sum === 1) { return done('empty') }

const last = index.value
const next = index.value + 2 > sum ? sum : index.value + 2
loaded.value = [...loaded.value, ...(list || []).slice(last, next)] as UnwrapRefSimple<T>[]

index.value = next
if (next === sum) {
done('empty')
} else {
done('ok')
}
}


return { load, loaded }
}
Loading

0 comments on commit 2f8eb92

Please sign in to comment.