2020-03-04 18:56:59 +05:30
|
|
|
package openapi
|
|
|
|
|
|
|
|
import (
|
2020-10-15 17:54:58 -07:00
|
|
|
"context"
|
2020-03-27 19:06:06 +05:30
|
|
|
"fmt"
|
2020-09-02 16:33:55 +05:30
|
|
|
"strings"
|
2020-12-23 17:48:00 -08:00
|
|
|
"time"
|
2020-03-04 18:56:59 +05:30
|
|
|
|
2022-08-31 14:03:47 +08:00
|
|
|
"github.com/kyverno/kyverno/pkg/clients/dclient"
|
2022-10-02 20:45:03 +01:00
|
|
|
"github.com/kyverno/kyverno/pkg/logging"
|
2022-08-31 14:03:47 +08:00
|
|
|
"github.com/kyverno/kyverno/pkg/metrics"
|
2022-07-01 08:30:05 +05:30
|
|
|
util "github.com/kyverno/kyverno/pkg/utils"
|
2022-05-17 07:56:48 +02:00
|
|
|
"github.com/pkg/errors"
|
2022-05-17 16:14:31 +02:00
|
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
2020-10-15 17:54:58 -07:00
|
|
|
runtimeSchema "k8s.io/apimachinery/pkg/runtime/schema"
|
2020-03-04 18:56:59 +05:30
|
|
|
"k8s.io/apimachinery/pkg/util/wait"
|
2022-07-01 08:30:05 +05:30
|
|
|
"k8s.io/client-go/discovery"
|
2020-03-04 18:56:59 +05:30
|
|
|
)
|
|
|
|
|
|
|
|
type crdSync struct {
|
2022-10-12 13:38:48 +02:00
|
|
|
client dclient.Interface
|
|
|
|
manager *Manager
|
2020-03-04 18:56:59 +05:30
|
|
|
}
|
|
|
|
|
2022-07-01 08:30:05 +05:30
|
|
|
const (
|
|
|
|
skipErrorMsg = "Got empty response for"
|
|
|
|
)
|
|
|
|
|
2020-05-27 19:51:34 -07:00
|
|
|
// crdDefinitionPrior represents CRDs version prior to 1.16
|
2020-05-15 16:57:26 -07:00
|
|
|
var crdDefinitionPrior struct {
|
|
|
|
Spec struct {
|
|
|
|
Names struct {
|
|
|
|
Kind string `json:"kind"`
|
|
|
|
} `json:"names"`
|
|
|
|
Validation struct {
|
|
|
|
OpenAPIV3Schema interface{} `json:"openAPIV3Schema"`
|
|
|
|
} `json:"validation"`
|
|
|
|
} `json:"spec"`
|
|
|
|
}
|
|
|
|
|
2020-05-27 19:51:34 -07:00
|
|
|
// crdDefinitionNew represents CRDs version 1.16+
|
2020-05-15 16:57:26 -07:00
|
|
|
var crdDefinitionNew struct {
|
|
|
|
Spec struct {
|
|
|
|
Names struct {
|
|
|
|
Kind string `json:"kind"`
|
|
|
|
} `json:"names"`
|
|
|
|
Versions []struct {
|
|
|
|
Schema struct {
|
|
|
|
OpenAPIV3Schema interface{} `json:"openAPIV3Schema"`
|
|
|
|
} `json:"schema"`
|
|
|
|
Storage bool `json:"storage"`
|
|
|
|
} `json:"versions"`
|
|
|
|
} `json:"spec"`
|
|
|
|
}
|
|
|
|
|
2020-11-17 13:07:30 -08:00
|
|
|
// NewCRDSync ...
|
2022-10-12 13:38:48 +02:00
|
|
|
func NewCRDSync(client dclient.Interface, mgr *Manager) *crdSync {
|
|
|
|
if mgr == nil {
|
|
|
|
panic(fmt.Errorf("nil manager sent into crd sync"))
|
2020-03-27 19:06:06 +05:30
|
|
|
}
|
|
|
|
|
2020-03-04 18:56:59 +05:30
|
|
|
return &crdSync{
|
2022-10-12 13:38:48 +02:00
|
|
|
manager: mgr,
|
|
|
|
client: client,
|
2020-03-04 18:56:59 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-30 13:56:47 +02:00
|
|
|
func (c *crdSync) Run(ctx context.Context, workers int) {
|
2021-05-13 12:03:13 -07:00
|
|
|
if err := c.updateInClusterKindToAPIVersions(); err != nil {
|
2022-10-02 20:45:03 +01:00
|
|
|
logging.Error(err, "failed to update in-cluster api versions")
|
2021-05-13 12:03:13 -07:00
|
|
|
}
|
|
|
|
|
2022-07-01 08:30:05 +05:30
|
|
|
newDoc, err := c.client.Discovery().OpenAPISchema()
|
2020-03-05 22:50:32 +05:30
|
|
|
if err != nil {
|
2022-10-02 20:45:03 +01:00
|
|
|
logging.Error(err, "cannot get OpenAPI schema")
|
2020-03-05 22:50:32 +05:30
|
|
|
}
|
|
|
|
|
2022-10-12 13:38:48 +02:00
|
|
|
err = c.manager.useOpenAPIDocument(newDoc)
|
2020-03-05 22:50:32 +05:30
|
|
|
if err != nil {
|
2022-10-02 20:45:03 +01:00
|
|
|
logging.Error(err, "Could not set custom OpenAPI document")
|
2020-03-05 22:50:32 +05:30
|
|
|
}
|
2020-03-25 02:20:04 +05:30
|
|
|
// Sync CRD before kyverno starts
|
|
|
|
c.sync()
|
2020-03-04 18:56:59 +05:30
|
|
|
for i := 0; i < workers; i++ {
|
2022-09-30 13:56:47 +02:00
|
|
|
go wait.UntilWithContext(ctx, c.CheckSync, 15*time.Second)
|
2020-03-04 18:56:59 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-05 22:50:32 +05:30
|
|
|
func (c *crdSync) sync() {
|
2022-05-03 07:30:04 +02:00
|
|
|
c.client.Discovery().DiscoveryCache().Invalidate()
|
2020-04-02 12:19:32 +05:30
|
|
|
crds, err := c.client.GetDynamicInterface().Resource(runtimeSchema.GroupVersionResource{
|
|
|
|
Group: "apiextensions.k8s.io",
|
2021-05-13 12:03:13 -07:00
|
|
|
Version: "v1",
|
2020-04-02 12:19:32 +05:30
|
|
|
Resource: "customresourcedefinitions",
|
2022-05-17 16:14:31 +02:00
|
|
|
}).List(context.TODO(), metav1.ListOptions{})
|
2022-08-31 14:03:47 +08:00
|
|
|
|
|
|
|
c.client.RecordClientQuery(metrics.ClientList, metrics.KubeDynamicClient, "CustomResourceDefinition", "")
|
2020-03-04 18:56:59 +05:30
|
|
|
if err != nil {
|
2022-10-02 20:45:03 +01:00
|
|
|
logging.Error(err, "could not fetch crd's from server")
|
2020-03-05 22:50:32 +05:30
|
|
|
return
|
2020-03-04 18:56:59 +05:30
|
|
|
}
|
|
|
|
|
2022-10-12 13:38:48 +02:00
|
|
|
c.manager.deleteCRDFromPreviousSync()
|
2020-03-06 01:09:38 +05:30
|
|
|
|
2020-03-05 22:50:32 +05:30
|
|
|
for _, crd := range crds.Items {
|
2022-10-12 13:38:48 +02:00
|
|
|
c.manager.ParseCRD(crd)
|
2020-03-06 01:09:38 +05:30
|
|
|
}
|
2021-05-13 12:03:13 -07:00
|
|
|
|
|
|
|
if err := c.updateInClusterKindToAPIVersions(); err != nil {
|
2022-10-02 20:45:03 +01:00
|
|
|
logging.Error(err, "sync failed, unable to update in-cluster api versions")
|
2021-05-13 12:03:13 -07:00
|
|
|
}
|
2021-11-22 19:22:45 +05:30
|
|
|
|
2022-07-01 08:30:05 +05:30
|
|
|
newDoc, err := c.client.Discovery().OpenAPISchema()
|
2021-11-22 19:22:45 +05:30
|
|
|
if err != nil {
|
2022-10-02 20:45:03 +01:00
|
|
|
logging.Error(err, "cannot get OpenAPI schema")
|
2021-11-22 19:22:45 +05:30
|
|
|
}
|
|
|
|
|
2022-10-12 13:38:48 +02:00
|
|
|
err = c.manager.useOpenAPIDocument(newDoc)
|
2021-11-22 19:22:45 +05:30
|
|
|
if err != nil {
|
2022-10-02 20:45:03 +01:00
|
|
|
logging.Error(err, "Could not set custom OpenAPI document")
|
2021-11-22 19:22:45 +05:30
|
|
|
}
|
2021-05-13 12:03:13 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *crdSync) updateInClusterKindToAPIVersions() error {
|
2022-07-01 08:30:05 +05:30
|
|
|
util.OverrideRuntimeErrorHandler()
|
|
|
|
_, apiResourceLists, err := discovery.ServerGroupsAndResources(c.client.Discovery().DiscoveryInterface())
|
|
|
|
|
|
|
|
if err != nil && !strings.Contains(err.Error(), skipErrorMsg) {
|
2021-11-22 18:27:51 +05:30
|
|
|
return errors.Wrapf(err, "fetching API server groups and resources")
|
2021-05-13 12:03:13 -07:00
|
|
|
}
|
2022-07-01 08:30:05 +05:30
|
|
|
preferredAPIResourcesLists, err := discovery.ServerPreferredResources(c.client.Discovery().DiscoveryInterface())
|
|
|
|
if err != nil && !strings.Contains(err.Error(), skipErrorMsg) {
|
2021-11-22 18:27:51 +05:30
|
|
|
return errors.Wrapf(err, "fetching API server preferreds resources")
|
2021-05-13 12:03:13 -07:00
|
|
|
}
|
|
|
|
|
2022-10-12 13:38:48 +02:00
|
|
|
c.manager.updateKindToAPIVersions(apiResourceLists, preferredAPIResourcesLists)
|
2021-05-13 12:03:13 -07:00
|
|
|
return nil
|
2020-03-06 01:09:38 +05:30
|
|
|
}
|
|
|
|
|
2022-09-30 13:56:47 +02:00
|
|
|
func (c *crdSync) CheckSync(ctx context.Context) {
|
2022-09-12 13:44:28 +05:30
|
|
|
crds, err := c.client.GetDynamicInterface().Resource(runtimeSchema.GroupVersionResource{
|
|
|
|
Group: "apiextensions.k8s.io",
|
|
|
|
Version: "v1",
|
|
|
|
Resource: "customresourcedefinitions",
|
2022-09-30 13:56:47 +02:00
|
|
|
}).List(ctx, metav1.ListOptions{})
|
2022-09-12 13:44:28 +05:30
|
|
|
if err != nil {
|
2022-10-02 20:45:03 +01:00
|
|
|
logging.Error(err, "could not fetch crd's from server")
|
2022-09-12 13:44:28 +05:30
|
|
|
return
|
|
|
|
}
|
2022-10-12 13:38:48 +02:00
|
|
|
if len(c.manager.crdList) != len(crds.Items) {
|
2022-09-12 13:44:28 +05:30
|
|
|
c.sync()
|
|
|
|
}
|
|
|
|
}
|