2021-02-27 18:11:49 +00:00
|
|
|
package cmd
|
|
|
|
|
|
|
|
import (
|
2022-07-25 15:34:41 +00:00
|
|
|
"context"
|
2023-05-02 09:00:14 +00:00
|
|
|
"errors"
|
2021-02-27 18:11:49 +00:00
|
|
|
"flag"
|
2021-12-13 15:02:40 +00:00
|
|
|
|
2021-02-27 18:11:49 +00:00
|
|
|
"github.com/spf13/cobra"
|
2023-03-16 13:38:24 +00:00
|
|
|
"go.uber.org/zap"
|
2022-07-03 21:49:16 +00:00
|
|
|
"golang.org/x/sync/errgroup"
|
2021-03-05 13:26:47 +00:00
|
|
|
"k8s.io/client-go/rest"
|
|
|
|
"k8s.io/client-go/tools/clientcmd"
|
2023-02-08 14:53:59 +00:00
|
|
|
|
2024-10-07 09:10:46 +00:00
|
|
|
"github.com/kyverno/policy-reporter/pkg/api"
|
|
|
|
v1 "github.com/kyverno/policy-reporter/pkg/api/v1"
|
|
|
|
v2 "github.com/kyverno/policy-reporter/pkg/api/v2"
|
2023-02-08 14:53:59 +00:00
|
|
|
"github.com/kyverno/policy-reporter/pkg/config"
|
2023-05-02 09:00:14 +00:00
|
|
|
"github.com/kyverno/policy-reporter/pkg/database"
|
2023-02-08 14:53:59 +00:00
|
|
|
"github.com/kyverno/policy-reporter/pkg/listener"
|
2021-02-27 18:11:49 +00:00
|
|
|
)
|
|
|
|
|
2023-05-02 09:00:14 +00:00
|
|
|
func newRunCMD(version string) *cobra.Command {
|
2021-02-27 18:11:49 +00:00
|
|
|
cmd := &cobra.Command{
|
|
|
|
Use: "run",
|
|
|
|
Short: "Run PolicyReporter Watcher & HTTP Metrics Server",
|
|
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
2022-07-03 21:49:16 +00:00
|
|
|
c, err := config.Load(cmd)
|
2021-02-27 18:11:49 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2023-05-02 09:00:14 +00:00
|
|
|
c.Version = version
|
2021-02-27 18:11:49 +00:00
|
|
|
|
2021-03-05 13:26:47 +00:00
|
|
|
var k8sConfig *rest.Config
|
2023-02-20 10:28:59 +00:00
|
|
|
if c.K8sClient.Kubeconfig != "" {
|
|
|
|
k8sConfig, err = clientcmd.BuildConfigFromFlags("", c.K8sClient.Kubeconfig)
|
2021-03-05 13:26:47 +00:00
|
|
|
} else {
|
|
|
|
k8sConfig, err = rest.InClusterConfig()
|
|
|
|
}
|
2021-02-27 18:11:49 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2023-02-20 10:28:59 +00:00
|
|
|
k8sConfig.QPS = c.K8sClient.QPS
|
|
|
|
k8sConfig.Burst = c.K8sClient.Burst
|
|
|
|
|
2023-05-02 09:00:14 +00:00
|
|
|
readinessProbe := config.NewReadinessProbe(c)
|
2024-10-07 09:10:46 +00:00
|
|
|
defer readinessProbe.Close()
|
|
|
|
|
2021-03-05 13:26:47 +00:00
|
|
|
resolver := config.NewResolver(c, k8sConfig)
|
2023-03-16 13:38:24 +00:00
|
|
|
logger, err := resolver.Logger()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-03-05 13:26:47 +00:00
|
|
|
|
2021-12-13 15:02:40 +00:00
|
|
|
client, err := resolver.PolicyReportClient()
|
2021-02-27 18:11:49 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2024-10-07 09:10:46 +00:00
|
|
|
secretInformer, err := resolver.SecretInformer()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-06-29 08:43:59 +00:00
|
|
|
|
2021-12-13 15:02:40 +00:00
|
|
|
g := &errgroup.Group{}
|
2021-02-27 18:11:49 +00:00
|
|
|
|
2023-05-02 09:00:14 +00:00
|
|
|
var store *database.Store
|
2024-10-07 09:10:46 +00:00
|
|
|
servOptions := []api.ServerOption{
|
|
|
|
api.WithPort(c.API.Port),
|
|
|
|
api.WithHealthChecks([]api.HealthCheck{
|
|
|
|
func() error {
|
|
|
|
if !client.HasSynced() {
|
|
|
|
return errors.New("informer not ready")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
}
|
2023-05-02 09:00:14 +00:00
|
|
|
|
2021-12-13 15:02:40 +00:00
|
|
|
if c.REST.Enabled {
|
2023-05-02 09:00:14 +00:00
|
|
|
db := resolver.Database()
|
|
|
|
if db == nil {
|
|
|
|
return errors.New("unable to create database connection")
|
2021-12-13 15:02:40 +00:00
|
|
|
}
|
|
|
|
defer db.Close()
|
2021-03-05 13:26:47 +00:00
|
|
|
|
2024-10-07 09:10:46 +00:00
|
|
|
store, err = resolver.Store(db)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
nsClient, err := resolver.NamespaceClient()
|
2021-12-13 15:02:40 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-02-27 18:11:49 +00:00
|
|
|
|
2023-05-02 09:00:14 +00:00
|
|
|
if !c.LeaderElection.Enabled || store.IsSQLite() {
|
|
|
|
store.PrepareDatabase(cmd.Context())
|
|
|
|
resolver.RegisterStoreListener(cmd.Context(), store)
|
|
|
|
}
|
|
|
|
|
2023-03-16 13:38:24 +00:00
|
|
|
logger.Info("REST api enabled")
|
2024-10-07 09:10:46 +00:00
|
|
|
servOptions = append(servOptions, v1.WithAPI(store, resolver.TargetClients(), resolver.ViolationsReporter()), v2.WithAPI(store, nsClient, c.Targets))
|
2021-12-13 15:02:40 +00:00
|
|
|
}
|
2021-03-13 18:56:38 +00:00
|
|
|
|
2021-12-13 15:02:40 +00:00
|
|
|
if c.Metrics.Enabled {
|
2023-03-16 13:38:24 +00:00
|
|
|
logger.Info("metrics enabled")
|
2021-12-13 15:02:40 +00:00
|
|
|
resolver.RegisterMetricsListener()
|
2024-10-07 09:10:46 +00:00
|
|
|
servOptions = append(servOptions, api.WithMetrics())
|
2021-12-13 15:02:40 +00:00
|
|
|
}
|
2021-04-24 10:32:15 +00:00
|
|
|
|
2022-05-13 08:59:32 +00:00
|
|
|
if c.Profiling.Enabled {
|
2023-03-16 13:38:24 +00:00
|
|
|
logger.Info("pprof profiling enabled")
|
2024-10-07 09:10:46 +00:00
|
|
|
servOptions = append(servOptions, api.WithProfiling())
|
2022-05-13 08:59:32 +00:00
|
|
|
}
|
|
|
|
|
2023-05-02 09:00:14 +00:00
|
|
|
if !resolver.ResultCache().Shared() {
|
|
|
|
logger.Debug("register new result listener")
|
|
|
|
resolver.RegisterNewResultsListener()
|
|
|
|
}
|
|
|
|
|
|
|
|
if resolver.EnableLeaderElection() {
|
2022-07-25 15:34:41 +00:00
|
|
|
elector, err := resolver.LeaderElectionClient()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2023-05-02 09:00:14 +00:00
|
|
|
elector.RegisterOnStart(func(ctx context.Context) {
|
2023-03-16 13:38:24 +00:00
|
|
|
logger.Info("started leadership")
|
2022-07-25 15:34:41 +00:00
|
|
|
|
2023-05-02 09:00:14 +00:00
|
|
|
if c.REST.Enabled && !store.IsSQLite() {
|
|
|
|
store.PrepareDatabase(cmd.Context())
|
|
|
|
|
|
|
|
logger.Debug("register database persistence")
|
|
|
|
resolver.RegisterStoreListener(ctx, store)
|
|
|
|
|
|
|
|
if readinessProbe.Running() {
|
|
|
|
logger.Debug("trigger informer restart")
|
|
|
|
client.Stop()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-25 15:34:41 +00:00
|
|
|
resolver.RegisterSendResultListener()
|
2023-05-02 09:00:14 +00:00
|
|
|
|
|
|
|
readinessProbe.Ready()
|
2022-07-25 15:34:41 +00:00
|
|
|
}).RegisterOnNew(func(currentID, lockID string) {
|
|
|
|
if currentID != lockID {
|
2023-03-16 13:38:24 +00:00
|
|
|
logger.Info("leadership", zap.String("leader", currentID))
|
2023-05-02 09:00:14 +00:00
|
|
|
readinessProbe.Ready()
|
|
|
|
return
|
2022-07-25 15:34:41 +00:00
|
|
|
}
|
|
|
|
}).RegisterOnStop(func() {
|
2023-03-16 13:38:24 +00:00
|
|
|
logger.Info("stopped leadership")
|
2022-07-25 15:34:41 +00:00
|
|
|
|
2023-05-02 09:00:14 +00:00
|
|
|
if !store.IsSQLite() {
|
|
|
|
resolver.EventPublisher().UnregisterListener(listener.Store)
|
|
|
|
}
|
|
|
|
|
|
|
|
if resolver.HasTargets() {
|
|
|
|
resolver.UnregisterSendResultListener()
|
|
|
|
}
|
2022-07-25 15:34:41 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
g.Go(func() error {
|
|
|
|
return elector.Run(cmd.Context())
|
|
|
|
})
|
2023-05-02 09:00:14 +00:00
|
|
|
} else {
|
2022-07-25 15:34:41 +00:00
|
|
|
resolver.RegisterSendResultListener()
|
2024-09-28 10:23:37 +00:00
|
|
|
readinessProbe.Ready()
|
2022-07-25 15:34:41 +00:00
|
|
|
}
|
|
|
|
|
2024-10-07 09:10:46 +00:00
|
|
|
server, err := resolver.Server(cmd.Context(), servOptions)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-12-13 15:02:40 +00:00
|
|
|
g.Go(server.Start)
|
2021-08-09 18:53:04 +00:00
|
|
|
|
2023-02-08 14:53:59 +00:00
|
|
|
g.Go(func() error {
|
2024-10-07 09:10:46 +00:00
|
|
|
logger.Info("wait policy informer")
|
2023-05-02 09:00:14 +00:00
|
|
|
readinessProbe.Wait()
|
|
|
|
|
2023-03-16 13:38:24 +00:00
|
|
|
logger.Info("start client", zap.Int("worker", c.WorkerCount))
|
2021-02-27 18:11:49 +00:00
|
|
|
|
2023-05-02 09:00:14 +00:00
|
|
|
for {
|
|
|
|
stop := make(chan struct{})
|
|
|
|
if err := client.Run(c.WorkerCount, stop); err != nil {
|
|
|
|
zap.L().Error("informer client error", zap.Error(err))
|
|
|
|
}
|
|
|
|
|
|
|
|
zap.L().Debug("informer restarts")
|
|
|
|
}
|
2023-02-08 14:53:59 +00:00
|
|
|
})
|
2021-02-27 18:11:49 +00:00
|
|
|
|
2024-10-07 09:10:46 +00:00
|
|
|
g.Go(func() error {
|
|
|
|
collection := resolver.TargetClients()
|
|
|
|
if !collection.UsesSecrets() {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
readinessProbe.Wait()
|
|
|
|
|
|
|
|
stop := make(chan struct{})
|
|
|
|
if err := secretInformer.Sync(collection, stop); err != nil {
|
|
|
|
zap.L().Error("secret informer error", zap.Error(err))
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
<-stop
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
|
2021-10-18 09:07:38 +00:00
|
|
|
return g.Wait()
|
2021-02-27 18:11:49 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
// For local usage
|
|
|
|
cmd.PersistentFlags().StringP("kubeconfig", "k", "", "absolute path to the kubeconfig file")
|
|
|
|
cmd.PersistentFlags().StringP("config", "c", "", "target configuration file")
|
2024-10-07 09:10:46 +00:00
|
|
|
cmd.PersistentFlags().IntP("port", "p", 8001, "http port for the optional rest api")
|
|
|
|
cmd.PersistentFlags().StringP("dbfile", "d", "sqlite-database-v2.db", "path to the SQLite DB File")
|
2021-12-13 15:02:40 +00:00
|
|
|
cmd.PersistentFlags().BoolP("metrics-enabled", "m", false, "Enable Policy Reporter's Metrics API")
|
|
|
|
cmd.PersistentFlags().BoolP("rest-enabled", "r", false, "Enable Policy Reporter's REST API")
|
2022-05-13 08:59:32 +00:00
|
|
|
cmd.PersistentFlags().Bool("profile", false, "Enable application profiling with pprof")
|
2022-07-25 15:34:41 +00:00
|
|
|
cmd.PersistentFlags().String("lease-name", "policy-reporter", "name of the LeaseLock")
|
2023-05-02 09:00:14 +00:00
|
|
|
cmd.PersistentFlags().String("pod-name", "policy-reporter", "name of the pod, used for leaderelection")
|
2024-05-04 08:04:27 +00:00
|
|
|
cmd.PersistentFlags().StringP("template-dir", "t", "./templates", "template directory")
|
2023-02-13 16:17:06 +00:00
|
|
|
cmd.PersistentFlags().Int("worker", 5, "amount of queue worker")
|
2023-02-20 10:28:59 +00:00
|
|
|
cmd.PersistentFlags().Float32("qps", 20, "K8s RESTClient QPS")
|
|
|
|
cmd.PersistentFlags().Int("burst", 50, "K8s RESTClient burst")
|
2021-02-27 18:11:49 +00:00
|
|
|
|
|
|
|
flag.Parse()
|
|
|
|
|
|
|
|
return cmd
|
|
|
|
}
|