mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-31 03:45:17 +00:00
handle discovery errors for metrics API group (#1494)
Signed-off-by: Jim Bugwadia <jim@nirmata.com>
This commit is contained in:
parent
e54776ee7e
commit
05da4190f8
5 changed files with 65 additions and 48 deletions
|
@ -46,6 +46,7 @@ func main() {
|
||||||
if err := flag.Set("v", "2"); err != nil {
|
if err := flag.Set("v", "2"); err != nil {
|
||||||
klog.Fatalf("failed to set log level: %v", err)
|
klog.Fatalf("failed to set log level: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
// os signal handler
|
// os signal handler
|
||||||
|
@ -109,9 +110,10 @@ func main() {
|
||||||
log.Log.Error(err, "failed to cleanup resource")
|
log.Log.Error(err, "failed to cleanup resource")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if there is any failure then we fail process
|
// if there is any failure then we fail process
|
||||||
if failure {
|
if failure {
|
||||||
log.Log.Info("failed to cleanup webhook configurations")
|
log.Log.Info("failed to cleanup prior configurations")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -131,6 +133,7 @@ func executeRequest(client *client.Client, req request) error {
|
||||||
case policyViolation, clusterPolicyViolation:
|
case policyViolation, clusterPolicyViolation:
|
||||||
return removeViolationCRD(client)
|
return removeViolationCRD(client)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,6 +143,7 @@ func createClientConfig(kubeconfig string) (*rest.Config, error) {
|
||||||
logger.Info("Using in-cluster configuration")
|
logger.Info("Using in-cluster configuration")
|
||||||
return rest.InClusterConfig()
|
return rest.InClusterConfig()
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Info(fmt.Sprintf("Using configuration from '%s'", kubeconfig))
|
logger.Info(fmt.Sprintf("Using configuration from '%s'", kubeconfig))
|
||||||
return clientcmd.BuildConfigFromFlags("", kubeconfig)
|
return clientcmd.BuildConfigFromFlags("", kubeconfig)
|
||||||
}
|
}
|
||||||
|
|
|
@ -123,7 +123,7 @@ func main() {
|
||||||
|
|
||||||
// CRD CHECK
|
// CRD CHECK
|
||||||
// - verify if Kyverno CRDs are available
|
// - verify if Kyverno CRDs are available
|
||||||
if !utils.CRDInstalled(client.DiscoveryClient, log.Log) {
|
if !utils.CRDsInstalled(client.DiscoveryClient) {
|
||||||
setupLog.Error(fmt.Errorf("CRDs not installed"), "Failed to access Kyverno CRDs")
|
setupLog.Error(fmt.Errorf("CRDs not installed"), "Failed to access Kyverno CRDs")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
|
@ -147,6 +147,7 @@ func (c *Client) ListResource(apiVersion string, kind string, namespace string,
|
||||||
if lselector != nil {
|
if lselector != nil {
|
||||||
options = meta.ListOptions{LabelSelector: helperv1.FormatLabelSelector(lselector)}
|
options = meta.ListOptions{LabelSelector: helperv1.FormatLabelSelector(lselector)}
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.getResourceInterface(apiVersion, kind, namespace).List(context.TODO(), options)
|
return c.getResourceInterface(apiVersion, kind, namespace).List(context.TODO(), options)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -325,31 +326,38 @@ func (c ServerPreferredResources) FindResource(apiVersion string, kind string) (
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c ServerPreferredResources) findResource(apiVersion string, kind string) (*meta.APIResource, schema.GroupVersionResource, error) {
|
func (c ServerPreferredResources) findResource(apiVersion string, kind string) (*meta.APIResource, schema.GroupVersionResource, error) {
|
||||||
var serverresources []*meta.APIResourceList
|
var serverResources []*meta.APIResourceList
|
||||||
var err error
|
var err error
|
||||||
if apiVersion == "" {
|
if apiVersion == "" {
|
||||||
serverresources, err = c.cachedClient.ServerPreferredResources()
|
serverResources, err = c.cachedClient.ServerPreferredResources()
|
||||||
} else {
|
} else {
|
||||||
serverresources, err = c.cachedClient.ServerResources()
|
_, serverResources, err = c.cachedClient.ServerGroupsAndResources()
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.log.Error(err, "failed to get registered preferred resources")
|
if discovery.IsGroupDiscoveryFailedError(err) {
|
||||||
return nil, schema.GroupVersionResource{}, err
|
logDiscoveryErrors(err, c)
|
||||||
|
} else if isMetricsServerUnavailable(kind, err) {
|
||||||
|
c.log.V(3).Info("failed to find preferred resource version", "error", err.Error())
|
||||||
|
} else {
|
||||||
|
c.log.Error(err, "failed to find preferred resource version")
|
||||||
|
return nil, schema.GroupVersionResource{}, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, serverresource := range serverresources {
|
for _, serverResource := range serverResources {
|
||||||
|
|
||||||
if apiVersion != "" && serverresource.GroupVersion != apiVersion {
|
if apiVersion != "" && serverResource.GroupVersion != apiVersion {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for _, resource := range serverresource.APIResources {
|
|
||||||
|
for _, resource := range serverResource.APIResources {
|
||||||
|
|
||||||
// skip the resource names with "/", to avoid comparison with subresources
|
// skip the resource names with "/", to avoid comparison with subresources
|
||||||
if resource.Kind == kind && !strings.Contains(resource.Name, "/") {
|
if resource.Kind == kind && !strings.Contains(resource.Name, "/") {
|
||||||
gv, err := schema.ParseGroupVersion(serverresource.GroupVersion)
|
gv, err := schema.ParseGroupVersion(serverResource.GroupVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.log.Error(err, "failed to parse groupVersion", "groupVersion", serverresource.GroupVersion)
|
c.log.Error(err, "failed to parse groupVersion", "groupVersion", serverResource.GroupVersion)
|
||||||
return nil, schema.GroupVersionResource{}, err
|
return nil, schema.GroupVersionResource{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -360,3 +368,24 @@ func (c ServerPreferredResources) findResource(apiVersion string, kind string) (
|
||||||
|
|
||||||
return nil, schema.GroupVersionResource{}, fmt.Errorf("kind '%s' not found in apiVersion '%s'", kind, apiVersion)
|
return nil, schema.GroupVersionResource{}, fmt.Errorf("kind '%s' not found in apiVersion '%s'", kind, apiVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func logDiscoveryErrors(err error, c ServerPreferredResources) {
|
||||||
|
discoveryError := err.(*discovery.ErrGroupDiscoveryFailed)
|
||||||
|
for gv, e := range discoveryError.Groups {
|
||||||
|
if gv.Group == "custom.metrics.k8s.io" || gv.Group == "metrics.k8s.io" {
|
||||||
|
// These error occur when Prometheus is installed as an external metrics server
|
||||||
|
// See: https://github.com/kyverno/kyverno/issues/1490
|
||||||
|
c.log.V(3).Info("failed to retrieve metrics API group", "gv", gv)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
c.log.Error(e, "failed to retrieve API group", "gv", gv)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func isMetricsServerUnavailable(kind string, err error) bool {
|
||||||
|
// error message is defined at:
|
||||||
|
// https://github.com/kubernetes/apimachinery/blob/2456ebdaba229616fab2161a615148884b46644b/pkg/api/errors/errors.go#L432
|
||||||
|
return strings.HasPrefix(kind, "metrics.k8s.io/") &&
|
||||||
|
strings.Contains(err.Error(), "the server is currently unable to handle the request")
|
||||||
|
}
|
||||||
|
|
|
@ -3,8 +3,6 @@ package generate
|
||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
"github.com/go-logr/logr"
|
||||||
kyverno "github.com/kyverno/kyverno/pkg/api/kyverno/v1"
|
kyverno "github.com/kyverno/kyverno/pkg/api/kyverno/v1"
|
||||||
kyvernoclient "github.com/kyverno/kyverno/pkg/client/clientset/versioned"
|
kyvernoclient "github.com/kyverno/kyverno/pkg/client/clientset/versioned"
|
||||||
|
@ -276,8 +274,6 @@ func (c *Controller) Run(workers int, stopCh <-chan struct{}) {
|
||||||
// worker runs a worker thread that just dequeues items, processes them, and marks them done.
|
// worker runs a worker thread that just dequeues items, processes them, and marks them done.
|
||||||
// It enforces that the syncHandler is never invoked concurrently with the same key.
|
// It enforces that the syncHandler is never invoked concurrently with the same key.
|
||||||
func (c *Controller) worker() {
|
func (c *Controller) worker() {
|
||||||
log.Log.Info("starting new worker...")
|
|
||||||
|
|
||||||
for c.processNextWorkItem() {
|
for c.processNextWorkItem() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,9 @@ package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
"github.com/go-logr/logr"
|
||||||
client "github.com/kyverno/kyverno/pkg/dclient"
|
client "github.com/kyverno/kyverno/pkg/dclient"
|
||||||
|
@ -57,35 +56,30 @@ func NewKubeClient(config *rest.Config) (kubernetes.Interface, error) {
|
||||||
return kclient, nil
|
return kclient, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//CRDInstalled to check if the CRD is installed or not
|
// CRDsInstalled checks if the Kyverno CRDs are installed or not
|
||||||
func CRDInstalled(discovery client.IDiscovery, log logr.Logger) bool {
|
func CRDsInstalled(discovery client.IDiscovery) bool {
|
||||||
logger := log.WithName("CRDInstalled")
|
|
||||||
check := func(kind string) bool {
|
|
||||||
gvr, err := discovery.GetGVRFromKind(kind)
|
|
||||||
if err != nil {
|
|
||||||
if isServerUnavailable(err) {
|
|
||||||
logger.Info("**WARNING** unable to check CRD status", "kind", kind, "error", err.Error())
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Error(err, "failed to check CRD status", "kind", kind)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if reflect.DeepEqual(gvr, schema.GroupVersionResource{}) {
|
|
||||||
logger.Info("CRD not installed", "kind", kind)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
logger.Info("CRD found", "kind", kind)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
kyvernoCRDs := []string{"ClusterPolicy", "ClusterPolicyReport", "PolicyReport", "ClusterReportChangeRequest", "ReportChangeRequest"}
|
kyvernoCRDs := []string{"ClusterPolicy", "ClusterPolicyReport", "PolicyReport", "ClusterReportChangeRequest", "ReportChangeRequest"}
|
||||||
for _, crd := range kyvernoCRDs {
|
for _, crd := range kyvernoCRDs {
|
||||||
if !check(crd) {
|
if !isCRDInstalled(discovery, crd) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func isCRDInstalled(discoveryClient client.IDiscovery, kind string) bool {
|
||||||
|
gvr, err := discoveryClient.GetGVRFromKind(kind)
|
||||||
|
if gvr.Empty() {
|
||||||
|
if err == nil {
|
||||||
|
err = fmt.Errorf("not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Log.Error(err, "failed to retrieve CRD", "kind", kind)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Log.Info("CRD found", "gvr", gvr.String())
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,9 +187,3 @@ func SliceContains(slice []string, values ...string) bool {
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func isServerUnavailable(err error) bool {
|
|
||||||
// error message -
|
|
||||||
// https://github.com/kubernetes/apimachinery/blob/2456ebdaba229616fab2161a615148884b46644b/pkg/api/errors/errors.go#L432
|
|
||||||
return strings.Contains(err.Error(), "the server is currently unable to handle the request")
|
|
||||||
}
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue