mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-31 03:45:17 +00:00
parent
39f75db435
commit
b5af456f64
126 changed files with 2111 additions and 3203 deletions
|
@ -1,18 +0,0 @@
|
||||||
engines:
|
|
||||||
govet:
|
|
||||||
enabled: true
|
|
||||||
golint:
|
|
||||||
enabled: false
|
|
||||||
gofmt:
|
|
||||||
enabled: true
|
|
||||||
|
|
||||||
ratings:
|
|
||||||
paths:
|
|
||||||
- "**.go"
|
|
||||||
|
|
||||||
exclude_paths:
|
|
||||||
- documentation/
|
|
||||||
- definitions
|
|
||||||
- gh-pages
|
|
||||||
- samples
|
|
||||||
- scripts
|
|
|
@ -1,17 +0,0 @@
|
||||||
linters:
|
|
||||||
enable:
|
|
||||||
- gosec
|
|
||||||
- errcheck
|
|
||||||
- gosimple
|
|
||||||
- bodyclose
|
|
||||||
- staticcheck
|
|
||||||
disable:
|
|
||||||
- ineffassign
|
|
||||||
- deadcode
|
|
||||||
- unused
|
|
||||||
- structcheck
|
|
||||||
|
|
||||||
run:
|
|
||||||
skip-files:
|
|
||||||
- ".+_test.go"
|
|
||||||
- ".+_test_.+.go"
|
|
|
@ -2,11 +2,6 @@ language: go
|
||||||
go:
|
go:
|
||||||
- "1.13"
|
- "1.13"
|
||||||
|
|
||||||
cache:
|
|
||||||
directories:
|
|
||||||
- $HOME/.cache/go-build
|
|
||||||
- $GOPATH/pkg/mod
|
|
||||||
|
|
||||||
# safelist
|
# safelist
|
||||||
branches:
|
branches:
|
||||||
only:
|
only:
|
||||||
|
|
|
@ -1,7 +1 @@
|
||||||
# Contributing to Kyverno
|
See: https://github.com/nirmata/kyverno#contributing
|
||||||
|
|
||||||
## Code Style
|
|
||||||
|
|
||||||
We follow the community provided standard [code structure](https://github.com/golang-standards/project-layout).
|
|
||||||
|
|
||||||
See : https://github.com/nirmata/kyverno#contributing
|
|
||||||
|
|
|
@ -171,6 +171,5 @@ See [Milestones](https://github.com/nirmata/kyverno/milestones) and [Issues](htt
|
||||||
Thanks for your interest in contributing!
|
Thanks for your interest in contributing!
|
||||||
|
|
||||||
* Please review and agree to abide with the [Code of Conduct](/CODE_OF_CONDUCT.md) before contributing.
|
* Please review and agree to abide with the [Code of Conduct](/CODE_OF_CONDUCT.md) before contributing.
|
||||||
* We encourage all contributions and encourage you to read our [contribution guidelines](./CONTRIBUTING.md).
|
|
||||||
* See the [Wiki](https://github.com/nirmata/kyverno/wiki) for developer documentation.
|
* See the [Wiki](https://github.com/nirmata/kyverno/wiki) for developer documentation.
|
||||||
* Browse through the [open issues](https://github.com/nirmata/kyverno/issues)
|
* Browse through the [open issues](https://github.com/nirmata/kyverno/issues)
|
||||||
|
|
|
@ -5,27 +5,23 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/golang/glog"
|
||||||
"github.com/nirmata/kyverno/pkg/config"
|
"github.com/nirmata/kyverno/pkg/config"
|
||||||
client "github.com/nirmata/kyverno/pkg/dclient"
|
client "github.com/nirmata/kyverno/pkg/dclient"
|
||||||
"github.com/nirmata/kyverno/pkg/signal"
|
"github.com/nirmata/kyverno/pkg/signal"
|
||||||
"k8s.io/apimachinery/pkg/api/errors"
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
rest "k8s.io/client-go/rest"
|
rest "k8s.io/client-go/rest"
|
||||||
clientcmd "k8s.io/client-go/tools/clientcmd"
|
clientcmd "k8s.io/client-go/tools/clientcmd"
|
||||||
"k8s.io/klog"
|
|
||||||
"k8s.io/klog/klogr"
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
kubeconfig string
|
kubeconfig string
|
||||||
setupLog = log.Log.WithName("setup")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -34,30 +30,20 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
klog.InitFlags(nil)
|
defer glog.Flush()
|
||||||
log.SetLogger(klogr.New())
|
|
||||||
// arguments
|
|
||||||
flag.StringVar(&kubeconfig, "kubeconfig", "", "Path to a kubeconfig. Only required if out-of-cluster.")
|
|
||||||
if err := flag.Set("v", "2"); err != nil {
|
|
||||||
klog.Fatalf("failed to set log level: %v", err)
|
|
||||||
}
|
|
||||||
flag.Parse()
|
|
||||||
|
|
||||||
// os signal handler
|
// os signal handler
|
||||||
stopCh := signal.SetupSignalHandler()
|
stopCh := signal.SetupSignalHandler()
|
||||||
// create client config
|
// create client config
|
||||||
clientConfig, err := createClientConfig(kubeconfig)
|
clientConfig, err := createClientConfig(kubeconfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
setupLog.Error(err, "Failed to build kubeconfig")
|
glog.Fatalf("Error building kubeconfig: %v\n", err)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DYNAMIC CLIENT
|
// DYNAMIC CLIENT
|
||||||
// - client for all registered resources
|
// - client for all registered resources
|
||||||
client, err := client.NewClient(clientConfig, 10*time.Second, stopCh, log.Log)
|
client, err := client.NewClient(clientConfig, 10*time.Second, stopCh)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
setupLog.Error(err, "Failed to create client")
|
glog.Fatalf("Error creating client: %v\n", err)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exit for unsupported version of kubernetes cluster
|
// Exit for unsupported version of kubernetes cluster
|
||||||
|
@ -92,46 +78,53 @@ func main() {
|
||||||
for err := range merge(done, stopCh, p1, p2) {
|
for err := range merge(done, stopCh, p1, p2) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
failure = true
|
failure = true
|
||||||
log.Log.Error(err, "failed to cleanup resource")
|
glog.Errorf("failed to cleanup: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 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")
|
glog.Errorf("failed to cleanup webhook configurations")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// arguments
|
||||||
|
flag.StringVar(&kubeconfig, "kubeconfig", "", "Path to a kubeconfig. Only required if out-of-cluster.")
|
||||||
|
flag.Set("logtostderr", "true")
|
||||||
|
flag.Set("stderrthreshold", "WARNING")
|
||||||
|
flag.Set("v", "2")
|
||||||
|
flag.Parse()
|
||||||
|
}
|
||||||
|
|
||||||
func removeWebhookIfExists(client *client.Client, kind string, name string) error {
|
func removeWebhookIfExists(client *client.Client, kind string, name string) error {
|
||||||
logger := log.Log.WithName("removeExistingWebhook").WithValues("kind", kind, "name", name)
|
|
||||||
var err error
|
var err error
|
||||||
// Get resource
|
// Get resource
|
||||||
_, err = client.GetResource(kind, "", name)
|
_, err = client.GetResource(kind, "", name)
|
||||||
if errors.IsNotFound(err) {
|
if errors.IsNotFound(err) {
|
||||||
logger.V(4).Info("resource not found")
|
glog.V(4).Infof("%s(%s) not found", name, kind)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "failed to get resource")
|
glog.Errorf("failed to get resource %s(%s)", name, kind)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Delete resource
|
// Delete resource
|
||||||
err = client.DeleteResource(kind, "", name, false)
|
err = client.DeleteResource(kind, "", name, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "failed to delete resource")
|
glog.Errorf("failed to delete resource %s(%s)", name, kind)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
logger.Info("removed the resource")
|
glog.Infof("cleaned up resource %s(%s)", name, kind)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createClientConfig(kubeconfig string) (*rest.Config, error) {
|
func createClientConfig(kubeconfig string) (*rest.Config, error) {
|
||||||
logger := log.Log
|
|
||||||
if kubeconfig == "" {
|
if kubeconfig == "" {
|
||||||
logger.Info("Using in-cluster configuration")
|
glog.Info("Using in-cluster configuration")
|
||||||
return rest.InClusterConfig()
|
return rest.InClusterConfig()
|
||||||
}
|
}
|
||||||
logger.Info(fmt.Sprintf("Using configuration from '%s'", kubeconfig))
|
glog.Infof("Using configuration from '%s'", kubeconfig)
|
||||||
return clientcmd.BuildConfigFromFlags("", kubeconfig)
|
return clientcmd.BuildConfigFromFlags("", kubeconfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,7 +163,6 @@ func gen(done <-chan struct{}, stopCh <-chan struct{}, requests ...request) <-ch
|
||||||
|
|
||||||
// processes the requests
|
// processes the requests
|
||||||
func process(client *client.Client, done <-chan struct{}, stopCh <-chan struct{}, requests <-chan request) <-chan error {
|
func process(client *client.Client, done <-chan struct{}, stopCh <-chan struct{}, requests <-chan request) <-chan error {
|
||||||
logger := log.Log.WithName("process")
|
|
||||||
out := make(chan error)
|
out := make(chan error)
|
||||||
go func() {
|
go func() {
|
||||||
defer close(out)
|
defer close(out)
|
||||||
|
@ -178,10 +170,10 @@ func process(client *client.Client, done <-chan struct{}, stopCh <-chan struct{}
|
||||||
select {
|
select {
|
||||||
case out <- removeWebhookIfExists(client, req.kind, req.name):
|
case out <- removeWebhookIfExists(client, req.kind, req.name):
|
||||||
case <-done:
|
case <-done:
|
||||||
logger.Info("done")
|
println("done process")
|
||||||
return
|
return
|
||||||
case <-stopCh:
|
case <-stopCh:
|
||||||
logger.Info("shutting down")
|
println("shutting down process")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -191,7 +183,6 @@ func process(client *client.Client, done <-chan struct{}, stopCh <-chan struct{}
|
||||||
|
|
||||||
// waits for all processes to be complete and merges result
|
// waits for all processes to be complete and merges result
|
||||||
func merge(done <-chan struct{}, stopCh <-chan struct{}, processes ...<-chan error) <-chan error {
|
func merge(done <-chan struct{}, stopCh <-chan struct{}, processes ...<-chan error) <-chan error {
|
||||||
logger := log.Log.WithName("merge")
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
out := make(chan error)
|
out := make(chan error)
|
||||||
// gets the output from each process
|
// gets the output from each process
|
||||||
|
@ -201,10 +192,10 @@ func merge(done <-chan struct{}, stopCh <-chan struct{}, processes ...<-chan err
|
||||||
select {
|
select {
|
||||||
case out <- err:
|
case out <- err:
|
||||||
case <-done:
|
case <-done:
|
||||||
logger.Info("done")
|
println("done merge")
|
||||||
return
|
return
|
||||||
case <-stopCh:
|
case <-stopCh:
|
||||||
logger.Info("shutting down")
|
println("shutting down merge")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -224,37 +215,30 @@ func merge(done <-chan struct{}, stopCh <-chan struct{}, processes ...<-chan err
|
||||||
}
|
}
|
||||||
|
|
||||||
func isVersionSupported(client *client.Client) {
|
func isVersionSupported(client *client.Client) {
|
||||||
logger := log.Log
|
|
||||||
serverVersion, err := client.DiscoveryClient.GetServerVersion()
|
serverVersion, err := client.DiscoveryClient.GetServerVersion()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "Failed to get kubernetes server version")
|
glog.Fatalf("Failed to get kubernetes server version: %v\n", err)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
exp := regexp.MustCompile(`v(\d*).(\d*).(\d*)`)
|
exp := regexp.MustCompile(`v(\d*).(\d*).(\d*)`)
|
||||||
groups := exp.FindAllStringSubmatch(serverVersion.String(), -1)
|
groups := exp.FindAllStringSubmatch(serverVersion.String(), -1)
|
||||||
if len(groups) != 1 || len(groups[0]) != 4 {
|
if len(groups) != 1 || len(groups[0]) != 4 {
|
||||||
logger.Error(err, "Failed to extract kubernetes server version", "serverVersion", serverVersion)
|
glog.Fatalf("Failed to extract kubernetes server version: %v.err %v\n", serverVersion, err)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
// convert string to int
|
// convert string to int
|
||||||
// assuming the version are always intergers
|
// assuming the version are always intergers
|
||||||
major, err := strconv.Atoi(groups[0][1])
|
major, err := strconv.Atoi(groups[0][1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "Failed to extract kubernetes major server version", "serverVersion", serverVersion)
|
glog.Fatalf("Failed to extract kubernetes major server version: %v.err %v\n", serverVersion, err)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
minor, err := strconv.Atoi(groups[0][2])
|
minor, err := strconv.Atoi(groups[0][2])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "Failed to extract kubernetes minor server version", "serverVersion", serverVersion)
|
glog.Fatalf("Failed to extract kubernetes minor server version: %v.err %v\n", serverVersion, err)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
sub, err := strconv.Atoi(groups[0][3])
|
sub, err := strconv.Atoi(groups[0][3])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "Failed to extract kubernetes sub minor server version", "serverVersion", serverVersion)
|
glog.Fatalf("Failed to extract kubernetes sub minor server version:%v. err %v\n", serverVersion, err)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
if major <= 1 && minor <= 12 && sub < 7 {
|
if major <= 1 && minor <= 12 && sub < 7 {
|
||||||
logger.Info("Unsupported kubernetes server version %s. Kyverno is supported from version v1.12.7+", "serverVersion", serverVersion)
|
glog.Fatalf("Unsupported kubernetes server version %s. Kyverno is supported from version v1.12.7+", serverVersion)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,12 +3,11 @@ package main
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/nirmata/kyverno/pkg/openapi"
|
"github.com/nirmata/kyverno/pkg/openapi"
|
||||||
|
|
||||||
|
"github.com/golang/glog"
|
||||||
"github.com/nirmata/kyverno/pkg/checker"
|
"github.com/nirmata/kyverno/pkg/checker"
|
||||||
kyvernoclient "github.com/nirmata/kyverno/pkg/client/clientset/versioned"
|
kyvernoclient "github.com/nirmata/kyverno/pkg/client/clientset/versioned"
|
||||||
kyvernoinformer "github.com/nirmata/kyverno/pkg/client/informers/externalversions"
|
kyvernoinformer "github.com/nirmata/kyverno/pkg/client/informers/externalversions"
|
||||||
|
@ -28,9 +27,6 @@ import (
|
||||||
"github.com/nirmata/kyverno/pkg/webhooks"
|
"github.com/nirmata/kyverno/pkg/webhooks"
|
||||||
webhookgenerate "github.com/nirmata/kyverno/pkg/webhooks/generate"
|
webhookgenerate "github.com/nirmata/kyverno/pkg/webhooks/generate"
|
||||||
kubeinformers "k8s.io/client-go/informers"
|
kubeinformers "k8s.io/client-go/informers"
|
||||||
"k8s.io/klog"
|
|
||||||
"k8s.io/klog/klogr"
|
|
||||||
log "sigs.k8s.io/controller-runtime/pkg/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -42,38 +38,20 @@ var (
|
||||||
// will be removed in future and the configuration will be set only via configmaps
|
// will be removed in future and the configuration will be set only via configmaps
|
||||||
filterK8Resources string
|
filterK8Resources string
|
||||||
// User FQDN as CSR CN
|
// User FQDN as CSR CN
|
||||||
fqdncn bool
|
fqdncn bool
|
||||||
setupLog = log.Log.WithName("setup")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
klog.InitFlags(nil)
|
defer glog.Flush()
|
||||||
log.SetLogger(klogr.New())
|
version.PrintVersionInfo()
|
||||||
flag.StringVar(&filterK8Resources, "filterK8Resources", "", "k8 resource in format [kind,namespace,name] where policy is not evaluated by the admission webhook. example --filterKind \"[Deployment, kyverno, kyverno]\" --filterKind \"[Deployment, kyverno, kyverno],[Events, *, *]\"")
|
|
||||||
flag.IntVar(&webhookTimeout, "webhooktimeout", 3, "timeout for webhook configurations")
|
|
||||||
flag.StringVar(&kubeconfig, "kubeconfig", "", "Path to a kubeconfig. Only required if out-of-cluster.")
|
|
||||||
flag.StringVar(&serverIP, "serverIP", "", "IP address where Kyverno controller runs. Only required if out-of-cluster.")
|
|
||||||
flag.StringVar(&runValidationInMutatingWebhook, "runValidationInMutatingWebhook", "", "Validation will also be done using the mutation webhook, set to 'true' to enable. Older kubernetes versions do not work properly when a validation webhook is registered.")
|
|
||||||
if err := flag.Set("v", "2"); err != nil {
|
|
||||||
setupLog.Error(err, "failed to set log level")
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate CSR with CN as FQDN due to https://github.com/nirmata/kyverno/issues/542
|
|
||||||
flag.BoolVar(&fqdncn, "fqdn-as-cn", false, "use FQDN as Common Name in CSR")
|
|
||||||
|
|
||||||
flag.Parse()
|
|
||||||
|
|
||||||
version.PrintVersionInfo(log.Log)
|
|
||||||
// cleanUp Channel
|
// cleanUp Channel
|
||||||
cleanUp := make(chan struct{})
|
cleanUp := make(chan struct{})
|
||||||
// handle os signals
|
// handle os signals
|
||||||
stopCh := signal.SetupSignalHandler()
|
stopCh := signal.SetupSignalHandler()
|
||||||
// CLIENT CONFIG
|
// CLIENT CONFIG
|
||||||
clientConfig, err := config.CreateClientConfig(kubeconfig, log.Log)
|
clientConfig, err := config.CreateClientConfig(kubeconfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
setupLog.Error(err, "Failed to build kubeconfig")
|
glog.Fatalf("Error building kubeconfig: %v\n", err)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// KYVENO CRD CLIENT
|
// KYVENO CRD CLIENT
|
||||||
|
@ -82,33 +60,29 @@ func main() {
|
||||||
// - PolicyViolation
|
// - PolicyViolation
|
||||||
pclient, err := kyvernoclient.NewForConfig(clientConfig)
|
pclient, err := kyvernoclient.NewForConfig(clientConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
setupLog.Error(err, "Failed to create client")
|
glog.Fatalf("Error creating client: %v\n", err)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DYNAMIC CLIENT
|
// DYNAMIC CLIENT
|
||||||
// - client for all registered resources
|
// - client for all registered resources
|
||||||
// - invalidate local cache of registered resource every 10 seconds
|
// - invalidate local cache of registered resource every 10 seconds
|
||||||
client, err := dclient.NewClient(clientConfig, 10*time.Second, stopCh, log.Log)
|
client, err := dclient.NewClient(clientConfig, 10*time.Second, stopCh)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
setupLog.Error(err, "Failed to create client")
|
glog.Fatalf("Error creating client: %v\n", err)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
// CRD CHECK
|
// CRD CHECK
|
||||||
// - verify if the CRD for Policy & PolicyViolation are available
|
// - verify if the CRD for Policy & PolicyViolation are available
|
||||||
if !utils.CRDInstalled(client.DiscoveryClient, log.Log) {
|
if !utils.CRDInstalled(client.DiscoveryClient) {
|
||||||
setupLog.Error(fmt.Errorf("pre-requisite CRDs not installed"), "Failed to create watch on kyverno CRDs")
|
glog.Fatalf("Required CRDs unavailable")
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
// KUBERNETES CLIENT
|
// KUBERNETES CLIENT
|
||||||
kubeClient, err := utils.NewKubeClient(clientConfig)
|
kubeClient, err := utils.NewKubeClient(clientConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
setupLog.Error(err, "Failed to create kubernetes client")
|
glog.Fatalf("Error creating kubernetes client: %v\n", err)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(shuting): To be removed for v1.2.0
|
// TODO(shuting): To be removed for v1.2.0
|
||||||
utils.CleanupOldCrd(client, log.Log)
|
utils.CleanupOldCrd(client)
|
||||||
|
|
||||||
// KUBERNETES RESOURCES INFORMER
|
// KUBERNETES RESOURCES INFORMER
|
||||||
// watches namespace resource
|
// watches namespace resource
|
||||||
|
@ -125,18 +99,16 @@ func main() {
|
||||||
clientConfig,
|
clientConfig,
|
||||||
client,
|
client,
|
||||||
serverIP,
|
serverIP,
|
||||||
int32(webhookTimeout),
|
int32(webhookTimeout))
|
||||||
log.Log)
|
|
||||||
|
|
||||||
// Resource Mutating Webhook Watcher
|
// Resource Mutating Webhook Watcher
|
||||||
lastReqTime := checker.NewLastReqTime(log.Log.WithName("LastReqTime"))
|
lastReqTime := checker.NewLastReqTime()
|
||||||
rWebhookWatcher := webhookconfig.NewResourceWebhookRegister(
|
rWebhookWatcher := webhookconfig.NewResourceWebhookRegister(
|
||||||
lastReqTime,
|
lastReqTime,
|
||||||
kubeInformer.Admissionregistration().V1beta1().MutatingWebhookConfigurations(),
|
kubeInformer.Admissionregistration().V1beta1().MutatingWebhookConfigurations(),
|
||||||
kubeInformer.Admissionregistration().V1beta1().ValidatingWebhookConfigurations(),
|
kubeInformer.Admissionregistration().V1beta1().ValidatingWebhookConfigurations(),
|
||||||
webhookRegistrationClient,
|
webhookRegistrationClient,
|
||||||
runValidationInMutatingWebhook,
|
runValidationInMutatingWebhook,
|
||||||
log.Log.WithName("ResourceWebhookRegister"),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// KYVERNO CRD INFORMER
|
// KYVERNO CRD INFORMER
|
||||||
|
@ -155,19 +127,16 @@ func main() {
|
||||||
configData := config.NewConfigData(
|
configData := config.NewConfigData(
|
||||||
kubeClient,
|
kubeClient,
|
||||||
kubeInformer.Core().V1().ConfigMaps(),
|
kubeInformer.Core().V1().ConfigMaps(),
|
||||||
filterK8Resources,
|
filterK8Resources)
|
||||||
log.Log.WithName("ConfigData"),
|
|
||||||
)
|
|
||||||
|
|
||||||
// Policy meta-data store
|
// Policy meta-data store
|
||||||
policyMetaStore := policystore.NewPolicyStore(pInformer.Kyverno().V1().ClusterPolicies(), log.Log.WithName("PolicyStore"))
|
policyMetaStore := policystore.NewPolicyStore(pInformer.Kyverno().V1().ClusterPolicies())
|
||||||
|
|
||||||
// EVENT GENERATOR
|
// EVENT GENERATOR
|
||||||
// - generate event with retry mechanism
|
// - generate event with retry mechanism
|
||||||
egen := event.NewEventGenerator(
|
egen := event.NewEventGenerator(
|
||||||
client,
|
client,
|
||||||
pInformer.Kyverno().V1().ClusterPolicies(),
|
pInformer.Kyverno().V1().ClusterPolicies())
|
||||||
log.Log.WithName("EventGenerator"))
|
|
||||||
|
|
||||||
// Policy Status Handler - deals with all logic related to policy status
|
// Policy Status Handler - deals with all logic related to policy status
|
||||||
statusSync := policystatus.NewSync(
|
statusSync := policystatus.NewSync(
|
||||||
|
@ -180,9 +149,7 @@ func main() {
|
||||||
client,
|
client,
|
||||||
pInformer.Kyverno().V1().ClusterPolicyViolations(),
|
pInformer.Kyverno().V1().ClusterPolicyViolations(),
|
||||||
pInformer.Kyverno().V1().PolicyViolations(),
|
pInformer.Kyverno().V1().PolicyViolations(),
|
||||||
statusSync.Listener,
|
statusSync.Listener)
|
||||||
log.Log.WithName("PolicyViolationGenerator"),
|
|
||||||
)
|
|
||||||
|
|
||||||
// POLICY CONTROLLER
|
// POLICY CONTROLLER
|
||||||
// - reconciliation policy and policy violation
|
// - reconciliation policy and policy violation
|
||||||
|
@ -198,16 +165,13 @@ func main() {
|
||||||
egen,
|
egen,
|
||||||
pvgen,
|
pvgen,
|
||||||
policyMetaStore,
|
policyMetaStore,
|
||||||
rWebhookWatcher,
|
rWebhookWatcher)
|
||||||
log.Log.WithName("PolicyController"),
|
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
setupLog.Error(err, "Failed to create policy controller")
|
glog.Fatalf("error creating policy controller: %v\n", err)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GENERATE REQUEST GENERATOR
|
// GENERATE REQUEST GENERATOR
|
||||||
grgen := webhookgenerate.NewGenerator(pclient, stopCh, log.Log.WithName("GenerateRequestGenerator"))
|
grgen := webhookgenerate.NewGenerator(pclient, stopCh)
|
||||||
|
|
||||||
// GENERATE CONTROLLER
|
// GENERATE CONTROLLER
|
||||||
// - applies generate rules on resources based on generate requests created by webhook
|
// - applies generate rules on resources based on generate requests created by webhook
|
||||||
|
@ -220,7 +184,6 @@ func main() {
|
||||||
pvgen,
|
pvgen,
|
||||||
kubedynamicInformer,
|
kubedynamicInformer,
|
||||||
statusSync.Listener,
|
statusSync.Listener,
|
||||||
log.Log.WithName("GenerateController"),
|
|
||||||
)
|
)
|
||||||
// GENERATE REQUEST CLEANUP
|
// GENERATE REQUEST CLEANUP
|
||||||
// -- cleans up the generate requests that have not been processed(i.e. state = [Pending, Failed]) for more than defined timeout
|
// -- cleans up the generate requests that have not been processed(i.e. state = [Pending, Failed]) for more than defined timeout
|
||||||
|
@ -230,14 +193,12 @@ func main() {
|
||||||
pInformer.Kyverno().V1().ClusterPolicies(),
|
pInformer.Kyverno().V1().ClusterPolicies(),
|
||||||
pInformer.Kyverno().V1().GenerateRequests(),
|
pInformer.Kyverno().V1().GenerateRequests(),
|
||||||
kubedynamicInformer,
|
kubedynamicInformer,
|
||||||
log.Log.WithName("GenerateCleanUpController"),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// CONFIGURE CERTIFICATES
|
// CONFIGURE CERTIFICATES
|
||||||
tlsPair, err := client.InitTLSPemPair(clientConfig, fqdncn)
|
tlsPair, err := client.InitTLSPemPair(clientConfig, fqdncn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
setupLog.Error(err, "Failed to initialize TLS key/certificate pair")
|
glog.Fatalf("Failed to initialize TLS key/certificate pair: %v\n", err)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// WEBHOOK REGISTRATION
|
// WEBHOOK REGISTRATION
|
||||||
|
@ -246,8 +207,7 @@ func main() {
|
||||||
// resource webhook confgiuration is generated dynamically in the webhook server and policy controller
|
// resource webhook confgiuration is generated dynamically in the webhook server and policy controller
|
||||||
// based on the policy resources created
|
// based on the policy resources created
|
||||||
if err = webhookRegistrationClient.Register(); err != nil {
|
if err = webhookRegistrationClient.Register(); err != nil {
|
||||||
setupLog.Error(err, "Failed to register Admission webhooks")
|
glog.Fatalf("Failed registering Admission Webhooks: %v\n", err)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sync openAPI definitions of resources
|
// Sync openAPI definitions of resources
|
||||||
|
@ -274,12 +234,9 @@ func main() {
|
||||||
pvgen,
|
pvgen,
|
||||||
grgen,
|
grgen,
|
||||||
rWebhookWatcher,
|
rWebhookWatcher,
|
||||||
cleanUp,
|
cleanUp)
|
||||||
log.Log.WithName("WebhookServer"),
|
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
setupLog.Error(err, "Failed to create webhook server")
|
glog.Fatalf("Unable to create webhook server: %v\n", err)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
// Start the components
|
// Start the components
|
||||||
pInformer.Start(stopCh)
|
pInformer.Start(stopCh)
|
||||||
|
@ -317,5 +274,18 @@ func main() {
|
||||||
// resource cleanup
|
// resource cleanup
|
||||||
// remove webhook configurations
|
// remove webhook configurations
|
||||||
<-cleanUp
|
<-cleanUp
|
||||||
setupLog.Info("Kyverno shutdown successful")
|
glog.Info("successful shutdown of kyverno controller")
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
flag.StringVar(&filterK8Resources, "filterK8Resources", "", "k8 resource in format [kind,namespace,name] where policy is not evaluated by the admission webhook. example --filterKind \"[Deployment, kyverno, kyverno]\" --filterKind \"[Deployment, kyverno, kyverno],[Events, *, *]\"")
|
||||||
|
flag.IntVar(&webhookTimeout, "webhooktimeout", 3, "timeout for webhook configurations")
|
||||||
|
flag.StringVar(&kubeconfig, "kubeconfig", "", "Path to a kubeconfig. Only required if out-of-cluster.")
|
||||||
|
flag.StringVar(&serverIP, "serverIP", "", "IP address where Kyverno controller runs. Only required if out-of-cluster.")
|
||||||
|
flag.StringVar(&runValidationInMutatingWebhook, "runValidationInMutatingWebhook", "", "Validation will also be done using the mutation webhook, set to 'true' to enable. Older kubernetes versions do not work properly when a validation webhook is registered.")
|
||||||
|
|
||||||
|
// Generate CSR with CN as FQDN due to https://github.com/nirmata/kyverno/issues/542
|
||||||
|
flag.BoolVar(&fqdncn, "fqdn-as-cn", false, "use FQDN as Common Name in CSR")
|
||||||
|
config.LogDefaultFlags()
|
||||||
|
flag.Parse()
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,6 +109,8 @@ spec:
|
||||||
type: string
|
type: string
|
||||||
exclude:
|
exclude:
|
||||||
type: object
|
type: object
|
||||||
|
required:
|
||||||
|
- resources
|
||||||
properties:
|
properties:
|
||||||
roles:
|
roles:
|
||||||
type: array
|
type: array
|
||||||
|
|
|
@ -109,6 +109,8 @@ spec:
|
||||||
type: string
|
type: string
|
||||||
exclude:
|
exclude:
|
||||||
type: object
|
type: object
|
||||||
|
required:
|
||||||
|
- resources
|
||||||
properties:
|
properties:
|
||||||
roles:
|
roles:
|
||||||
type: array
|
type: array
|
||||||
|
|
32
go.mod
32
go.mod
|
@ -5,37 +5,39 @@ go 1.13
|
||||||
require (
|
require (
|
||||||
github.com/cenkalti/backoff v2.2.1+incompatible
|
github.com/cenkalti/backoff v2.2.1+incompatible
|
||||||
github.com/evanphx/json-patch v4.5.0+incompatible
|
github.com/evanphx/json-patch v4.5.0+incompatible
|
||||||
github.com/go-logr/logr v0.1.0
|
github.com/gogo/protobuf v1.3.1 // indirect
|
||||||
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
|
||||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7 // indirect
|
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7 // indirect
|
||||||
github.com/googleapis/gnostic v0.3.1
|
github.com/googleapis/gnostic v0.3.1
|
||||||
|
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
|
||||||
github.com/hashicorp/golang-lru v0.5.3 // indirect
|
github.com/hashicorp/golang-lru v0.5.3 // indirect
|
||||||
github.com/imdario/mergo v0.3.8 // indirect
|
github.com/imdario/mergo v0.3.8 // indirect
|
||||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af
|
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af
|
||||||
github.com/json-iterator/go v1.1.9 // indirect
|
github.com/json-iterator/go v1.1.9 // indirect
|
||||||
github.com/minio/minio v0.0.0-20200114012931-30922148fbb5
|
github.com/minio/minio v0.0.0-20200114012931-30922148fbb5
|
||||||
|
github.com/ory/go-acc v0.1.0 // indirect
|
||||||
|
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
|
||||||
github.com/spf13/cobra v0.0.5
|
github.com/spf13/cobra v0.0.5
|
||||||
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
github.com/tevino/abool v0.0.0-20170917061928-9b9efcf221b5
|
github.com/tevino/abool v0.0.0-20170917061928-9b9efcf221b5
|
||||||
|
golang.org/x/crypto v0.0.0-20200109152110-61a87790db17 // indirect
|
||||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 // indirect
|
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 // indirect
|
||||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect
|
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect
|
||||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1 // indirect
|
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1 // indirect
|
||||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect
|
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect
|
||||||
google.golang.org/appengine v1.6.5 // indirect
|
google.golang.org/appengine v1.6.5 // indirect
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
|
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||||
gopkg.in/yaml.v2 v2.2.8
|
gopkg.in/yaml.v2 v2.2.7
|
||||||
gotest.tools v2.2.0+incompatible
|
gotest.tools v2.2.0+incompatible
|
||||||
k8s.io/api v0.17.4
|
k8s.io/api v0.0.0-20190409021203-6e4e0e4f393b
|
||||||
k8s.io/apimachinery v0.17.4
|
k8s.io/apimachinery v0.0.0-20190404173353-6a84e37a896d
|
||||||
k8s.io/cli-runtime v0.17.4
|
k8s.io/cli-runtime v0.0.0-20191004110135-b9eb767d2e1a
|
||||||
k8s.io/client-go v0.17.4
|
k8s.io/client-go v11.0.1-0.20190516230509-ae8359b20417+incompatible
|
||||||
k8s.io/klog v1.0.0
|
k8s.io/klog v1.0.0 // indirect
|
||||||
k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c
|
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a
|
||||||
k8s.io/utils v0.0.0-20200109141947-94aeca20bf09 // indirect
|
k8s.io/utils v0.0.0-20200109141947-94aeca20bf09 // indirect
|
||||||
sigs.k8s.io/controller-runtime v0.5.0
|
sigs.k8s.io/kustomize v2.0.3+incompatible // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
// Added for go1.13 migration https://github.com/golang/go/issues/32805
|
// Added for go1.13 migration https://github.com/golang/go/issues/32805
|
||||||
replace (
|
replace github.com/gorilla/rpc v1.2.0+incompatible => github.com/gorilla/rpc v1.2.0
|
||||||
github.com/gorilla/rpc v1.2.0+incompatible => github.com/gorilla/rpc v1.2.0
|
|
||||||
k8s.io/code-generator => k8s.io/code-generator v0.0.0-20200306081859-6a048a382944
|
|
||||||
k8s.io/component-base => k8s.io/component-base v0.0.0-20190612130303-4062e14deebe
|
|
||||||
)
|
|
||||||
|
|
185
go.sum
185
go.sum
|
@ -15,13 +15,6 @@ github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiU
|
||||||
github.com/Azure/azure-storage-blob-go v0.8.0/go.mod h1:lPI3aLPpuLTeUwh1sViKXFxwl2B6teiRqI0deQUvsw0=
|
github.com/Azure/azure-storage-blob-go v0.8.0/go.mod h1:lPI3aLPpuLTeUwh1sViKXFxwl2B6teiRqI0deQUvsw0=
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
||||||
github.com/Azure/go-autorest v11.7.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
|
github.com/Azure/go-autorest v11.7.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
|
||||||
github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
|
|
||||||
github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0=
|
|
||||||
github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA=
|
|
||||||
github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
|
|
||||||
github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
|
|
||||||
github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc=
|
|
||||||
github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
|
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||||
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
|
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
|
||||||
|
@ -33,29 +26,21 @@ github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8
|
||||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||||
github.com/PuerkitoBio/purell v1.0.0 h1:0GoNN3taZV6QI81IXgCbxMyEaJDXMSIjArYBCYzVVvs=
|
github.com/PuerkitoBio/purell v1.0.0 h1:0GoNN3taZV6QI81IXgCbxMyEaJDXMSIjArYBCYzVVvs=
|
||||||
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||||
github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
|
||||||
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
|
|
||||||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
|
||||||
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2 h1:JCHLVE3B+kJde7bIEo5N4J+ZbLhp0J1Fs+ulyRws4gE=
|
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2 h1:JCHLVE3B+kJde7bIEo5N4J+ZbLhp0J1Fs+ulyRws4gE=
|
||||||
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
|
|
||||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
|
||||||
github.com/Shopify/sarama v1.24.1/go.mod h1:fGP8eQ6PugKEI0iUETYYtnP6d1pH/bdDMTel1X5ajsU=
|
github.com/Shopify/sarama v1.24.1/go.mod h1:fGP8eQ6PugKEI0iUETYYtnP6d1pH/bdDMTel1X5ajsU=
|
||||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||||
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
|
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
|
||||||
github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
|
|
||||||
github.com/ajg/form v0.0.0-20160822230020-523a5da1a92f/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
|
github.com/ajg/form v0.0.0-20160822230020-523a5da1a92f/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
|
||||||
github.com/alecthomas/participle v0.2.1/go.mod h1:SW6HZGeZgSIpcUWX3fXpfZhuaWHnmoD5KCVaqSaNTkk=
|
github.com/alecthomas/participle v0.2.1/go.mod h1:SW6HZGeZgSIpcUWX3fXpfZhuaWHnmoD5KCVaqSaNTkk=
|
||||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20190307165228-86c17b95fcd5/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
|
github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20190307165228-86c17b95fcd5/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
|
||||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
|
||||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||||
github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878/go.mod h1:3AMJUQhVx52RsWOnlkpikZr01T/yAVN2gn0861vByNg=
|
github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878/go.mod h1:3AMJUQhVx52RsWOnlkpikZr01T/yAVN2gn0861vByNg=
|
||||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||||
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
|
||||||
github.com/aws/aws-sdk-go v1.20.21/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
github.com/aws/aws-sdk-go v1.20.21/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||||
github.com/aws/aws-sdk-go v1.23.19/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
github.com/aws/aws-sdk-go v1.23.19/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||||
github.com/aws/aws-xray-sdk-go v0.9.4/go.mod h1:XtMKdBQfpVut+tJEwI7+dJFRxxRdxHDyVNp2tHXRq04=
|
github.com/aws/aws-xray-sdk-go v0.9.4/go.mod h1:XtMKdBQfpVut+tJEwI7+dJFRxxRdxHDyVNp2tHXRq04=
|
||||||
|
@ -65,7 +50,6 @@ github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NR
|
||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||||
github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
|
||||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
|
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
|
||||||
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
|
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
|
||||||
github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
|
github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
|
||||||
|
@ -80,7 +64,6 @@ github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
||||||
github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk=
|
github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk=
|
||||||
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
|
|
||||||
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
|
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
|
||||||
github.com/codegangsta/negroni v1.0.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2iZY63YTKWo0=
|
github.com/codegangsta/negroni v1.0.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2iZY63YTKWo0=
|
||||||
github.com/containerd/continuity v0.0.0-20181203112020-004b46473808/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
|
github.com/containerd/continuity v0.0.0-20181203112020-004b46473808/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
|
||||||
|
@ -90,16 +73,11 @@ github.com/coreos/bbolt v1.3.3/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkE
|
||||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||||
github.com/coreos/etcd v3.3.12+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
github.com/coreos/etcd v3.3.12+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||||
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
||||||
github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
|
|
||||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||||
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
|
||||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||||
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
|
||||||
github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
|
||||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
|
||||||
github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
@ -107,13 +85,9 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||||
github.com/djherbis/atime v1.0.0/go.mod h1:5W+KBIuTwVGcqjIfaTwt+KSYX1o6uep8dtevevQP/f8=
|
github.com/djherbis/atime v1.0.0/go.mod h1:5W+KBIuTwVGcqjIfaTwt+KSYX1o6uep8dtevevQP/f8=
|
||||||
github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
|
||||||
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||||
github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||||
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
|
||||||
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
|
|
||||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
||||||
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
|
||||||
github.com/dustin/go-humanize v0.0.0-20180713052910-9f541cc9db5d/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
github.com/dustin/go-humanize v0.0.0-20180713052910-9f541cc9db5d/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||||
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
|
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
|
||||||
|
@ -122,14 +96,9 @@ github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1
|
||||||
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
||||||
github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts=
|
github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts=
|
||||||
github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
|
github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
|
||||||
github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
|
|
||||||
github.com/elazarl/goproxy v0.0.0-20181003060214-f58a169a71a5/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
|
github.com/elazarl/goproxy v0.0.0-20181003060214-f58a169a71a5/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
|
||||||
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633 h1:H2pdYOb3KQ1/YsqVWoWNLQO+fusocsw354rqGTZtAgw=
|
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633 h1:H2pdYOb3KQ1/YsqVWoWNLQO+fusocsw354rqGTZtAgw=
|
||||||
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
||||||
github.com/emicklei/go-restful v2.9.5+incompatible h1:spTtZBk5DYEvbxMVutUuTyh1Ao2r4iyvLdACqsl/Ljk=
|
|
||||||
github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
|
||||||
github.com/evanphx/json-patch v0.0.0-20190203023257-5858425f7550/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
|
||||||
github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
|
||||||
github.com/evanphx/json-patch v4.5.0+incompatible h1:ouOWdg56aJriqS0huScTkVXPC5IcNrDCXZ6OoTAWu7M=
|
github.com/evanphx/json-patch v4.5.0+incompatible h1:ouOWdg56aJriqS0huScTkVXPC5IcNrDCXZ6OoTAWu7M=
|
||||||
github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||||
|
@ -144,68 +113,21 @@ github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2H
|
||||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 h1:Mn26/9ZMNWSw9C9ERFA1PUxfmGpolnw2v0bKOREu5ew=
|
github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 h1:Mn26/9ZMNWSw9C9ERFA1PUxfmGpolnw2v0bKOREu5ew=
|
||||||
github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I=
|
github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I=
|
||||||
github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
|
|
||||||
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
|
|
||||||
github.com/go-bindata/go-bindata v3.1.1+incompatible/go.mod h1:xK8Dsgwmeed+BBsSy2XTopBn/8uK2HWuGSnA11C3Joo=
|
github.com/go-bindata/go-bindata v3.1.1+incompatible/go.mod h1:xK8Dsgwmeed+BBsSy2XTopBn/8uK2HWuGSnA11C3Joo=
|
||||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc=
|
github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc=
|
||||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||||
github.com/go-logr/logr v0.1.0 h1:M1Tv3VzNlEHg6uyACnRdtrploV2P7wZqH8BoQMtz0cg=
|
|
||||||
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
|
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
|
||||||
github.com/go-logr/zapr v0.1.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk=
|
|
||||||
github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
|
github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
|
||||||
github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI=
|
|
||||||
github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
|
|
||||||
github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
|
|
||||||
github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk=
|
|
||||||
github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU=
|
|
||||||
github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
|
|
||||||
github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
|
|
||||||
github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94=
|
|
||||||
github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1 h1:wSt/4CYxs70xbATrGXhokKF1i0tZjENLOo1ioIO13zk=
|
github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1 h1:wSt/4CYxs70xbATrGXhokKF1i0tZjENLOo1ioIO13zk=
|
||||||
github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0=
|
github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0=
|
||||||
github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
|
|
||||||
github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
|
|
||||||
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
|
|
||||||
github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w=
|
|
||||||
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
|
||||||
github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9 h1:tF+augKRWlWx0J0B7ZyyKSiTyV6E1zZe+7b3qQlcEf8=
|
github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9 h1:tF+augKRWlWx0J0B7ZyyKSiTyV6E1zZe+7b3qQlcEf8=
|
||||||
github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg=
|
github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg=
|
||||||
github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
|
|
||||||
github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
|
|
||||||
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
|
|
||||||
github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o=
|
|
||||||
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
|
|
||||||
github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
|
|
||||||
github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
|
|
||||||
github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
|
|
||||||
github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs=
|
|
||||||
github.com/go-openapi/loads v0.19.4/go.mod h1:zZVHonKd8DXyxyw4yfnVjPzBjIQcLt0CCsn0N0ZrQsk=
|
|
||||||
github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA=
|
|
||||||
github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64=
|
|
||||||
github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4=
|
|
||||||
github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501 h1:C1JKChikHGpXwT5UQDFaryIpDtyyGL/CR6C2kB7F1oc=
|
github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501 h1:C1JKChikHGpXwT5UQDFaryIpDtyyGL/CR6C2kB7F1oc=
|
||||||
github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc=
|
github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc=
|
||||||
github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
|
|
||||||
github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
|
|
||||||
github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY=
|
|
||||||
github.com/go-openapi/spec v0.19.3 h1:0XRyw8kguri6Yw4SxhsQA/atC88yqrk0+G4YhI2wabc=
|
|
||||||
github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
|
|
||||||
github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
|
|
||||||
github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
|
|
||||||
github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY=
|
|
||||||
github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU=
|
|
||||||
github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87 h1:zP3nY8Tk2E6RTkqGYrarZXuzh+ffyLDljLxCy1iJw80=
|
github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87 h1:zP3nY8Tk2E6RTkqGYrarZXuzh+ffyLDljLxCy1iJw80=
|
||||||
github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
|
github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
|
||||||
github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
|
|
||||||
github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
|
|
||||||
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
|
||||||
github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY=
|
|
||||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
|
||||||
github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4=
|
|
||||||
github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA=
|
|
||||||
github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4=
|
|
||||||
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
|
@ -379,18 +301,14 @@ github.com/gobuffalo/x v0.0.0-20181003152136-452098b06085/go.mod h1:WevpGD+5YOre
|
||||||
github.com/gobuffalo/x v0.0.0-20181007152206-913e47c59ca7/go.mod h1:9rDPXaB3kXdKWzMc4odGQQdG2e2DIEmANy5aSJ9yesY=
|
github.com/gobuffalo/x v0.0.0-20181007152206-913e47c59ca7/go.mod h1:9rDPXaB3kXdKWzMc4odGQQdG2e2DIEmANy5aSJ9yesY=
|
||||||
github.com/gofrs/uuid v3.1.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
github.com/gofrs/uuid v3.1.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||||
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||||
github.com/gogo/protobuf v0.0.0-20171007142547-342cbe0a0415/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
|
||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||||
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
|
||||||
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
|
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
|
||||||
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||||
github.com/golang/gddo v0.0.0-20180828051604-96d2a289f41e/go.mod h1:xEhNfoBDX1hzLm2Nf80qUvZ2sVwoMZ8d6IE2SrsQfh4=
|
github.com/golang/gddo v0.0.0-20180828051604-96d2a289f41e/go.mod h1:xEhNfoBDX1hzLm2Nf80qUvZ2sVwoMZ8d6IE2SrsQfh4=
|
||||||
github.com/golang/gddo v0.0.0-20190904175337-72a348e765d2/go.mod h1:xEhNfoBDX1hzLm2Nf80qUvZ2sVwoMZ8d6IE2SrsQfh4=
|
github.com/golang/gddo v0.0.0-20190904175337-72a348e765d2/go.mod h1:xEhNfoBDX1hzLm2Nf80qUvZ2sVwoMZ8d6IE2SrsQfh4=
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
|
||||||
github.com/golang/groupcache v0.0.0-20180513044358-24b0969c4cb7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
|
||||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7 h1:5ZkaAPbicIKTF2I64qf5Fh8Aa83Q/dnOafMYV0OMwjA=
|
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7 h1:5ZkaAPbicIKTF2I64qf5Fh8Aa83Q/dnOafMYV0OMwjA=
|
||||||
|
@ -415,7 +333,6 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
|
||||||
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
|
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
|
||||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
|
github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
|
||||||
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
|
|
||||||
github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
|
github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||||
|
@ -424,13 +341,11 @@ github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OI
|
||||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/uuid v1.1.0 h1:Jf4mxPC/ziBnoPIdpQdPJ9OeiomAUHLvxmPRSPH9m4s=
|
github.com/google/uuid v1.1.0 h1:Jf4mxPC/ziBnoPIdpQdPJ9OeiomAUHLvxmPRSPH9m4s=
|
||||||
github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
|
||||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||||
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
|
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
|
||||||
github.com/googleapis/gnostic v0.3.1 h1:WeAefnSUHlBb0iJKwxFDZdbfGwkd7xRNuV+IpXMJhYk=
|
github.com/googleapis/gnostic v0.3.1 h1:WeAefnSUHlBb0iJKwxFDZdbfGwkd7xRNuV+IpXMJhYk=
|
||||||
github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU=
|
github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU=
|
||||||
github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
|
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181004151105-1babbf986f6f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20181004151105-1babbf986f6f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20190328170749-bb2674552d8f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20190328170749-bb2674552d8f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
|
@ -443,12 +358,9 @@ github.com/gorilla/rpc v1.2.0/go.mod h1:V4h9r+4sF5HnzqbwIez0fKSpANP0zlYd3qR7p36j
|
||||||
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
||||||
github.com/gorilla/sessions v1.1.2/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w=
|
github.com/gorilla/sessions v1.1.2/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w=
|
||||||
github.com/gorilla/sessions v1.1.3/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w=
|
github.com/gorilla/sessions v1.1.3/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w=
|
||||||
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
|
||||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||||
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY=
|
github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY=
|
||||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM=
|
|
||||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
|
||||||
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA=
|
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA=
|
||||||
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||||
|
@ -456,7 +368,6 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de
|
||||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
|
||||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||||
|
@ -488,8 +399,6 @@ github.com/hashicorp/vault/sdk v0.1.13/go.mod h1:B+hVj7TpuQY1Y/GPbCpffmgd+tSEwvh
|
||||||
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
|
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
|
||||||
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
|
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
|
||||||
github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
|
||||||
github.com/imdario/mergo v0.3.8 h1:CGgOkSJeqMRmt0D9XLWExdT4m4F1vd3FV3VPt+0VxkQ=
|
github.com/imdario/mergo v0.3.8 h1:CGgOkSJeqMRmt0D9XLWExdT4m4F1vd3FV3VPt+0VxkQ=
|
||||||
github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||||
github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf/go.mod h1:hyb9oH7vZsitZCiBt0ZvifOrB+qc8PS5IiilCIb87rg=
|
github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf/go.mod h1:hyb9oH7vZsitZCiBt0ZvifOrB+qc8PS5IiilCIb87rg=
|
||||||
|
@ -506,10 +415,7 @@ github.com/joho/godotenv v1.2.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqx
|
||||||
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
||||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||||
github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||||
github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
|
||||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
|
||||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
|
||||||
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
|
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
|
||||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||||
|
@ -539,14 +445,11 @@ github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
|
|
||||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/kurin/blazer v0.5.4-0.20190613185654-cf2f27cc0be3/go.mod h1:4FCXMUWo9DllR2Do4TtBd377ezyAJ51vB5uTBjt0pGU=
|
github.com/kurin/blazer v0.5.4-0.20190613185654-cf2f27cc0be3/go.mod h1:4FCXMUWo9DllR2Do4TtBd377ezyAJ51vB5uTBjt0pGU=
|
||||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||||
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=
|
|
||||||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
|
|
||||||
github.com/luna-duclos/instrumentedsql v1.1.2/go.mod h1:4LGbEqDnopzNAiyxPPDXhLspyunZxgPTMJBKtC6U0BQ=
|
github.com/luna-duclos/instrumentedsql v1.1.2/go.mod h1:4LGbEqDnopzNAiyxPPDXhLspyunZxgPTMJBKtC6U0BQ=
|
||||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
|
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
|
||||||
|
@ -554,12 +457,6 @@ github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czP
|
||||||
github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||||
github.com/mailru/easyjson v0.0.0-20180730094502-03f2033d19d5 h1:0x4qcEHDpruK6ML/m/YSlFUUu0UpRD3I2PHsNCuGnyA=
|
github.com/mailru/easyjson v0.0.0-20180730094502-03f2033d19d5 h1:0x4qcEHDpruK6ML/m/YSlFUUu0UpRD3I2PHsNCuGnyA=
|
||||||
github.com/mailru/easyjson v0.0.0-20180730094502-03f2033d19d5/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
github.com/mailru/easyjson v0.0.0-20180730094502-03f2033d19d5/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||||
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
|
||||||
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
|
||||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
|
||||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
|
||||||
github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM=
|
|
||||||
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
|
|
||||||
github.com/markbates/deplist v1.0.4/go.mod h1:gRRbPbbuA8TmMiRvaOzUlRfzfjeCCBqX2A6arxN01MM=
|
github.com/markbates/deplist v1.0.4/go.mod h1:gRRbPbbuA8TmMiRvaOzUlRfzfjeCCBqX2A6arxN01MM=
|
||||||
github.com/markbates/deplist v1.0.5/go.mod h1:gRRbPbbuA8TmMiRvaOzUlRfzfjeCCBqX2A6arxN01MM=
|
github.com/markbates/deplist v1.0.5/go.mod h1:gRRbPbbuA8TmMiRvaOzUlRfzfjeCCBqX2A6arxN01MM=
|
||||||
github.com/markbates/going v1.0.2/go.mod h1:UWCk3zm0UKefHZ7l8BNqi26UyiEMniznk8naLdTcy6c=
|
github.com/markbates/going v1.0.2/go.mod h1:UWCk3zm0UKefHZ7l8BNqi26UyiEMniznk8naLdTcy6c=
|
||||||
|
@ -586,7 +483,6 @@ github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx
|
||||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||||
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||||
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||||
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
|
||||||
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||||
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||||
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||||
|
@ -629,9 +525,7 @@ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwd
|
||||||
github.com/monoculum/formam v0.0.0-20180901015400-4e68be1d79ba/go.mod h1:RKgILGEJq24YyJ2ban8EO0RUVSJlF1pGsEvoLEACr/Q=
|
github.com/monoculum/formam v0.0.0-20180901015400-4e68be1d79ba/go.mod h1:RKgILGEJq24YyJ2ban8EO0RUVSJlF1pGsEvoLEACr/Q=
|
||||||
github.com/moul/http2curl v0.0.0-20170919181001-9ac6cf4d929b/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ=
|
github.com/moul/http2curl v0.0.0-20170919181001-9ac6cf4d929b/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ=
|
||||||
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
|
||||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
|
|
||||||
github.com/nats-io/gnatsd v1.4.1/go.mod h1:nqco77VO78hLCJpIcVfygDP2rPGfsEHkGTUk94uh5DQ=
|
github.com/nats-io/gnatsd v1.4.1/go.mod h1:nqco77VO78hLCJpIcVfygDP2rPGfsEHkGTUk94uh5DQ=
|
||||||
github.com/nats-io/go-nats v1.7.2/go.mod h1:+t7RHT5ApZebkrQdnn6AhQJmhJJiKAvJUio1PiiCtj0=
|
github.com/nats-io/go-nats v1.7.2/go.mod h1:+t7RHT5ApZebkrQdnn6AhQJmhJJiKAvJUio1PiiCtj0=
|
||||||
github.com/nats-io/go-nats-streaming v0.4.4/go.mod h1:gfq4R3c9sKAINOpelo0gn/b9QDMBZnmrttcsNF+lqyo=
|
github.com/nats-io/go-nats-streaming v0.4.4/go.mod h1:gfq4R3c9sKAINOpelo0gn/b9QDMBZnmrttcsNF+lqyo=
|
||||||
|
@ -651,21 +545,15 @@ github.com/nsqio/go-nsq v1.0.7/go.mod h1:XP5zaUs3pqf+Q71EqUJs3HYfBIqfK6G83WQMdNN
|
||||||
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
|
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
|
||||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||||
github.com/oleiade/reflections v1.0.0/go.mod h1:RbATFBbKYkVdqmSFtx13Bb/tVhR0lgOBXunWTZKeL4w=
|
github.com/oleiade/reflections v1.0.0/go.mod h1:RbATFBbKYkVdqmSFtx13Bb/tVhR0lgOBXunWTZKeL4w=
|
||||||
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
|
|
||||||
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c h1:Hww8mOyEKTeON4bZn7FrlLismspbPc1teNRUVH7wLQ8=
|
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c h1:Hww8mOyEKTeON4bZn7FrlLismspbPc1teNRUVH7wLQ8=
|
||||||
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
|
||||||
github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
|
||||||
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c h1:eSfnfIuwhxZyULg1NNuZycJcYkjYVGYe7FczwQReM6U=
|
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c h1:eSfnfIuwhxZyULg1NNuZycJcYkjYVGYe7FczwQReM6U=
|
||||||
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||||
github.com/onsi/gomega v0.0.0-20190113212917-5533ce8a0da3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
|
||||||
github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||||
github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||||
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
|
||||||
github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
|
|
||||||
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||||
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
||||||
github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
|
github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
|
||||||
|
@ -703,12 +591,10 @@ github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||||
github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
|
|
||||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||||
github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
|
github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
|
||||||
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
|
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
|
||||||
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
|
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
|
||||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
|
||||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||||
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
|
@ -716,12 +602,10 @@ github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7q
|
||||||
github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||||
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||||
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
|
||||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
|
||||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||||
github.com/rcrowley/go-metrics v0.0.0-20190704165056-9c2d0518ed81/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
github.com/rcrowley/go-metrics v0.0.0-20190704165056-9c2d0518ed81/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||||
|
@ -782,7 +666,6 @@ github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb6
|
||||||
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
|
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
|
||||||
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
||||||
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
|
||||||
github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||||
|
@ -794,7 +677,6 @@ github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DM
|
||||||
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
|
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
|
||||||
github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||||
|
@ -808,7 +690,6 @@ github.com/tidwall/gjson v1.3.5/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJH
|
||||||
github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E=
|
github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E=
|
||||||
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||||
github.com/tidwall/sjson v1.0.4/go.mod h1:bURseu1nuBkFpIES5cz6zBtjmYeOQmEESshn7VpF15Y=
|
github.com/tidwall/sjson v1.0.4/go.mod h1:bURseu1nuBkFpIES5cz6zBtjmYeOQmEESshn7VpF15Y=
|
||||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
|
||||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||||
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
|
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
|
||||||
github.com/uber-go/atomic v1.3.2/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g=
|
github.com/uber-go/atomic v1.3.2/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g=
|
||||||
|
@ -820,10 +701,8 @@ github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljT
|
||||||
github.com/ugorji/go/codec v1.1.5-pre/go.mod h1:tULtS6Gy1AE1yCENaw4Vb//HLH5njI2tfCQDUqRd8fI=
|
github.com/ugorji/go/codec v1.1.5-pre/go.mod h1:tULtS6Gy1AE1yCENaw4Vb//HLH5njI2tfCQDUqRd8fI=
|
||||||
github.com/unrolled/secure v0.0.0-20180918153822-f340ee86eb8b/go.mod h1:mnPT77IAdsi/kV7+Es7y+pXALeV3h7G6dQF6mNYjcLA=
|
github.com/unrolled/secure v0.0.0-20180918153822-f340ee86eb8b/go.mod h1:mnPT77IAdsi/kV7+Es7y+pXALeV3h7G6dQF6mNYjcLA=
|
||||||
github.com/unrolled/secure v0.0.0-20181005190816-ff9db2ff917f/go.mod h1:mnPT77IAdsi/kV7+Es7y+pXALeV3h7G6dQF6mNYjcLA=
|
github.com/unrolled/secure v0.0.0-20181005190816-ff9db2ff917f/go.mod h1:mnPT77IAdsi/kV7+Es7y+pXALeV3h7G6dQF6mNYjcLA=
|
||||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
|
||||||
github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4=
|
github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4=
|
||||||
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
|
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
|
||||||
github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw=
|
|
||||||
github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=
|
github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=
|
||||||
github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
|
github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||||
|
@ -833,10 +712,6 @@ github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c/go.mod h1:UrdRz5enIKZ63M
|
||||||
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
|
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
|
||||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||||
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||||
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
|
|
||||||
go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
|
|
||||||
go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
|
|
||||||
go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
|
|
||||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||||
go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA=
|
go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA=
|
||||||
|
@ -859,22 +734,15 @@ golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85/go.mod h1:6SG95UA2DQfeDnf
|
||||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190102171810-8d7daa0c54b3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20190102171810-8d7daa0c54b3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190103213133-ff983b9c42bc/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20190103213133-ff983b9c42bc/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
|
||||||
golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
||||||
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
|
||||||
golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
|
||||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
|
||||||
golang.org/x/crypto v0.0.0-20191117063200-497ca9f6d64f/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20191117063200-497ca9f6d64f/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20200109152110-61a87790db17 h1:nVJ3guKA9qdkEQ3TUdXI9QSINo2CUPM/cySEvw2w8I0=
|
golang.org/x/crypto v0.0.0-20200109152110-61a87790db17 h1:nVJ3guKA9qdkEQ3TUdXI9QSINo2CUPM/cySEvw2w8I0=
|
||||||
golang.org/x/crypto v0.0.0-20200109152110-61a87790db17/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200109152110-61a87790db17/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975 h1:/Tl7pH94bvbAAHBdZJT947M/+gp0+CqQXDtMRC0fseo=
|
|
||||||
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||||
|
@ -903,22 +771,16 @@ golang.org/x/net v0.0.0-20181207154023-610586996380/go.mod h1:mL1N/T3taQHkDXs73r
|
||||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190206173232-65e2d4e15006/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8=
|
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8=
|
||||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
|
@ -960,11 +822,9 @@ golang.org/x/sys v0.0.0-20190102155601-82a175fd1598/go.mod h1:STP8DvDyc/dI5b8T5h
|
||||||
golang.org/x/sys v0.0.0-20190116161447-11f53e031339/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190116161447-11f53e031339/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
@ -972,10 +832,8 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190523142557-0e01d883c5c5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190523142557-0e01d883c5c5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191105231009-c1f44814a5cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191105231009-c1f44814a5cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1 h1:gZpLHxUX5BdYLA08Lj4YCJNN/jk7KtquiArPoeX0WvA=
|
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1 h1:gZpLHxUX5BdYLA08Lj4YCJNN/jk7KtquiArPoeX0WvA=
|
||||||
|
@ -986,7 +844,6 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3
|
||||||
golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs=
|
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs=
|
||||||
|
@ -1018,7 +875,6 @@ golang.org/x/tools v0.0.0-20190104182027-498d95493402/go.mod h1:n7NCudcB/nEzxVGm
|
||||||
golang.org/x/tools v0.0.0-20190111214448-fc1d57b08d7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20190111214448-fc1d57b08d7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190118193359-16909d206f00/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20190118193359-16909d206f00/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
@ -1028,14 +884,9 @@ golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBn
|
||||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
|
||||||
golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
|
||||||
golang.org/x/tools v0.0.0-20190624190245-7f2218787638/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
golang.org/x/tools v0.0.0-20190624190245-7f2218787638/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
golang.org/x/tools v0.0.0-20190711191110-9a621aea19f8/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
|
golang.org/x/tools v0.0.0-20190711191110-9a621aea19f8/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
|
||||||
golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
gomodules.xyz/jsonpatch/v2 v2.0.1/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU=
|
|
||||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||||
google.golang.org/api v0.5.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
google.golang.org/api v0.5.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||||
|
@ -1067,7 +918,6 @@ google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiq
|
||||||
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||||
google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
|
||||||
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
|
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
|
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
|
||||||
|
@ -1075,15 +925,12 @@ gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUy
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
|
||||||
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
|
||||||
gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||||
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
|
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
|
||||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
|
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
|
||||||
gopkg.in/gorp.v1 v1.7.2/go.mod h1:Wo3h+DBQZIxATwftsglhdD/62zRFPhGhTiu5jUJmCaw=
|
gopkg.in/gorp.v1 v1.7.2/go.mod h1:Wo3h+DBQZIxATwftsglhdD/62zRFPhGhTiu5jUJmCaw=
|
||||||
gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
|
||||||
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||||
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
|
@ -1095,7 +942,6 @@ gopkg.in/jcmturner/gokrb5.v7 v7.2.3/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuv
|
||||||
gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLvuNnlv8=
|
gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLvuNnlv8=
|
||||||
gopkg.in/ldap.v3 v3.0.3/go.mod h1:oxD7NyBuxchC+SgJDE1Q5Od05eGt29SDQVBmV+HYbzw=
|
gopkg.in/ldap.v3 v3.0.3/go.mod h1:oxD7NyBuxchC+SgJDE1Q5Od05eGt29SDQVBmV+HYbzw=
|
||||||
gopkg.in/mail.v2 v2.0.0-20180731213649-a0242b2233b4/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw=
|
gopkg.in/mail.v2 v2.0.0-20180731213649-a0242b2233b4/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw=
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
|
||||||
gopkg.in/olivere/elastic.v5 v5.0.80/go.mod h1:uhHoB4o3bvX5sorxBU29rPcmBQdV2Qfg0FBrx5D6pV0=
|
gopkg.in/olivere/elastic.v5 v5.0.80/go.mod h1:uhHoB4o3bvX5sorxBU29rPcmBQdV2Qfg0FBrx5D6pV0=
|
||||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||||
gopkg.in/square/go-jose.v2 v2.1.9/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
gopkg.in/square/go-jose.v2 v2.1.9/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||||
|
@ -1109,8 +955,6 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
|
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
|
||||||
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
|
||||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
|
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
|
||||||
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
@ -1119,53 +963,24 @@ honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWh
|
||||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
k8s.io/api v0.0.0-20190409021203-6e4e0e4f393b h1:aBGgKJUM9Hk/3AE8WaZIApnTxG35kbuQba2w+SXqezo=
|
k8s.io/api v0.0.0-20190409021203-6e4e0e4f393b h1:aBGgKJUM9Hk/3AE8WaZIApnTxG35kbuQba2w+SXqezo=
|
||||||
k8s.io/api v0.0.0-20190409021203-6e4e0e4f393b/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA=
|
k8s.io/api v0.0.0-20190409021203-6e4e0e4f393b/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA=
|
||||||
k8s.io/api v0.17.2/go.mod h1:BS9fjjLc4CMuqfSO8vgbHPKMt5+SF0ET6u/RVDihTo4=
|
|
||||||
k8s.io/api v0.17.4 h1:HbwOhDapkguO8lTAE8OX3hdF2qp8GtpC9CW/MQATXXo=
|
|
||||||
k8s.io/api v0.17.4/go.mod h1:5qxx6vjmwUVG2nHQTKGlLts8Tbok8PzHl4vHtVFuZCA=
|
|
||||||
k8s.io/apiextensions-apiserver v0.17.2/go.mod h1:4KdMpjkEjjDI2pPfBA15OscyNldHWdBCfsWMDWAmSTs=
|
|
||||||
k8s.io/apimachinery v0.0.0-20190404173353-6a84e37a896d h1:Jmdtdt1ZnoGfWWIIik61Z7nKYgO3J+swQJtPYsP9wHA=
|
k8s.io/apimachinery v0.0.0-20190404173353-6a84e37a896d h1:Jmdtdt1ZnoGfWWIIik61Z7nKYgO3J+swQJtPYsP9wHA=
|
||||||
k8s.io/apimachinery v0.0.0-20190404173353-6a84e37a896d/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0=
|
k8s.io/apimachinery v0.0.0-20190404173353-6a84e37a896d/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0=
|
||||||
k8s.io/apimachinery v0.0.0-20190612125636-6a5db36e93ad/go.mod h1:I4A+glKBHiTgiEjQiCCQfCAIcIMFGt291SmsvcrFzJA=
|
|
||||||
k8s.io/apimachinery v0.17.2/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg=
|
|
||||||
k8s.io/apimachinery v0.17.4 h1:UzM+38cPUJnzqSQ+E1PY4YxMHIzQyCg29LOoGfo79Zw=
|
|
||||||
k8s.io/apimachinery v0.17.4/go.mod h1:gxLnyZcGNdZTCLnq3fgzyg2A5BVCHTNDFrw8AmuJ+0g=
|
|
||||||
k8s.io/apiserver v0.17.2/go.mod h1:lBmw/TtQdtxvrTk0e2cgtOxHizXI+d0mmGQURIHQZlo=
|
|
||||||
k8s.io/cli-runtime v0.0.0-20191004110135-b9eb767d2e1a h1:REMzGxu+NpG9dPRsE9my/fw9iYIecz1S8UFFl6hbe18=
|
k8s.io/cli-runtime v0.0.0-20191004110135-b9eb767d2e1a h1:REMzGxu+NpG9dPRsE9my/fw9iYIecz1S8UFFl6hbe18=
|
||||||
k8s.io/cli-runtime v0.0.0-20191004110135-b9eb767d2e1a/go.mod h1:qWnH3/b8sp/l7EvlDh7ulDU3UWA4P4N1NFbEEP791tM=
|
k8s.io/cli-runtime v0.0.0-20191004110135-b9eb767d2e1a/go.mod h1:qWnH3/b8sp/l7EvlDh7ulDU3UWA4P4N1NFbEEP791tM=
|
||||||
k8s.io/cli-runtime v0.17.4 h1:ZIJdxpBEszZqUhydrCoiI5rLXS2J/1AF5xFok2QJ9bc=
|
|
||||||
k8s.io/cli-runtime v0.17.4/go.mod h1:IVW4zrKKx/8gBgNNkhiUIc7nZbVVNhc1+HcQh+PiNHc=
|
|
||||||
k8s.io/client-go v0.17.2/go.mod h1:QAzRgsa0C2xl4/eVpeVAZMvikCn8Nm81yqVx3Kk9XYI=
|
|
||||||
k8s.io/client-go v0.17.4 h1:VVdVbpTY70jiNHS1eiFkUt7ZIJX3txd29nDxxXH4en8=
|
|
||||||
k8s.io/client-go v0.17.4/go.mod h1:ouF6o5pz3is8qU0/qYL2RnoxOPqgfuidYLowytyLJmc=
|
|
||||||
k8s.io/client-go v11.0.1-0.20190516230509-ae8359b20417+incompatible h1:bK03DJulJi9j05gwnXUufcs2j7h4M85YFvJ0dIlQ9k4=
|
k8s.io/client-go v11.0.1-0.20190516230509-ae8359b20417+incompatible h1:bK03DJulJi9j05gwnXUufcs2j7h4M85YFvJ0dIlQ9k4=
|
||||||
k8s.io/client-go v11.0.1-0.20190516230509-ae8359b20417+incompatible/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s=
|
k8s.io/client-go v11.0.1-0.20190516230509-ae8359b20417+incompatible/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s=
|
||||||
k8s.io/code-generator v0.0.0-20200306081859-6a048a382944/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRVkTc=
|
|
||||||
k8s.io/component-base v0.0.0-20190612130303-4062e14deebe/go.mod h1:MmIDXnint3qMN0cqXHKrSiJ2XQKo3J1BPIz7in7NvO0=
|
|
||||||
k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
|
k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
|
||||||
k8s.io/gengo v0.0.0-20200114144118-36b2048a9120/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
|
|
||||||
k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
||||||
k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
||||||
k8s.io/klog v0.3.1/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
|
||||||
k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
|
k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
|
||||||
k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
|
k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
|
||||||
k8s.io/kube-openapi v0.0.0-20190228160746-b3a7cee44a30/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc=
|
|
||||||
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a h1:UcxjrRMyNx/i/y8G7kPvLyy7rfbeuf1PYyBf973pgyU=
|
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a h1:UcxjrRMyNx/i/y8G7kPvLyy7rfbeuf1PYyBf973pgyU=
|
||||||
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
|
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
|
||||||
k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c h1:/KUFqjjqAcY4Us6luF5RDNZ16KJtb49HfR3ZHB9qYXM=
|
|
||||||
k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E=
|
|
||||||
k8s.io/utils v0.0.0-20190221042446-c2654d5206da/go.mod h1:8k8uAuAQ0rXslZKaEWd0c3oVhZz7sSzSiPnVZayjIX0=
|
|
||||||
k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
|
|
||||||
k8s.io/utils v0.0.0-20200109141947-94aeca20bf09 h1:sz6xjn8QP74104YNmJpzLbJ+a3ZtHt0tkD0g8vpdWNw=
|
k8s.io/utils v0.0.0-20200109141947-94aeca20bf09 h1:sz6xjn8QP74104YNmJpzLbJ+a3ZtHt0tkD0g8vpdWNw=
|
||||||
k8s.io/utils v0.0.0-20200109141947-94aeca20bf09/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
|
k8s.io/utils v0.0.0-20200109141947-94aeca20bf09/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
|
||||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||||
sigs.k8s.io/controller-runtime v0.5.0 h1:CbqIy5fbUX+4E9bpnBFd204YAzRYlM9SWW77BbrcDQo=
|
|
||||||
sigs.k8s.io/controller-runtime v0.5.0/go.mod h1:REiJzC7Y00U+2YkMbT8wxgrsX5USpXKGhb2sCtAXiT8=
|
|
||||||
sigs.k8s.io/kustomize v2.0.3+incompatible h1:JUufWFNlI44MdtnjUqVnvh29rR37PQFzPbLXqhyOyX0=
|
sigs.k8s.io/kustomize v2.0.3+incompatible h1:JUufWFNlI44MdtnjUqVnvh29rR37PQFzPbLXqhyOyX0=
|
||||||
sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU=
|
sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU=
|
||||||
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
|
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
|
||||||
sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18=
|
|
||||||
sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw=
|
|
||||||
sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs=
|
sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs=
|
||||||
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
||||||
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
|
|
||||||
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
|
|
||||||
|
|
|
@ -74,7 +74,7 @@ func (in *ClusterPolicy) DeepCopyObject() runtime.Object {
|
||||||
func (in *ClusterPolicyList) DeepCopyInto(out *ClusterPolicyList) {
|
func (in *ClusterPolicyList) DeepCopyInto(out *ClusterPolicyList) {
|
||||||
*out = *in
|
*out = *in
|
||||||
out.TypeMeta = in.TypeMeta
|
out.TypeMeta = in.TypeMeta
|
||||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
out.ListMeta = in.ListMeta
|
||||||
if in.Items != nil {
|
if in.Items != nil {
|
||||||
in, out := &in.Items, &out.Items
|
in, out := &in.Items, &out.Items
|
||||||
*out = make([]ClusterPolicy, len(*in))
|
*out = make([]ClusterPolicy, len(*in))
|
||||||
|
@ -135,7 +135,7 @@ func (in *ClusterPolicyViolation) DeepCopyObject() runtime.Object {
|
||||||
func (in *ClusterPolicyViolationList) DeepCopyInto(out *ClusterPolicyViolationList) {
|
func (in *ClusterPolicyViolationList) DeepCopyInto(out *ClusterPolicyViolationList) {
|
||||||
*out = *in
|
*out = *in
|
||||||
out.TypeMeta = in.TypeMeta
|
out.TypeMeta = in.TypeMeta
|
||||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
out.ListMeta = in.ListMeta
|
||||||
if in.Items != nil {
|
if in.Items != nil {
|
||||||
in, out := &in.Items, &out.Items
|
in, out := &in.Items, &out.Items
|
||||||
*out = make([]ClusterPolicyViolation, len(*in))
|
*out = make([]ClusterPolicyViolation, len(*in))
|
||||||
|
@ -241,7 +241,7 @@ func (in *GenerateRequestContext) DeepCopy() *GenerateRequestContext {
|
||||||
func (in *GenerateRequestList) DeepCopyInto(out *GenerateRequestList) {
|
func (in *GenerateRequestList) DeepCopyInto(out *GenerateRequestList) {
|
||||||
*out = *in
|
*out = *in
|
||||||
out.TypeMeta = in.TypeMeta
|
out.TypeMeta = in.TypeMeta
|
||||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
out.ListMeta = in.ListMeta
|
||||||
if in.Items != nil {
|
if in.Items != nil {
|
||||||
in, out := &in.Items, &out.Items
|
in, out := &in.Items, &out.Items
|
||||||
*out = make([]GenerateRequest, len(*in))
|
*out = make([]GenerateRequest, len(*in))
|
||||||
|
@ -420,7 +420,7 @@ func (in *PolicyViolation) DeepCopyObject() runtime.Object {
|
||||||
func (in *PolicyViolationList) DeepCopyInto(out *PolicyViolationList) {
|
func (in *PolicyViolationList) DeepCopyInto(out *PolicyViolationList) {
|
||||||
*out = *in
|
*out = *in
|
||||||
out.TypeMeta = in.TypeMeta
|
out.TypeMeta = in.TypeMeta
|
||||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
out.ListMeta = in.ListMeta
|
||||||
if in.Items != nil {
|
if in.Items != nil {
|
||||||
in, out := &in.Items, &out.Items
|
in, out := &in.Items, &out.Items
|
||||||
*out = make([]PolicyViolation, len(*in))
|
*out = make([]PolicyViolation, len(*in))
|
||||||
|
|
108
pkg/auth/auth.go
108
pkg/auth/auth.go
|
@ -1,108 +0,0 @@
|
||||||
package auth
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
|
||||||
client "github.com/nirmata/kyverno/pkg/dclient"
|
|
||||||
authorizationv1 "k8s.io/api/authorization/v1"
|
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
|
||||||
)
|
|
||||||
|
|
||||||
//CanIOptions provides utility ti check if user has authorization for the given operation
|
|
||||||
type CanIOptions struct {
|
|
||||||
namespace string
|
|
||||||
verb string
|
|
||||||
kind string
|
|
||||||
client *client.Client
|
|
||||||
log logr.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
//NewCanI returns a new instance of operation access controler evaluator
|
|
||||||
func NewCanI(client *client.Client, kind, namespace, verb string, log logr.Logger) *CanIOptions {
|
|
||||||
o := CanIOptions{
|
|
||||||
client: client,
|
|
||||||
log: log,
|
|
||||||
}
|
|
||||||
|
|
||||||
o.namespace = namespace
|
|
||||||
o.kind = kind
|
|
||||||
o.verb = verb
|
|
||||||
|
|
||||||
return &o
|
|
||||||
}
|
|
||||||
|
|
||||||
//RunAccessCheck checks if the caller can perform the operation
|
|
||||||
// - operation is a combination of namespace, kind, verb
|
|
||||||
// - can only evaluate a single verb
|
|
||||||
// - group version resource is determined from the kind using the discovery client REST mapper
|
|
||||||
// - If disallowed, the reason and evaluationError is avialable in the logs
|
|
||||||
// - each can generates a SelfSubjectAccessReview resource and response is evaluated for permissions
|
|
||||||
func (o *CanIOptions) RunAccessCheck() (bool, error) {
|
|
||||||
// get GroupVersionResource from RESTMapper
|
|
||||||
// get GVR from kind
|
|
||||||
gvr := o.client.DiscoveryClient.GetGVRFromKind(o.kind)
|
|
||||||
if reflect.DeepEqual(gvr, schema.GroupVersionResource{}) {
|
|
||||||
// cannot find GVR
|
|
||||||
return false, fmt.Errorf("failed to get the Group Version Resource for kind %s", o.kind)
|
|
||||||
}
|
|
||||||
|
|
||||||
sar := &authorizationv1.SelfSubjectAccessReview{
|
|
||||||
Spec: authorizationv1.SelfSubjectAccessReviewSpec{
|
|
||||||
ResourceAttributes: &authorizationv1.ResourceAttributes{
|
|
||||||
Namespace: o.namespace,
|
|
||||||
Verb: o.verb,
|
|
||||||
Group: gvr.Group,
|
|
||||||
Resource: gvr.Resource,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
// Set self subject access review
|
|
||||||
// - namespace
|
|
||||||
// - verb
|
|
||||||
// - resource
|
|
||||||
// - subresource
|
|
||||||
logger := o.log.WithValues("kind", sar.Kind, "namespace", sar.Namespace, "name", sar.Name)
|
|
||||||
|
|
||||||
// Create the Resource
|
|
||||||
resp, err := o.client.CreateResource("SelfSubjectAccessReview", "", sar, false)
|
|
||||||
if err != nil {
|
|
||||||
logger.Error(err, "failed to create resource")
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// status.allowed
|
|
||||||
allowed, ok, err := unstructured.NestedBool(resp.Object, "status", "allowed")
|
|
||||||
if !ok {
|
|
||||||
if err != nil {
|
|
||||||
logger.Error(err, "failed to get the field", "field", "status.allowed")
|
|
||||||
}
|
|
||||||
logger.Info("field not found", "field", "status.allowed")
|
|
||||||
}
|
|
||||||
|
|
||||||
if !allowed {
|
|
||||||
// status.reason
|
|
||||||
reason, ok, err := unstructured.NestedString(resp.Object, "status", "reason")
|
|
||||||
if !ok {
|
|
||||||
if err != nil {
|
|
||||||
logger.Error(err, "failed to get the field", "field", "status.reason")
|
|
||||||
}
|
|
||||||
logger.Info("field not found", "field", "status.reason")
|
|
||||||
}
|
|
||||||
// status.evaluationError
|
|
||||||
evaluationError, ok, err := unstructured.NestedString(resp.Object, "status", "evaludationError")
|
|
||||||
if !ok {
|
|
||||||
if err != nil {
|
|
||||||
logger.Error(err, "failed to get the field", "field", "status.evaluationError")
|
|
||||||
}
|
|
||||||
logger.Info("field not found", "field", "status.evaluationError")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reporting ? (just logs)
|
|
||||||
logger.Info("disallowed operation", "reason", reason, "evaluationError", evaluationError)
|
|
||||||
}
|
|
||||||
|
|
||||||
return allowed, nil
|
|
||||||
}
|
|
|
@ -1,48 +0,0 @@
|
||||||
package auth
|
|
||||||
|
|
||||||
// import (
|
|
||||||
// "testing"
|
|
||||||
// "time"
|
|
||||||
|
|
||||||
// "github.com/golang/glog"
|
|
||||||
// "github.com/nirmata/kyverno/pkg/config"
|
|
||||||
// dclient "github.com/nirmata/kyverno/pkg/dclient"
|
|
||||||
// "github.com/nirmata/kyverno/pkg/signal"
|
|
||||||
// )
|
|
||||||
|
|
||||||
// func Test_Auth_pass(t *testing.T) {
|
|
||||||
// // needs running cluster
|
|
||||||
// var kubeconfig string
|
|
||||||
// stopCh := signal.SetupSignalHandler()
|
|
||||||
// kubeconfig = "/Users/shivd/.kube/config"
|
|
||||||
// clientConfig, err := config.CreateClientConfig(kubeconfig)
|
|
||||||
// if err != nil {
|
|
||||||
// glog.Fatalf("Error building kubeconfig: %v\n", err)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // DYNAMIC CLIENT
|
|
||||||
// // - client for all registered resources
|
|
||||||
// // - invalidate local cache of registered resource every 10 seconds
|
|
||||||
// client, err := dclient.NewClient(clientConfig, 10*time.Second, stopCh)
|
|
||||||
// if err != nil {
|
|
||||||
// glog.Fatalf("Error creating client: %v\n", err)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Can i authenticate
|
|
||||||
|
|
||||||
// kind := "Deployment"
|
|
||||||
// namespace := "default"
|
|
||||||
// verb := "test"
|
|
||||||
// canI := NewCanI(client, kind, namespace, verb)
|
|
||||||
// ok, err := canI.RunAccessCheck()
|
|
||||||
// if err != nil {
|
|
||||||
// t.Error(err)
|
|
||||||
// }
|
|
||||||
// if ok {
|
|
||||||
// t.Log("allowed")
|
|
||||||
// } else {
|
|
||||||
// t.Log("notallowed")
|
|
||||||
// }
|
|
||||||
// t.FailNow()
|
|
||||||
|
|
||||||
// }
|
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
"github.com/golang/glog"
|
||||||
kyvernolister "github.com/nirmata/kyverno/pkg/client/listers/kyverno/v1"
|
kyvernolister "github.com/nirmata/kyverno/pkg/client/listers/kyverno/v1"
|
||||||
dclient "github.com/nirmata/kyverno/pkg/dclient"
|
dclient "github.com/nirmata/kyverno/pkg/dclient"
|
||||||
"github.com/nirmata/kyverno/pkg/event"
|
"github.com/nirmata/kyverno/pkg/event"
|
||||||
|
@ -20,9 +20,8 @@ const (
|
||||||
|
|
||||||
// LastReqTime stores the lastrequest times for incoming api-requests
|
// LastReqTime stores the lastrequest times for incoming api-requests
|
||||||
type LastReqTime struct {
|
type LastReqTime struct {
|
||||||
t time.Time
|
t time.Time
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
log logr.Logger
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Time returns the lastrequest time
|
//Time returns the lastrequest time
|
||||||
|
@ -40,17 +39,16 @@ func (t *LastReqTime) SetTime(tm time.Time) {
|
||||||
}
|
}
|
||||||
|
|
||||||
//NewLastReqTime returns a new instance of LastRequestTime store
|
//NewLastReqTime returns a new instance of LastRequestTime store
|
||||||
func NewLastReqTime(log logr.Logger) *LastReqTime {
|
func NewLastReqTime() *LastReqTime {
|
||||||
return &LastReqTime{
|
return &LastReqTime{
|
||||||
t: time.Now(),
|
t: time.Now(),
|
||||||
log: log,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkIfPolicyWithMutateAndGenerateExists(pLister kyvernolister.ClusterPolicyLister, log logr.Logger) bool {
|
func checkIfPolicyWithMutateAndGenerateExists(pLister kyvernolister.ClusterPolicyLister) bool {
|
||||||
policies, err := pLister.ListResources(labels.NewSelector())
|
policies, err := pLister.ListResources(labels.NewSelector())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err, "failed to list cluster policies")
|
glog.Error()
|
||||||
}
|
}
|
||||||
for _, policy := range policies {
|
for _, policy := range policies {
|
||||||
if policy.HasMutateOrValidateOrGenerate() {
|
if policy.HasMutateOrValidateOrGenerate() {
|
||||||
|
@ -64,16 +62,15 @@ func checkIfPolicyWithMutateAndGenerateExists(pLister kyvernolister.ClusterPolic
|
||||||
|
|
||||||
//Run runs the checker and verify the resource update
|
//Run runs the checker and verify the resource update
|
||||||
func (t *LastReqTime) Run(pLister kyvernolister.ClusterPolicyLister, eventGen event.Interface, client *dclient.Client, defaultResync time.Duration, deadline time.Duration, stopCh <-chan struct{}) {
|
func (t *LastReqTime) Run(pLister kyvernolister.ClusterPolicyLister, eventGen event.Interface, client *dclient.Client, defaultResync time.Duration, deadline time.Duration, stopCh <-chan struct{}) {
|
||||||
logger := t.log
|
glog.V(2).Infof("starting default resync for webhook checker with resync time %d nanoseconds", defaultResync)
|
||||||
logger.V(2).Info("tarting default resync for webhook checker", "resyncTime", defaultResync)
|
|
||||||
maxDeadline := deadline * time.Duration(MaxRetryCount)
|
maxDeadline := deadline * time.Duration(MaxRetryCount)
|
||||||
ticker := time.NewTicker(defaultResync)
|
ticker := time.NewTicker(defaultResync)
|
||||||
/// interface to update and increment kyverno webhook status via annotations
|
/// interface to update and increment kyverno webhook status via annotations
|
||||||
statuscontrol := NewVerifyControl(client, eventGen, logger.WithName("StatusControl"))
|
statuscontrol := NewVerifyControl(client, eventGen)
|
||||||
// send the initial update status
|
// send the initial update status
|
||||||
if checkIfPolicyWithMutateAndGenerateExists(pLister, logger) {
|
if checkIfPolicyWithMutateAndGenerateExists(pLister) {
|
||||||
if err := statuscontrol.SuccessStatus(); err != nil {
|
if err := statuscontrol.SuccessStatus(); err != nil {
|
||||||
logger.Error(err, "failed to set 'success' status")
|
glog.Error(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,36 +84,36 @@ func (t *LastReqTime) Run(pLister kyvernolister.ClusterPolicyLister, eventGen ev
|
||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
// if there are no policies then we dont have a webhook on resource.
|
// if there are no policies then we dont have a webhook on resource.
|
||||||
// we indirectly check if the resource
|
// we indirectly check if the resource
|
||||||
if !checkIfPolicyWithMutateAndGenerateExists(pLister, logger) {
|
if !checkIfPolicyWithMutateAndGenerateExists(pLister) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// get current time
|
// get current time
|
||||||
timeDiff := time.Since(t.Time())
|
timeDiff := time.Since(t.Time())
|
||||||
if timeDiff > maxDeadline {
|
if timeDiff > maxDeadline {
|
||||||
logger.Info("request exceeded max deadline", "deadline", maxDeadline)
|
glog.Infof("failed to receive any request for more than %v ", maxDeadline)
|
||||||
logger.Info("Admission Control failing: Webhook is not receiving requests forwarded by api-server as per webhook configurations")
|
glog.Info("Admission Control failing: Webhook is not receiving requests forwarded by api-server as per webhook configurations")
|
||||||
// set the status unavailable
|
// set the status unavailable
|
||||||
if err := statuscontrol.FailedStatus(); err != nil {
|
if err := statuscontrol.FailedStatus(); err != nil {
|
||||||
logger.Error(err, "failed to set 'failed' status")
|
glog.Error(err)
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if timeDiff > deadline {
|
if timeDiff > deadline {
|
||||||
logger.Info("Admission Control failing: Webhook is not receiving requests forwarded by api-server as per webhook configurations")
|
glog.Info("Admission Control failing: Webhook is not receiving requests forwarded by api-server as per webhook configurations")
|
||||||
// send request to update the kyverno deployment
|
// send request to update the kyverno deployment
|
||||||
if err := statuscontrol.IncrementAnnotation(); err != nil {
|
if err := statuscontrol.IncrementAnnotation(); err != nil {
|
||||||
logger.Error(err, "failed to increment annotation")
|
glog.Error(err)
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// if the status was false before then we update it to true
|
// if the status was false before then we update it to true
|
||||||
// send request to update the kyverno deployment
|
// send request to update the kyverno deployment
|
||||||
if err := statuscontrol.SuccessStatus(); err != nil {
|
if err := statuscontrol.SuccessStatus(); err != nil {
|
||||||
logger.Error(err, "failed to update success status")
|
glog.Error(err)
|
||||||
}
|
}
|
||||||
case <-stopCh:
|
case <-stopCh:
|
||||||
// handler termination signal
|
// handler termination signal
|
||||||
logger.V(2).Info("stopping default resync for webhook checker")
|
glog.V(2).Infof("stopping default resync for webhook checker")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
"github.com/golang/glog"
|
||||||
dclient "github.com/nirmata/kyverno/pkg/dclient"
|
dclient "github.com/nirmata/kyverno/pkg/dclient"
|
||||||
"github.com/nirmata/kyverno/pkg/event"
|
"github.com/nirmata/kyverno/pkg/event"
|
||||||
)
|
)
|
||||||
|
@ -29,7 +29,6 @@ type StatusInterface interface {
|
||||||
type StatusControl struct {
|
type StatusControl struct {
|
||||||
client *dclient.Client
|
client *dclient.Client
|
||||||
eventGen event.Interface
|
eventGen event.Interface
|
||||||
log logr.Logger
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//SuccessStatus ...
|
//SuccessStatus ...
|
||||||
|
@ -43,22 +42,20 @@ func (vc StatusControl) FailedStatus() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewVerifyControl ...
|
// NewVerifyControl ...
|
||||||
func NewVerifyControl(client *dclient.Client, eventGen event.Interface, log logr.Logger) *StatusControl {
|
func NewVerifyControl(client *dclient.Client, eventGen event.Interface) *StatusControl {
|
||||||
return &StatusControl{
|
return &StatusControl{
|
||||||
client: client,
|
client: client,
|
||||||
eventGen: eventGen,
|
eventGen: eventGen,
|
||||||
log: log,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vc StatusControl) setStatus(status string) error {
|
func (vc StatusControl) setStatus(status string) error {
|
||||||
logger := vc.log
|
glog.Infof("setting deployment %s in ns %s annotation %s to %s", deployName, deployNamespace, annWebhookStats, status)
|
||||||
logger.Info(fmt.Sprintf("setting deployment %s in ns %s annotation %s to %s", deployName, deployNamespace, annWebhookStats, status))
|
|
||||||
var ann map[string]string
|
var ann map[string]string
|
||||||
var err error
|
var err error
|
||||||
deploy, err := vc.client.GetResource("Deployment", deployNamespace, deployName)
|
deploy, err := vc.client.GetResource("Deployment", deployNamespace, deployName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "failed to get deployment resource")
|
glog.V(4).Infof("failed to get deployment %s in namespace %s: %v", deployName, deployNamespace, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
ann = deploy.GetAnnotations()
|
ann = deploy.GetAnnotations()
|
||||||
|
@ -70,7 +67,7 @@ func (vc StatusControl) setStatus(status string) error {
|
||||||
if ok {
|
if ok {
|
||||||
// annotatiaion is present
|
// annotatiaion is present
|
||||||
if webhookAction == status {
|
if webhookAction == status {
|
||||||
logger.V(4).Info(fmt.Sprintf("annotation %s already set to '%s'", annWebhookStats, status))
|
glog.V(4).Infof("annotation %s already set to '%s'", annWebhookStats, status)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,7 +77,7 @@ func (vc StatusControl) setStatus(status string) error {
|
||||||
// update counter
|
// update counter
|
||||||
_, err = vc.client.UpdateResource("Deployment", deployNamespace, deploy, false)
|
_, err = vc.client.UpdateResource("Deployment", deployNamespace, deploy, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, fmt.Sprintf("failed to update annotation %s for deployment %s in namespace %s", annWebhookStats, deployName, deployNamespace))
|
glog.V(4).Infof("failed to update annotation %s for deployment %s in namespace %s: %v", annWebhookStats, deployName, deployNamespace, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// create event on kyverno deployment
|
// create event on kyverno deployment
|
||||||
|
@ -100,13 +97,12 @@ func createStatusUpdateEvent(status string, eventGen event.Interface) {
|
||||||
|
|
||||||
//IncrementAnnotation ...
|
//IncrementAnnotation ...
|
||||||
func (vc StatusControl) IncrementAnnotation() error {
|
func (vc StatusControl) IncrementAnnotation() error {
|
||||||
logger := vc.log
|
glog.Infof("setting deployment %s in ns %s annotation %s", deployName, deployNamespace, annCounter)
|
||||||
logger.Info(fmt.Sprintf("setting deployment %s in ns %s annotation %s", deployName, deployNamespace, annCounter))
|
|
||||||
var ann map[string]string
|
var ann map[string]string
|
||||||
var err error
|
var err error
|
||||||
deploy, err := vc.client.GetResource("Deployment", deployNamespace, deployName)
|
deploy, err := vc.client.GetResource("Deployment", deployNamespace, deployName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "failed to get deployment %s in namespace %s", deployName, deployNamespace)
|
glog.V(4).Infof("failed to get deployment %s in namespace %s: %v", deployName, deployNamespace, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
ann = deploy.GetAnnotations()
|
ann = deploy.GetAnnotations()
|
||||||
|
@ -116,18 +112,18 @@ func (vc StatusControl) IncrementAnnotation() error {
|
||||||
}
|
}
|
||||||
counter, err := strconv.Atoi(ann[annCounter])
|
counter, err := strconv.Atoi(ann[annCounter])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "Failed to parse string")
|
glog.V(4).Infof("failed to parse string: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// increment counter
|
// increment counter
|
||||||
counter++
|
counter++
|
||||||
ann[annCounter] = strconv.Itoa(counter)
|
ann[annCounter] = strconv.Itoa(counter)
|
||||||
logger.Info("incrementing annotation", "old", annCounter, "new", counter)
|
glog.Infof("incrementing annotation %s counter to %d", annCounter, counter)
|
||||||
deploy.SetAnnotations(ann)
|
deploy.SetAnnotations(ann)
|
||||||
// update counter
|
// update counter
|
||||||
_, err = vc.client.UpdateResource("Deployment", deployNamespace, deploy, false)
|
_, err = vc.client.UpdateResource("Deployment", deployNamespace, deploy, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, fmt.Sprintf("failed to update annotation %s for deployment %s in namespace %s", annCounter, deployName, deployNamespace))
|
glog.V(4).Infof("failed to update annotation %s for deployment %s in namespace %s: %v", annCounter, deployName, deployNamespace, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -19,8 +19,6 @@ limitations under the License.
|
||||||
package versioned
|
package versioned
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
kyvernov1 "github.com/nirmata/kyverno/pkg/client/clientset/versioned/typed/kyverno/v1"
|
kyvernov1 "github.com/nirmata/kyverno/pkg/client/clientset/versioned/typed/kyverno/v1"
|
||||||
discovery "k8s.io/client-go/discovery"
|
discovery "k8s.io/client-go/discovery"
|
||||||
rest "k8s.io/client-go/rest"
|
rest "k8s.io/client-go/rest"
|
||||||
|
@ -53,14 +51,9 @@ func (c *Clientset) Discovery() discovery.DiscoveryInterface {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewForConfig creates a new Clientset for the given config.
|
// NewForConfig creates a new Clientset for the given config.
|
||||||
// If config's RateLimiter is not set and QPS and Burst are acceptable,
|
|
||||||
// NewForConfig will generate a rate-limiter in configShallowCopy.
|
|
||||||
func NewForConfig(c *rest.Config) (*Clientset, error) {
|
func NewForConfig(c *rest.Config) (*Clientset, error) {
|
||||||
configShallowCopy := *c
|
configShallowCopy := *c
|
||||||
if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 {
|
if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 {
|
||||||
if configShallowCopy.Burst <= 0 {
|
|
||||||
return nil, fmt.Errorf("Burst is required to be greater than 0 when RateLimiter is not set and QPS is set to greater than 0")
|
|
||||||
}
|
|
||||||
configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst)
|
configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst)
|
||||||
}
|
}
|
||||||
var cs Clientset
|
var cs Clientset
|
||||||
|
|
|
@ -41,7 +41,7 @@ func NewSimpleClientset(objects ...runtime.Object) *Clientset {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cs := &Clientset{tracker: o}
|
cs := &Clientset{}
|
||||||
cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake}
|
cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake}
|
||||||
cs.AddReactor("*", "*", testing.ObjectReaction(o))
|
cs.AddReactor("*", "*", testing.ObjectReaction(o))
|
||||||
cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) {
|
cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) {
|
||||||
|
@ -63,17 +63,12 @@ func NewSimpleClientset(objects ...runtime.Object) *Clientset {
|
||||||
type Clientset struct {
|
type Clientset struct {
|
||||||
testing.Fake
|
testing.Fake
|
||||||
discovery *fakediscovery.FakeDiscovery
|
discovery *fakediscovery.FakeDiscovery
|
||||||
tracker testing.ObjectTracker
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Clientset) Discovery() discovery.DiscoveryInterface {
|
func (c *Clientset) Discovery() discovery.DiscoveryInterface {
|
||||||
return c.discovery
|
return c.discovery
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Clientset) Tracker() testing.ObjectTracker {
|
|
||||||
return c.tracker
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ clientset.Interface = &Clientset{}
|
var _ clientset.Interface = &Clientset{}
|
||||||
|
|
||||||
// KyvernoV1 retrieves the KyvernoV1Client
|
// KyvernoV1 retrieves the KyvernoV1Client
|
||||||
|
|
|
@ -29,8 +29,7 @@ import (
|
||||||
|
|
||||||
var scheme = runtime.NewScheme()
|
var scheme = runtime.NewScheme()
|
||||||
var codecs = serializer.NewCodecFactory(scheme)
|
var codecs = serializer.NewCodecFactory(scheme)
|
||||||
|
var parameterCodec = runtime.NewParameterCodec(scheme)
|
||||||
// var parameterCodec = runtime.NewParameterCodec(scheme)
|
|
||||||
var localSchemeBuilder = runtime.SchemeBuilder{
|
var localSchemeBuilder = runtime.SchemeBuilder{
|
||||||
kyvernov1.AddToScheme,
|
kyvernov1.AddToScheme,
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ package v1
|
||||||
import (
|
import (
|
||||||
v1 "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
v1 "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||||
"github.com/nirmata/kyverno/pkg/client/clientset/versioned/scheme"
|
"github.com/nirmata/kyverno/pkg/client/clientset/versioned/scheme"
|
||||||
|
serializer "k8s.io/apimachinery/pkg/runtime/serializer"
|
||||||
rest "k8s.io/client-go/rest"
|
rest "k8s.io/client-go/rest"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -85,7 +86,7 @@ func setConfigDefaults(config *rest.Config) error {
|
||||||
gv := v1.SchemeGroupVersion
|
gv := v1.SchemeGroupVersion
|
||||||
config.GroupVersion = &gv
|
config.GroupVersion = &gv
|
||||||
config.APIPath = "/apis"
|
config.APIPath = "/apis"
|
||||||
config.NegotiatedSerializer = scheme.Codecs.WithoutConversion()
|
config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: scheme.Codecs}
|
||||||
|
|
||||||
if config.UserAgent == "" {
|
if config.UserAgent == "" {
|
||||||
config.UserAgent = rest.DefaultKubernetesUserAgent()
|
config.UserAgent = rest.DefaultKubernetesUserAgent()
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/go-logr/logr"
|
"flag"
|
||||||
|
|
||||||
|
"github.com/golang/glog"
|
||||||
rest "k8s.io/client-go/rest"
|
rest "k8s.io/client-go/rest"
|
||||||
clientcmd "k8s.io/client-go/tools/clientcmd"
|
clientcmd "k8s.io/client-go/tools/clientcmd"
|
||||||
)
|
)
|
||||||
|
@ -72,13 +74,29 @@ var (
|
||||||
VerifyMutatingWebhookServicePath = "/verifymutate"
|
VerifyMutatingWebhookServicePath = "/verifymutate"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//LogDefaultFlags sets default glog flags
|
||||||
|
func LogDefaultFlags() {
|
||||||
|
var err error
|
||||||
|
err = flag.Set("logtostderr", "true")
|
||||||
|
if err != nil {
|
||||||
|
glog.Fatalf("failed to set flag 'logtostderr' to 'true':%v", err)
|
||||||
|
}
|
||||||
|
err = flag.Set("stderrthreshold", "WARNING")
|
||||||
|
if err != nil {
|
||||||
|
glog.Fatalf("failed to set flag 'stderrthreshold' to 'WARNING':%v", err)
|
||||||
|
}
|
||||||
|
flag.Set("v", "2")
|
||||||
|
if err != nil {
|
||||||
|
glog.Fatalf("failed to set flag 'v' to '2':%v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//CreateClientConfig creates client config
|
//CreateClientConfig creates client config
|
||||||
func CreateClientConfig(kubeconfig string, log logr.Logger) (*rest.Config, error) {
|
func CreateClientConfig(kubeconfig string) (*rest.Config, error) {
|
||||||
logger := log.WithName("CreateClientConfig")
|
|
||||||
if kubeconfig == "" {
|
if kubeconfig == "" {
|
||||||
logger.Info("Using in-cluster configuration")
|
glog.Info("Using in-cluster configuration")
|
||||||
return rest.InClusterConfig()
|
return rest.InClusterConfig()
|
||||||
}
|
}
|
||||||
logger.V(4).Info("Using specified kubeconfig", "kubeconfig", kubeconfig)
|
glog.V(4).Infof("Using configuration from '%s'", kubeconfig)
|
||||||
return clientcmd.BuildConfigFromFlags("", kubeconfig)
|
return clientcmd.BuildConfigFromFlags("", kubeconfig)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
"github.com/golang/glog"
|
||||||
"github.com/minio/minio/pkg/wildcard"
|
"github.com/minio/minio/pkg/wildcard"
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
informers "k8s.io/client-go/informers/core/v1"
|
informers "k8s.io/client-go/informers/core/v1"
|
||||||
|
@ -30,7 +31,6 @@ type ConfigData struct {
|
||||||
filters []k8Resource
|
filters []k8Resource
|
||||||
// hasynced
|
// hasynced
|
||||||
cmSycned cache.InformerSynced
|
cmSycned cache.InformerSynced
|
||||||
log logr.Logger
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToFilter checks if the given resource is set to be filtered in the configuration
|
// ToFilter checks if the given resource is set to be filtered in the configuration
|
||||||
|
@ -51,21 +51,20 @@ type Interface interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewConfigData ...
|
// NewConfigData ...
|
||||||
func NewConfigData(rclient kubernetes.Interface, cmInformer informers.ConfigMapInformer, filterK8Resources string, log logr.Logger) *ConfigData {
|
func NewConfigData(rclient kubernetes.Interface, cmInformer informers.ConfigMapInformer, filterK8Resources string) *ConfigData {
|
||||||
// environment var is read at start only
|
// environment var is read at start only
|
||||||
if cmNameEnv == "" {
|
if cmNameEnv == "" {
|
||||||
log.Info("ConfigMap name not defined in env:INIT_CONFIG: loading no default configuration")
|
glog.Info("ConfigMap name not defined in env:INIT_CONFIG: loading no default configuration")
|
||||||
}
|
}
|
||||||
cd := ConfigData{
|
cd := ConfigData{
|
||||||
client: rclient,
|
client: rclient,
|
||||||
cmName: os.Getenv(cmNameEnv),
|
cmName: os.Getenv(cmNameEnv),
|
||||||
cmSycned: cmInformer.Informer().HasSynced,
|
cmSycned: cmInformer.Informer().HasSynced,
|
||||||
log: log,
|
|
||||||
}
|
}
|
||||||
//TODO: this has been added to backward support command line arguments
|
//TODO: this has been added to backward support command line arguments
|
||||||
// will be removed in future and the configuration will be set only via configmaps
|
// will be removed in future and the configuration will be set only via configmaps
|
||||||
if filterK8Resources != "" {
|
if filterK8Resources != "" {
|
||||||
cd.log.Info("init configuration from commandline arguments")
|
glog.Info("Init configuration from commandline arguments")
|
||||||
cd.initFilters(filterK8Resources)
|
cd.initFilters(filterK8Resources)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,10 +78,9 @@ func NewConfigData(rclient kubernetes.Interface, cmInformer informers.ConfigMapI
|
||||||
|
|
||||||
//Run checks syncing
|
//Run checks syncing
|
||||||
func (cd *ConfigData) Run(stopCh <-chan struct{}) {
|
func (cd *ConfigData) Run(stopCh <-chan struct{}) {
|
||||||
logger := cd.log
|
|
||||||
// wait for cache to populate first time
|
// wait for cache to populate first time
|
||||||
if !cache.WaitForCacheSync(stopCh, cd.cmSycned) {
|
if !cache.WaitForCacheSync(stopCh, cd.cmSycned) {
|
||||||
logger.Info("configuration: failed to sync informer cache")
|
glog.Error("configuration: failed to sync informer cache")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,17 +103,16 @@ func (cd *ConfigData) updateCM(old, cur interface{}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cd *ConfigData) deleteCM(obj interface{}) {
|
func (cd *ConfigData) deleteCM(obj interface{}) {
|
||||||
logger := cd.log
|
|
||||||
cm, ok := obj.(*v1.ConfigMap)
|
cm, ok := obj.(*v1.ConfigMap)
|
||||||
if !ok {
|
if !ok {
|
||||||
tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
|
tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
|
||||||
if !ok {
|
if !ok {
|
||||||
logger.Info("failed to get object from tombstone")
|
glog.Info(fmt.Errorf("Couldn't get object from tombstone %#v", obj))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_, ok = tombstone.Obj.(*v1.ConfigMap)
|
_, ok = tombstone.Obj.(*v1.ConfigMap)
|
||||||
if !ok {
|
if !ok {
|
||||||
logger.Info("Tombstone contained object that is not a ConfigMap", "object", obj)
|
glog.Info(fmt.Errorf("Tombstone contained object that is not a ConfigMap %#v", obj))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -128,20 +125,19 @@ func (cd *ConfigData) deleteCM(obj interface{}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cd *ConfigData) load(cm v1.ConfigMap) {
|
func (cd *ConfigData) load(cm v1.ConfigMap) {
|
||||||
logger := cd.log.WithValues("name", cm.Name, "namespace", cm.Namespace)
|
|
||||||
if cm.Data == nil {
|
if cm.Data == nil {
|
||||||
logger.V(4).Info("configuration: No data defined in ConfigMap")
|
glog.V(4).Infof("Configuration: No data defined in ConfigMap %s", cm.Name)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// get resource filters
|
// get resource filters
|
||||||
filters, ok := cm.Data["resourceFilters"]
|
filters, ok := cm.Data["resourceFilters"]
|
||||||
if !ok {
|
if !ok {
|
||||||
logger.V(4).Info("configuration: No resourceFilters defined in ConfigMap")
|
glog.V(4).Infof("Configuration: No resourceFilters defined in ConfigMap %s", cm.Name)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// filters is a string
|
// filters is a string
|
||||||
if filters == "" {
|
if filters == "" {
|
||||||
logger.V(4).Info("configuration: resourceFilters is empty in ConfigMap")
|
glog.V(4).Infof("Configuration: resourceFilters is empty in ConfigMap %s", cm.Name)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// parse and load the configuration
|
// parse and load the configuration
|
||||||
|
@ -150,10 +146,11 @@ func (cd *ConfigData) load(cm v1.ConfigMap) {
|
||||||
|
|
||||||
newFilters := parseKinds(filters)
|
newFilters := parseKinds(filters)
|
||||||
if reflect.DeepEqual(newFilters, cd.filters) {
|
if reflect.DeepEqual(newFilters, cd.filters) {
|
||||||
logger.V(4).Info("resourceFilters did not change")
|
glog.V(4).Infof("Configuration: resourceFilters did not change in ConfigMap %s", cm.Name)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
logger.V(4).Info(" Updated resource filters", "oldFilters", cd.filters, "newFilters", newFilters)
|
glog.V(4).Infof("Configuration: Old resource filters %v", cd.filters)
|
||||||
|
glog.Infof("Configuration: New resource filters to %v", newFilters)
|
||||||
// update filters
|
// update filters
|
||||||
cd.filters = newFilters
|
cd.filters = newFilters
|
||||||
}
|
}
|
||||||
|
@ -161,20 +158,20 @@ func (cd *ConfigData) load(cm v1.ConfigMap) {
|
||||||
//TODO: this has been added to backward support command line arguments
|
//TODO: this has been added to backward support command line arguments
|
||||||
// will be removed in future and the configuration will be set only via configmaps
|
// will be removed in future and the configuration will be set only via configmaps
|
||||||
func (cd *ConfigData) initFilters(filters string) {
|
func (cd *ConfigData) initFilters(filters string) {
|
||||||
logger := cd.log
|
|
||||||
// parse and load the configuration
|
// parse and load the configuration
|
||||||
cd.mux.Lock()
|
cd.mux.Lock()
|
||||||
defer cd.mux.Unlock()
|
defer cd.mux.Unlock()
|
||||||
|
|
||||||
newFilters := parseKinds(filters)
|
newFilters := parseKinds(filters)
|
||||||
logger.Info("Init resource filters", "filters", newFilters)
|
glog.Infof("Configuration: Init resource filters to %v", newFilters)
|
||||||
// update filters
|
// update filters
|
||||||
cd.filters = newFilters
|
cd.filters = newFilters
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cd *ConfigData) unload(cm v1.ConfigMap) {
|
func (cd *ConfigData) unload(cm v1.ConfigMap) {
|
||||||
logger := cd.log
|
// TODO pick one msg
|
||||||
logger.Info("ConfigMap deleted, removing configuration filters", "name", cm.Name, "namespace", cm.Namespace)
|
glog.Infof("Configuration: ConfigMap %s deleted, removing configuration filters", cm.Name)
|
||||||
|
glog.Infof("Configuration: Removing all resource filters as ConfigMap %s deleted", cm.Name)
|
||||||
cd.mux.Lock()
|
cd.mux.Lock()
|
||||||
defer cd.mux.Unlock()
|
defer cd.mux.Unlock()
|
||||||
cd.filters = []k8Resource{}
|
cd.filters = []k8Resource{}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/golang/glog"
|
||||||
"github.com/nirmata/kyverno/pkg/config"
|
"github.com/nirmata/kyverno/pkg/config"
|
||||||
tls "github.com/nirmata/kyverno/pkg/tls"
|
tls "github.com/nirmata/kyverno/pkg/tls"
|
||||||
certificates "k8s.io/api/certificates/v1beta1"
|
certificates "k8s.io/api/certificates/v1beta1"
|
||||||
|
@ -18,14 +19,13 @@ import (
|
||||||
// Created pair is stored in cluster's secret.
|
// Created pair is stored in cluster's secret.
|
||||||
// Returns struct with key/certificate pair.
|
// Returns struct with key/certificate pair.
|
||||||
func (c *Client) InitTLSPemPair(configuration *rest.Config, fqdncn bool) (*tls.TlsPemPair, error) {
|
func (c *Client) InitTLSPemPair(configuration *rest.Config, fqdncn bool) (*tls.TlsPemPair, error) {
|
||||||
logger := c.log
|
|
||||||
certProps, err := c.GetTLSCertProps(configuration)
|
certProps, err := c.GetTLSCertProps(configuration)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
tlsPair := c.ReadTlsPair(certProps)
|
tlsPair := c.ReadTlsPair(certProps)
|
||||||
if tls.IsTLSPairShouldBeUpdated(tlsPair) {
|
if tls.IsTLSPairShouldBeUpdated(tlsPair) {
|
||||||
logger.Info("Generating new key/certificate pair for TLS")
|
glog.Info("Generating new key/certificate pair for TLS")
|
||||||
tlsPair, err = c.generateTLSPemPair(certProps, fqdncn)
|
tlsPair, err = c.generateTLSPemPair(certProps, fqdncn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -35,7 +35,8 @@ func (c *Client) InitTLSPemPair(configuration *rest.Config, fqdncn bool) (*tls.T
|
||||||
}
|
}
|
||||||
return tlsPair, nil
|
return tlsPair, nil
|
||||||
}
|
}
|
||||||
logger.Info("Using existing TLS key/certificate pair")
|
|
||||||
|
glog.Infoln("Using existing TLS key/certificate pair")
|
||||||
return tlsPair, nil
|
return tlsPair, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +71,6 @@ func (c *Client) generateTLSPemPair(props tls.TlsCertificateProps, fqdncn bool)
|
||||||
|
|
||||||
// Submits and approves certificate request, returns request which need to be fetched
|
// Submits and approves certificate request, returns request which need to be fetched
|
||||||
func (c *Client) submitAndApproveCertificateRequest(req *certificates.CertificateSigningRequest) (*certificates.CertificateSigningRequest, error) {
|
func (c *Client) submitAndApproveCertificateRequest(req *certificates.CertificateSigningRequest) (*certificates.CertificateSigningRequest, error) {
|
||||||
logger := c.log.WithName("submitAndApproveCertificateRequest")
|
|
||||||
certClient, err := c.GetCSRInterface()
|
certClient, err := c.GetCSRInterface()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -86,7 +86,7 @@ func (c *Client) submitAndApproveCertificateRequest(req *certificates.Certificat
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Unable to delete existing certificate request: %v", err)
|
return nil, fmt.Errorf("Unable to delete existing certificate request: %v", err)
|
||||||
}
|
}
|
||||||
logger.Info("Old certificate request is deleted")
|
glog.Info("Old certificate request is deleted")
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -95,7 +95,7 @@ func (c *Client) submitAndApproveCertificateRequest(req *certificates.Certificat
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
logger.Info("Certificate request created", "name", unstrRes.GetName())
|
glog.Infof("Certificate request %s is created", unstrRes.GetName())
|
||||||
|
|
||||||
res, err := convertToCSR(unstrRes)
|
res, err := convertToCSR(unstrRes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -110,7 +110,7 @@ func (c *Client) submitAndApproveCertificateRequest(req *certificates.Certificat
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Unable to approve certificate request: %v", err)
|
return nil, fmt.Errorf("Unable to approve certificate request: %v", err)
|
||||||
}
|
}
|
||||||
logger.Info("Certificate request is approved", "name", res.ObjectMeta.Name)
|
glog.Infof("Certificate request %s is approved", res.ObjectMeta.Name)
|
||||||
|
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
@ -144,10 +144,9 @@ func (c *Client) fetchCertificateFromRequest(req *certificates.CertificateSignin
|
||||||
|
|
||||||
//ReadRootCASecret returns the RootCA from the pre-defined secret
|
//ReadRootCASecret returns the RootCA from the pre-defined secret
|
||||||
func (c *Client) ReadRootCASecret() (result []byte) {
|
func (c *Client) ReadRootCASecret() (result []byte) {
|
||||||
logger := c.log.WithName("ReadRootCASecret")
|
|
||||||
certProps, err := c.GetTLSCertProps(c.clientConfig)
|
certProps, err := c.GetTLSCertProps(c.clientConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "failed to get TLS Cert Properties")
|
glog.Error(err)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
sname := generateRootCASecretName(certProps)
|
sname := generateRootCASecretName(certProps)
|
||||||
|
@ -157,16 +156,16 @@ func (c *Client) ReadRootCASecret() (result []byte) {
|
||||||
}
|
}
|
||||||
tlsca, err := convertToSecret(stlsca)
|
tlsca, err := convertToSecret(stlsca)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "failed to convert secret", "name", sname, "namespace", certProps.Namespace)
|
glog.Error(err)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
result = tlsca.Data[rootCAKey]
|
result = tlsca.Data[rootCAKey]
|
||||||
if len(result) == 0 {
|
if len(result) == 0 {
|
||||||
logger.Info("root CA certificate not found in secret", "name", tlsca.Name, "namespace", certProps.Namespace)
|
glog.Warningf("root CA certificate not found in secret %s/%s", certProps.Namespace, tlsca.Name)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
logger.V(4).Info("using CA bundle defined in secret to validate the webhook's server certificate", "name", tlsca.Name, "namespace", certProps.Namespace)
|
glog.V(4).Infof("using CA bundle defined in secret %s/%s to validate the webhook's server certificate", certProps.Namespace, tlsca.Name)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,11 +174,10 @@ const rootCAKey string = "rootCA.crt"
|
||||||
|
|
||||||
//ReadTlsPair Reads the pair of TLS certificate and key from the specified secret.
|
//ReadTlsPair Reads the pair of TLS certificate and key from the specified secret.
|
||||||
func (c *Client) ReadTlsPair(props tls.TlsCertificateProps) *tls.TlsPemPair {
|
func (c *Client) ReadTlsPair(props tls.TlsCertificateProps) *tls.TlsPemPair {
|
||||||
logger := c.log.WithName("ReadTlsPair")
|
|
||||||
sname := generateTLSPairSecretName(props)
|
sname := generateTLSPairSecretName(props)
|
||||||
unstrSecret, err := c.GetResource(Secrets, props.Namespace, sname)
|
unstrSecret, err := c.GetResource(Secrets, props.Namespace, sname)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "Failed to get secret", "name", sname, "namespace", props.Namespace)
|
glog.Warningf("Unable to get secret %s/%s: %s", props.Namespace, sname, err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,7 +188,7 @@ func (c *Client) ReadTlsPair(props tls.TlsCertificateProps) *tls.TlsPemPair {
|
||||||
sname := generateRootCASecretName(props)
|
sname := generateRootCASecretName(props)
|
||||||
_, err := c.GetResource(Secrets, props.Namespace, sname)
|
_, err := c.GetResource(Secrets, props.Namespace, sname)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "Root CA secret is required while using self-signed certificates TLS pair, defaulting to generating new TLS pair", "name", sname, "namespace", props.Namespace)
|
glog.Errorf("Root CA secret %s/%s is required while using self-signed certificates TLS pair, defaulting to generating new TLS pair", props.Namespace, sname)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -203,11 +201,11 @@ func (c *Client) ReadTlsPair(props tls.TlsCertificateProps) *tls.TlsPemPair {
|
||||||
PrivateKey: secret.Data[v1.TLSPrivateKeyKey],
|
PrivateKey: secret.Data[v1.TLSPrivateKeyKey],
|
||||||
}
|
}
|
||||||
if len(pemPair.Certificate) == 0 {
|
if len(pemPair.Certificate) == 0 {
|
||||||
logger.Info("TLS Certificate not found in secret", "name", sname, "namespace", props.Namespace)
|
glog.Warningf("TLS Certificate not found in secret %s/%s", props.Namespace, sname)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if len(pemPair.PrivateKey) == 0 {
|
if len(pemPair.PrivateKey) == 0 {
|
||||||
logger.Info("TLS PrivateKey not found in secret", "name", sname, "namespace", props.Namespace)
|
glog.Warningf("TLS PrivateKey not found in secret %s/%s", props.Namespace, sname)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return &pemPair
|
return &pemPair
|
||||||
|
@ -216,7 +214,6 @@ func (c *Client) ReadTlsPair(props tls.TlsCertificateProps) *tls.TlsPemPair {
|
||||||
//WriteTlsPair Writes the pair of TLS certificate and key to the specified secret.
|
//WriteTlsPair Writes the pair of TLS certificate and key to the specified secret.
|
||||||
// Updates existing secret or creates new one.
|
// Updates existing secret or creates new one.
|
||||||
func (c *Client) WriteTlsPair(props tls.TlsCertificateProps, pemPair *tls.TlsPemPair) error {
|
func (c *Client) WriteTlsPair(props tls.TlsCertificateProps, pemPair *tls.TlsPemPair) error {
|
||||||
logger := c.log.WithName("WriteTlsPair")
|
|
||||||
name := generateTLSPairSecretName(props)
|
name := generateTLSPairSecretName(props)
|
||||||
_, err := c.GetResource(Secrets, props.Namespace, name)
|
_, err := c.GetResource(Secrets, props.Namespace, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -238,7 +235,7 @@ func (c *Client) WriteTlsPair(props tls.TlsCertificateProps, pemPair *tls.TlsPem
|
||||||
|
|
||||||
_, err := c.CreateResource(Secrets, props.Namespace, secret, false)
|
_, err := c.CreateResource(Secrets, props.Namespace, secret, false)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
logger.Info("secret created", "name", name, "namespace", props.Namespace)
|
glog.Infof("Secret %s is created", name)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -254,7 +251,7 @@ func (c *Client) WriteTlsPair(props tls.TlsCertificateProps, pemPair *tls.TlsPem
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
logger.Info("secret updated", "name", name, "namespace", props.Namespace)
|
glog.Infof("Secret %s is updated", name)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,9 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
|
||||||
openapi_v2 "github.com/googleapis/gnostic/OpenAPIv2"
|
openapi_v2 "github.com/googleapis/gnostic/OpenAPIv2"
|
||||||
|
|
||||||
|
"github.com/golang/glog"
|
||||||
"github.com/nirmata/kyverno/pkg/config"
|
"github.com/nirmata/kyverno/pkg/config"
|
||||||
apps "k8s.io/api/apps/v1"
|
apps "k8s.io/api/apps/v1"
|
||||||
certificates "k8s.io/api/certificates/v1beta1"
|
certificates "k8s.io/api/certificates/v1beta1"
|
||||||
|
@ -31,15 +32,13 @@ import (
|
||||||
//Client enables interaction with k8 resource
|
//Client enables interaction with k8 resource
|
||||||
type Client struct {
|
type Client struct {
|
||||||
client dynamic.Interface
|
client dynamic.Interface
|
||||||
log logr.Logger
|
|
||||||
clientConfig *rest.Config
|
clientConfig *rest.Config
|
||||||
kclient kubernetes.Interface
|
kclient kubernetes.Interface
|
||||||
DiscoveryClient IDiscovery
|
DiscoveryClient IDiscovery
|
||||||
}
|
}
|
||||||
|
|
||||||
//NewClient creates new instance of client
|
//NewClient creates new instance of client
|
||||||
func NewClient(config *rest.Config, resync time.Duration, stopCh <-chan struct{}, log logr.Logger) (*Client, error) {
|
func NewClient(config *rest.Config, resync time.Duration, stopCh <-chan struct{}) (*Client, error) {
|
||||||
|
|
||||||
dclient, err := dynamic.NewForConfig(config)
|
dclient, err := dynamic.NewForConfig(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -52,10 +51,9 @@ func NewClient(config *rest.Config, resync time.Duration, stopCh <-chan struct{}
|
||||||
client: dclient,
|
client: dclient,
|
||||||
clientConfig: config,
|
clientConfig: config,
|
||||||
kclient: kclient,
|
kclient: kclient,
|
||||||
log: log.WithName("Client"),
|
|
||||||
}
|
}
|
||||||
// Set discovery client
|
// Set discovery client
|
||||||
discoveryClient := ServerPreferredResources{cachedClient: memory.NewMemCacheClient(kclient.Discovery()), log: client.log}
|
discoveryClient := ServerPreferredResources{memory.NewMemCacheClient(kclient.Discovery())}
|
||||||
// client will invalidate registered resources cache every x seconds,
|
// client will invalidate registered resources cache every x seconds,
|
||||||
// As there is no way to identify if the registered resource is available or not
|
// As there is no way to identify if the registered resource is available or not
|
||||||
// we will be invalidating the local cache, so the next request get a fresh cache
|
// we will be invalidating the local cache, so the next request get a fresh cache
|
||||||
|
@ -191,6 +189,7 @@ func (c *Client) UpdateStatusResource(kind string, namespace string, obj interfa
|
||||||
func convertToUnstructured(obj interface{}) *unstructured.Unstructured {
|
func convertToUnstructured(obj interface{}) *unstructured.Unstructured {
|
||||||
unstructuredObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&obj)
|
unstructuredObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
glog.Errorf("Unable to convert : %v", err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return &unstructured.Unstructured{Object: unstructuredObj}
|
return &unstructured.Unstructured{Object: unstructuredObj}
|
||||||
|
@ -229,24 +228,22 @@ func (c *Client) SetDiscovery(discoveryClient IDiscovery) {
|
||||||
//ServerPreferredResources stores the cachedClient instance for discovery client
|
//ServerPreferredResources stores the cachedClient instance for discovery client
|
||||||
type ServerPreferredResources struct {
|
type ServerPreferredResources struct {
|
||||||
cachedClient discovery.CachedDiscoveryInterface
|
cachedClient discovery.CachedDiscoveryInterface
|
||||||
log logr.Logger
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Poll will keep invalidate the local cache
|
//Poll will keep invalidate the local cache
|
||||||
func (c ServerPreferredResources) Poll(resync time.Duration, stopCh <-chan struct{}) {
|
func (c ServerPreferredResources) Poll(resync time.Duration, stopCh <-chan struct{}) {
|
||||||
logger := c.log.WithName("Poll")
|
|
||||||
// start a ticker
|
// start a ticker
|
||||||
ticker := time.NewTicker(resync)
|
ticker := time.NewTicker(resync)
|
||||||
defer func() { ticker.Stop() }()
|
defer func() { ticker.Stop() }()
|
||||||
logger.Info("starting registered resources sync", "period", resync)
|
glog.Infof("Starting registered resources sync: every %d seconds", resync)
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-stopCh:
|
case <-stopCh:
|
||||||
logger.Info("stopping registered resources sync")
|
glog.Info("Stopping registered resources sync")
|
||||||
return
|
return
|
||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
// set cache as stale
|
// set cache as stale
|
||||||
logger.V(6).Info("invalidating local client cache for registered resources")
|
glog.V(6).Info("invalidating local client cache for registered resources")
|
||||||
c.cachedClient.Invalidate()
|
c.cachedClient.Invalidate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -264,12 +261,12 @@ func (c ServerPreferredResources) OpenAPISchema() (*openapi_v2.Document, error)
|
||||||
func (c ServerPreferredResources) GetGVRFromKind(kind string) schema.GroupVersionResource {
|
func (c ServerPreferredResources) GetGVRFromKind(kind string) schema.GroupVersionResource {
|
||||||
var gvr schema.GroupVersionResource
|
var gvr schema.GroupVersionResource
|
||||||
var err error
|
var err error
|
||||||
gvr, err = loadServerResources(kind, c.cachedClient, c.log)
|
gvr, err = loadServerResources(kind, c.cachedClient)
|
||||||
if err != nil && !c.cachedClient.Fresh() {
|
if err != nil && !c.cachedClient.Fresh() {
|
||||||
|
|
||||||
// invalidate cahce & re-try once more
|
// invalidate cahce & re-try once more
|
||||||
c.cachedClient.Invalidate()
|
c.cachedClient.Invalidate()
|
||||||
gvr, err = loadServerResources(kind, c.cachedClient, c.log)
|
gvr, err = loadServerResources(kind, c.cachedClient)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return gvr
|
return gvr
|
||||||
}
|
}
|
||||||
|
@ -282,12 +279,11 @@ func (c ServerPreferredResources) GetServerVersion() (*version.Info, error) {
|
||||||
return c.cachedClient.ServerVersion()
|
return c.cachedClient.ServerVersion()
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadServerResources(k string, cdi discovery.CachedDiscoveryInterface, log logr.Logger) (schema.GroupVersionResource, error) {
|
func loadServerResources(k string, cdi discovery.CachedDiscoveryInterface) (schema.GroupVersionResource, error) {
|
||||||
logger := log.WithName("loadServerResources")
|
|
||||||
emptyGVR := schema.GroupVersionResource{}
|
|
||||||
serverresources, err := cdi.ServerPreferredResources()
|
serverresources, err := cdi.ServerPreferredResources()
|
||||||
|
emptyGVR := schema.GroupVersionResource{}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "failed to get registered preferred resources")
|
glog.Error(err)
|
||||||
return emptyGVR, err
|
return emptyGVR, err
|
||||||
}
|
}
|
||||||
for _, serverresource := range serverresources {
|
for _, serverresource := range serverresources {
|
||||||
|
@ -297,7 +293,7 @@ func loadServerResources(k string, cdi discovery.CachedDiscoveryInterface, log l
|
||||||
if resource.Kind == k && !strings.Contains(resource.Name, "/") {
|
if resource.Kind == k && !strings.Contains(resource.Name, "/") {
|
||||||
gv, err := schema.ParseGroupVersion(serverresource.GroupVersion)
|
gv, err := schema.ParseGroupVersion(serverresource.GroupVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "failed to parse groupVersion from schema", "groupVersion", serverresource.GroupVersion)
|
glog.Error(err)
|
||||||
return emptyGVR, err
|
return emptyGVR, err
|
||||||
}
|
}
|
||||||
return gv.WithResource(resource.Name), nil
|
return gv.WithResource(resource.Name), nil
|
||||||
|
|
|
@ -4,8 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
"github.com/golang/glog"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
//ValidationHandler for element processes
|
//ValidationHandler for element processes
|
||||||
|
@ -13,7 +12,7 @@ type ValidationHandler interface {
|
||||||
Handle(handler resourceElementHandler, resourceMap map[string]interface{}, originPattern interface{}) (string, error)
|
Handle(handler resourceElementHandler, resourceMap map[string]interface{}, originPattern interface{}) (string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type resourceElementHandler = func(log logr.Logger, resourceElement, patternElement, originPattern interface{}, path string) (string, error)
|
type resourceElementHandler = func(resourceElement, patternElement, originPattern interface{}, path string) (string, error)
|
||||||
|
|
||||||
//CreateElementHandler factory to process elements
|
//CreateElementHandler factory to process elements
|
||||||
func CreateElementHandler(element string, pattern interface{}, path string) ValidationHandler {
|
func CreateElementHandler(element string, pattern interface{}, path string) ValidationHandler {
|
||||||
|
@ -83,7 +82,7 @@ func (eh EqualityHandler) Handle(handler resourceElementHandler, resourceMap map
|
||||||
// check if anchor is present in resource
|
// check if anchor is present in resource
|
||||||
if value, ok := resourceMap[anchorKey]; ok {
|
if value, ok := resourceMap[anchorKey]; ok {
|
||||||
// validate the values of the pattern
|
// validate the values of the pattern
|
||||||
returnPath, err := handler(log.Log, value, eh.pattern, originPattern, currentPath)
|
returnPath, err := handler(value, eh.pattern, originPattern, currentPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return returnPath, err
|
return returnPath, err
|
||||||
}
|
}
|
||||||
|
@ -116,7 +115,7 @@ func (dh DefaultHandler) Handle(handler resourceElementHandler, resourceMap map[
|
||||||
} else if dh.pattern == "*" && resourceMap[dh.element] == nil {
|
} else if dh.pattern == "*" && resourceMap[dh.element] == nil {
|
||||||
return dh.path, fmt.Errorf("Validation rule failed at %s, Field %s is not present", dh.path, dh.element)
|
return dh.path, fmt.Errorf("Validation rule failed at %s, Field %s is not present", dh.path, dh.element)
|
||||||
} else {
|
} else {
|
||||||
path, err := handler(log.Log, resourceMap[dh.element], dh.pattern, originPattern, currentPath)
|
path, err := handler(resourceMap[dh.element], dh.pattern, originPattern, currentPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return path, err
|
return path, err
|
||||||
}
|
}
|
||||||
|
@ -147,7 +146,7 @@ func (ch ConditionAnchorHandler) Handle(handler resourceElementHandler, resource
|
||||||
// check if anchor is present in resource
|
// check if anchor is present in resource
|
||||||
if value, ok := resourceMap[anchorKey]; ok {
|
if value, ok := resourceMap[anchorKey]; ok {
|
||||||
// validate the values of the pattern
|
// validate the values of the pattern
|
||||||
returnPath, err := handler(log.Log, value, ch.pattern, originPattern, currentPath)
|
returnPath, err := handler(value, ch.pattern, originPattern, currentPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return returnPath, err
|
return returnPath, err
|
||||||
}
|
}
|
||||||
|
@ -195,6 +194,7 @@ func (eh ExistenceHandler) Handle(handler resourceElementHandler, resourceMap ma
|
||||||
}
|
}
|
||||||
return validateExistenceListResource(handler, typedResource, typedPatternMap, originPattern, currentPath)
|
return validateExistenceListResource(handler, typedResource, typedPatternMap, originPattern, currentPath)
|
||||||
default:
|
default:
|
||||||
|
glog.Error("Invalid type: Existence ^ () anchor can be used only on list/array type resource")
|
||||||
return currentPath, fmt.Errorf("Invalid resource type %T: Existence ^ () anchor can be used only on list/array type resource", value)
|
return currentPath, fmt.Errorf("Invalid resource type %T: Existence ^ () anchor can be used only on list/array type resource", value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -206,9 +206,10 @@ func validateExistenceListResource(handler resourceElementHandler, resourceList
|
||||||
// if non satisfy then throw an error
|
// if non satisfy then throw an error
|
||||||
for i, resourceElement := range resourceList {
|
for i, resourceElement := range resourceList {
|
||||||
currentPath := path + strconv.Itoa(i) + "/"
|
currentPath := path + strconv.Itoa(i) + "/"
|
||||||
_, err := handler(log.Log, resourceElement, patternMap, originPattern, currentPath)
|
_, err := handler(resourceElement, patternMap, originPattern, currentPath)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
// condition is satisfied, dont check further
|
// condition is satisfied, dont check further
|
||||||
|
glog.V(4).Infof("Existence check satisfied at path %s, for pattern %v", currentPath, patternMap)
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,9 +6,8 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
jsonpatch "github.com/evanphx/json-patch"
|
jsonpatch "github.com/evanphx/json-patch"
|
||||||
"github.com/go-logr/logr"
|
"github.com/golang/glog"
|
||||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
//Interface to manage context operations
|
//Interface to manage context operations
|
||||||
|
@ -34,7 +33,6 @@ type Context struct {
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
jsonRaw []byte
|
jsonRaw []byte
|
||||||
whiteListVars []string
|
whiteListVars []string
|
||||||
log logr.Logger
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//NewContext returns a new context
|
//NewContext returns a new context
|
||||||
|
@ -44,7 +42,6 @@ func NewContext(whiteListVars ...string) *Context {
|
||||||
// data: map[string]interface{}{},
|
// data: map[string]interface{}{},
|
||||||
jsonRaw: []byte(`{}`), // empty json struct
|
jsonRaw: []byte(`{}`), // empty json struct
|
||||||
whiteListVars: whiteListVars,
|
whiteListVars: whiteListVars,
|
||||||
log: log.Log.WithName("context"),
|
|
||||||
}
|
}
|
||||||
return &ctx
|
return &ctx
|
||||||
}
|
}
|
||||||
|
@ -57,7 +54,7 @@ func (ctx *Context) AddJSON(dataRaw []byte) error {
|
||||||
// merge json
|
// merge json
|
||||||
ctx.jsonRaw, err = jsonpatch.MergePatch(ctx.jsonRaw, dataRaw)
|
ctx.jsonRaw, err = jsonpatch.MergePatch(ctx.jsonRaw, dataRaw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.log.Error(err, "failed to merge JSON data")
|
glog.V(4).Infof("failed to merge JSON data: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -69,7 +66,7 @@ func (ctx *Context) AddResource(dataRaw []byte) error {
|
||||||
// unmarshall the resource struct
|
// unmarshall the resource struct
|
||||||
var data interface{}
|
var data interface{}
|
||||||
if err := json.Unmarshal(dataRaw, &data); err != nil {
|
if err := json.Unmarshal(dataRaw, &data); err != nil {
|
||||||
ctx.log.Error(err, "failed to unmarshall the resource")
|
glog.V(4).Infof("failed to unmarshall the context data: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,7 +82,7 @@ func (ctx *Context) AddResource(dataRaw []byte) error {
|
||||||
|
|
||||||
objRaw, err := json.Marshal(modifiedResource)
|
objRaw, err := json.Marshal(modifiedResource)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.log.Error(err, "failed to marshal the resource")
|
glog.V(4).Infof("failed to marshall the updated context data")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return ctx.AddJSON(objRaw)
|
return ctx.AddJSON(objRaw)
|
||||||
|
@ -101,7 +98,7 @@ func (ctx *Context) AddUserInfo(userRequestInfo kyverno.RequestInfo) error {
|
||||||
|
|
||||||
objRaw, err := json.Marshal(modifiedResource)
|
objRaw, err := json.Marshal(modifiedResource)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.log.Error(err, "failed to marshal the UserInfo")
|
glog.V(4).Infof("failed to marshall the updated context data")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return ctx.AddJSON(objRaw)
|
return ctx.AddJSON(objRaw)
|
||||||
|
@ -121,6 +118,8 @@ func (ctx *Context) AddSA(userName string) error {
|
||||||
// filter namespace
|
// filter namespace
|
||||||
groups := strings.Split(sa, ":")
|
groups := strings.Split(sa, ":")
|
||||||
if len(groups) >= 2 {
|
if len(groups) >= 2 {
|
||||||
|
glog.V(4).Infof("serviceAccount namespace: %s", groups[0])
|
||||||
|
glog.V(4).Infof("serviceAccount name: %s", groups[1])
|
||||||
saName = groups[1]
|
saName = groups[1]
|
||||||
saNamespace = groups[0]
|
saNamespace = groups[0]
|
||||||
}
|
}
|
||||||
|
@ -132,7 +131,7 @@ func (ctx *Context) AddSA(userName string) error {
|
||||||
}
|
}
|
||||||
saNameRaw, err := json.Marshal(saNameObj)
|
saNameRaw, err := json.Marshal(saNameObj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.log.Error(err, "failed to marshal the SA")
|
glog.V(4).Infof("failed to marshall the updated context data")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := ctx.AddJSON(saNameRaw); err != nil {
|
if err := ctx.AddJSON(saNameRaw); err != nil {
|
||||||
|
@ -146,7 +145,7 @@ func (ctx *Context) AddSA(userName string) error {
|
||||||
}
|
}
|
||||||
saNsRaw, err := json.Marshal(saNsObj)
|
saNsRaw, err := json.Marshal(saNsObj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.log.Error(err, "failed to marshal the SA namespace")
|
glog.V(4).Infof("failed to marshall the updated context data")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := ctx.AddJSON(saNsRaw); err != nil {
|
if err := ctx.AddJSON(saNsRaw); err != nil {
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/golang/glog"
|
||||||
jmespath "github.com/jmespath/go-jmespath"
|
jmespath "github.com/jmespath/go-jmespath"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -18,7 +19,7 @@ func (ctx *Context) Query(query string) (interface{}, error) {
|
||||||
// compile the query
|
// compile the query
|
||||||
queryPath, err := jmespath.Compile(query)
|
queryPath, err := jmespath.Compile(query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.log.Error(err, "incorrect query", "query", query)
|
glog.V(4).Infof("incorrect query %s: %v", query, err)
|
||||||
return emptyResult, fmt.Errorf("incorrect query %s: %v", query, err)
|
return emptyResult, fmt.Errorf("incorrect query %s: %v", query, err)
|
||||||
}
|
}
|
||||||
// search
|
// search
|
||||||
|
@ -27,13 +28,13 @@ func (ctx *Context) Query(query string) (interface{}, error) {
|
||||||
|
|
||||||
var data interface{}
|
var data interface{}
|
||||||
if err := json.Unmarshal(ctx.jsonRaw, &data); err != nil {
|
if err := json.Unmarshal(ctx.jsonRaw, &data); err != nil {
|
||||||
ctx.log.Error(err, "failed to unmarshal context")
|
glog.V(4).Infof("failed to unmarshall context: %v", err)
|
||||||
return emptyResult, fmt.Errorf("failed to unmarshall context: %v", err)
|
return emptyResult, fmt.Errorf("failed to unmarshall context: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err := queryPath.Search(data)
|
result, err := queryPath.Search(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.log.Error(err, "failed to search query", "query", query)
|
glog.V(4).Infof("failed to search query %s: %v", query, err)
|
||||||
return emptyResult, fmt.Errorf("failed to search query %s: %v", query, err)
|
return emptyResult, fmt.Errorf("failed to search query %s: %v", query, err)
|
||||||
}
|
}
|
||||||
return result, nil
|
return result, nil
|
||||||
|
|
|
@ -12,7 +12,6 @@ import (
|
||||||
"github.com/nirmata/kyverno/pkg/engine/utils"
|
"github.com/nirmata/kyverno/pkg/engine/utils"
|
||||||
"github.com/nirmata/kyverno/pkg/engine/variables"
|
"github.com/nirmata/kyverno/pkg/engine/variables"
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func mutateResourceWithOverlay(resource unstructured.Unstructured, overlay interface{}) (unstructured.Unstructured, error) {
|
func mutateResourceWithOverlay(resource unstructured.Unstructured, overlay interface{}) (unstructured.Unstructured, error) {
|
||||||
|
@ -58,7 +57,7 @@ func ForceMutate(ctx context.EvalInterface, policy kyverno.ClusterPolicy, resour
|
||||||
if mutation.Overlay != nil {
|
if mutation.Overlay != nil {
|
||||||
overlay := mutation.Overlay
|
overlay := mutation.Overlay
|
||||||
if ctx != nil {
|
if ctx != nil {
|
||||||
if overlay, err = variables.SubstituteVars(log.Log, ctx, overlay); err != nil {
|
if overlay, err = variables.SubstituteVars(ctx, overlay); err != nil {
|
||||||
return unstructured.Unstructured{}, err
|
return unstructured.Unstructured{}, err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -73,7 +72,7 @@ func ForceMutate(ctx context.EvalInterface, policy kyverno.ClusterPolicy, resour
|
||||||
|
|
||||||
if rule.Mutation.Patches != nil {
|
if rule.Mutation.Patches != nil {
|
||||||
var resp response.RuleResponse
|
var resp response.RuleResponse
|
||||||
resp, resource = mutate.ProcessPatches(log.Log, rule, resource)
|
resp, resource = mutate.ProcessPatches(rule, resource)
|
||||||
if !resp.Success {
|
if !resp.Success {
|
||||||
return unstructured.Unstructured{}, fmt.Errorf(resp.Message)
|
return unstructured.Unstructured{}, fmt.Errorf(resp.Message)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,14 +3,12 @@ package engine
|
||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
"github.com/golang/glog"
|
||||||
|
|
||||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||||
"github.com/nirmata/kyverno/pkg/engine/context"
|
"github.com/nirmata/kyverno/pkg/engine/context"
|
||||||
"github.com/nirmata/kyverno/pkg/engine/response"
|
"github.com/nirmata/kyverno/pkg/engine/response"
|
||||||
"github.com/nirmata/kyverno/pkg/engine/variables"
|
"github.com/nirmata/kyverno/pkg/engine/variables"
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Generate checks for validity of generate rule on the resource
|
// Generate checks for validity of generate rule on the resource
|
||||||
|
@ -22,11 +20,10 @@ func Generate(policyContext PolicyContext) (resp response.EngineResponse) {
|
||||||
resource := policyContext.NewResource
|
resource := policyContext.NewResource
|
||||||
admissionInfo := policyContext.AdmissionInfo
|
admissionInfo := policyContext.AdmissionInfo
|
||||||
ctx := policyContext.Context
|
ctx := policyContext.Context
|
||||||
logger := log.Log.WithName("Generate").WithValues("policy", policy.Name, "kind", resource.GetKind(), "namespace", resource.GetNamespace(), "name", resource.GetName())
|
return filterRules(policy, resource, admissionInfo, ctx)
|
||||||
return filterRules(policy, resource, admissionInfo, ctx, logger)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func filterRule(rule kyverno.Rule, resource unstructured.Unstructured, admissionInfo kyverno.RequestInfo, ctx context.EvalInterface, log logr.Logger) *response.RuleResponse {
|
func filterRule(rule kyverno.Rule, resource unstructured.Unstructured, admissionInfo kyverno.RequestInfo, ctx context.EvalInterface) *response.RuleResponse {
|
||||||
if !rule.HasGenerate() {
|
if !rule.HasGenerate() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -34,14 +31,15 @@ func filterRule(rule kyverno.Rule, resource unstructured.Unstructured, admission
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
|
|
||||||
if err := MatchesResourceDescription(resource, rule, admissionInfo); err != nil {
|
if err := MatchesResourceDescription(resource, rule, admissionInfo); err != nil {
|
||||||
|
glog.V(4).Infof(err.Error())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// operate on the copy of the conditions, as we perform variable substitution
|
// operate on the copy of the conditions, as we perform variable substitution
|
||||||
copyConditions := copyConditions(rule.Conditions)
|
copyConditions := copyConditions(rule.Conditions)
|
||||||
|
|
||||||
// evaluate pre-conditions
|
// evaluate pre-conditions
|
||||||
if !variables.EvaluateConditions(log, ctx, copyConditions) {
|
if !variables.EvaluateConditions(ctx, copyConditions) {
|
||||||
log.V(4).Info("preconditions not satisfied, skipping rule", "rule", rule.Name)
|
glog.V(4).Infof("resource %s/%s does not satisfy the conditions for the rule ", resource.GetNamespace(), resource.GetName())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// build rule Response
|
// build rule Response
|
||||||
|
@ -55,7 +53,7 @@ func filterRule(rule kyverno.Rule, resource unstructured.Unstructured, admission
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func filterRules(policy kyverno.ClusterPolicy, resource unstructured.Unstructured, admissionInfo kyverno.RequestInfo, ctx context.EvalInterface, log logr.Logger) response.EngineResponse {
|
func filterRules(policy kyverno.ClusterPolicy, resource unstructured.Unstructured, admissionInfo kyverno.RequestInfo, ctx context.EvalInterface) response.EngineResponse {
|
||||||
resp := response.EngineResponse{
|
resp := response.EngineResponse{
|
||||||
PolicyResponse: response.PolicyResponse{
|
PolicyResponse: response.PolicyResponse{
|
||||||
Policy: policy.Name,
|
Policy: policy.Name,
|
||||||
|
@ -68,7 +66,7 @@ func filterRules(policy kyverno.ClusterPolicy, resource unstructured.Unstructure
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, rule := range policy.Spec.Rules {
|
for _, rule := range policy.Spec.Rules {
|
||||||
if ruleResp := filterRule(rule, resource, admissionInfo, ctx, log); ruleResp != nil {
|
if ruleResp := filterRule(rule, resource, admissionInfo, ctx); ruleResp != nil {
|
||||||
resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, *ruleResp)
|
resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, *ruleResp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,53 +10,51 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/golang/glog"
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
|
||||||
|
|
||||||
jsonpatch "github.com/evanphx/json-patch"
|
jsonpatch "github.com/evanphx/json-patch"
|
||||||
"github.com/go-logr/logr"
|
|
||||||
"github.com/nirmata/kyverno/pkg/engine/anchor"
|
"github.com/nirmata/kyverno/pkg/engine/anchor"
|
||||||
"github.com/nirmata/kyverno/pkg/engine/response"
|
"github.com/nirmata/kyverno/pkg/engine/response"
|
||||||
"github.com/nirmata/kyverno/pkg/engine/utils"
|
"github.com/nirmata/kyverno/pkg/engine/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ProcessOverlay processes mutation overlay on the resource
|
// ProcessOverlay processes mutation overlay on the resource
|
||||||
func ProcessOverlay(log logr.Logger, ruleName string, overlay interface{}, resource unstructured.Unstructured) (resp response.RuleResponse, patchedResource unstructured.Unstructured) {
|
func ProcessOverlay(ruleName string, overlay interface{}, resource unstructured.Unstructured) (resp response.RuleResponse, patchedResource unstructured.Unstructured) {
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
logger := log.WithValues("rule", ruleName)
|
glog.V(4).Infof("started applying overlay rule %q (%v)", ruleName, startTime)
|
||||||
logger.V(4).Info("started applying overlay rule ", "startTime", startTime)
|
|
||||||
resp.Name = ruleName
|
resp.Name = ruleName
|
||||||
resp.Type = utils.Mutation.String()
|
resp.Type = utils.Mutation.String()
|
||||||
defer func() {
|
defer func() {
|
||||||
resp.RuleStats.ProcessingTime = time.Since(startTime)
|
resp.RuleStats.ProcessingTime = time.Since(startTime)
|
||||||
logger.V(4).Info("finished applying overlay rule", "processingTime", resp.RuleStats.ProcessingTime)
|
glog.V(4).Infof("finished applying overlay rule %q (%v)", resp.Name, resp.RuleStats.ProcessingTime)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
patches, overlayerr := processOverlayPatches(logger, resource.UnstructuredContent(), overlay)
|
patches, overlayerr := processOverlayPatches(resource.UnstructuredContent(), overlay)
|
||||||
// resource does not satisfy the overlay pattern, we don't apply this rule
|
// resource does not satisfy the overlay pattern, we don't apply this rule
|
||||||
if !reflect.DeepEqual(overlayerr, overlayError{}) {
|
if !reflect.DeepEqual(overlayerr, overlayError{}) {
|
||||||
switch overlayerr.statusCode {
|
switch overlayerr.statusCode {
|
||||||
// condition key is not present in the resource, don't apply this rule
|
// condition key is not present in the resource, don't apply this rule
|
||||||
// consider as success
|
// consider as success
|
||||||
case conditionNotPresent:
|
case conditionNotPresent:
|
||||||
logger.V(3).Info("skip applying rule")
|
glog.V(3).Infof("Skip applying rule '%s' on resource '%s/%s/%s': %s", ruleName, resource.GetKind(), resource.GetNamespace(), resource.GetName(), overlayerr.ErrorMsg())
|
||||||
resp.Success = true
|
resp.Success = true
|
||||||
return resp, resource
|
return resp, resource
|
||||||
// conditions are not met, don't apply this rule
|
// conditions are not met, don't apply this rule
|
||||||
case conditionFailure:
|
case conditionFailure:
|
||||||
logger.V(3).Info("skip applying rule")
|
glog.V(3).Infof("Skip applying rule '%s' on resource '%s/%s/%s': %s", ruleName, resource.GetKind(), resource.GetNamespace(), resource.GetName(), overlayerr.ErrorMsg())
|
||||||
//TODO: send zero response and not consider this as applied?
|
//TODO: send zero response and not consider this as applied?
|
||||||
resp.Success = true
|
resp.Success = true
|
||||||
resp.Message = overlayerr.ErrorMsg()
|
resp.Message = overlayerr.ErrorMsg()
|
||||||
return resp, resource
|
return resp, resource
|
||||||
// rule application failed
|
// rule application failed
|
||||||
case overlayFailure:
|
case overlayFailure:
|
||||||
logger.Info("failed to process overlay")
|
glog.Errorf("Resource %s/%s/%s: failed to process overlay: %v in the rule %s", resource.GetKind(), resource.GetNamespace(), resource.GetName(), overlayerr.ErrorMsg(), ruleName)
|
||||||
resp.Success = false
|
resp.Success = false
|
||||||
resp.Message = fmt.Sprintf("failed to process overlay: %v", overlayerr.ErrorMsg())
|
resp.Message = fmt.Sprintf("failed to process overlay: %v", overlayerr.ErrorMsg())
|
||||||
return resp, resource
|
return resp, resource
|
||||||
default:
|
default:
|
||||||
logger.Info("failed to process overlay")
|
glog.Errorf("Resource %s/%s/%s: Unknown type of error: %v", resource.GetKind(), resource.GetNamespace(), resource.GetName(), overlayerr.Error())
|
||||||
resp.Success = false
|
resp.Success = false
|
||||||
resp.Message = fmt.Sprintf("Unknown type of error: %v", overlayerr.Error())
|
resp.Message = fmt.Sprintf("Unknown type of error: %v", overlayerr.Error())
|
||||||
return resp, resource
|
return resp, resource
|
||||||
|
@ -72,7 +70,7 @@ func ProcessOverlay(log logr.Logger, ruleName string, overlay interface{}, resou
|
||||||
resourceRaw, err := resource.MarshalJSON()
|
resourceRaw, err := resource.MarshalJSON()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Success = false
|
resp.Success = false
|
||||||
logger.Error(err, "failed to marshal resource")
|
glog.Infof("unable to marshall resource: %v", err)
|
||||||
resp.Message = fmt.Sprintf("failed to process JSON patches: %v", err)
|
resp.Message = fmt.Sprintf("failed to process JSON patches: %v", err)
|
||||||
return resp, resource
|
return resp, resource
|
||||||
}
|
}
|
||||||
|
@ -81,7 +79,7 @@ func ProcessOverlay(log logr.Logger, ruleName string, overlay interface{}, resou
|
||||||
patchResource, err = utils.ApplyPatches(resourceRaw, patches)
|
patchResource, err = utils.ApplyPatches(resourceRaw, patches)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
msg := fmt.Sprintf("failed to apply JSON patches: %v", err)
|
msg := fmt.Sprintf("failed to apply JSON patches: %v", err)
|
||||||
logger.V(2).Info("applying patches", "patches", string(utils.JoinPatches(patches)))
|
glog.V(2).Infof("%s, patches=%s", msg, string(utils.JoinPatches(patches)))
|
||||||
resp.Success = false
|
resp.Success = false
|
||||||
resp.Message = msg
|
resp.Message = msg
|
||||||
return resp, resource
|
return resp, resource
|
||||||
|
@ -89,7 +87,7 @@ func ProcessOverlay(log logr.Logger, ruleName string, overlay interface{}, resou
|
||||||
|
|
||||||
err = patchedResource.UnmarshalJSON(patchResource)
|
err = patchedResource.UnmarshalJSON(patchResource)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "failed to unmarshal resource")
|
glog.Infof("failed to unmarshall resource to undstructured: %v", err)
|
||||||
resp.Success = false
|
resp.Success = false
|
||||||
resp.Message = fmt.Sprintf("failed to process JSON patches: %v", err)
|
resp.Message = fmt.Sprintf("failed to process JSON patches: %v", err)
|
||||||
return resp, resource
|
return resp, resource
|
||||||
|
@ -103,17 +101,17 @@ func ProcessOverlay(log logr.Logger, ruleName string, overlay interface{}, resou
|
||||||
return resp, patchedResource
|
return resp, patchedResource
|
||||||
}
|
}
|
||||||
|
|
||||||
func processOverlayPatches(log logr.Logger, resource, overlay interface{}) ([][]byte, overlayError) {
|
func processOverlayPatches(resource, overlay interface{}) ([][]byte, overlayError) {
|
||||||
if path, overlayerr := meetConditions(log, resource, overlay); !reflect.DeepEqual(overlayerr, overlayError{}) {
|
if path, overlayerr := meetConditions(resource, overlay); !reflect.DeepEqual(overlayerr, overlayError{}) {
|
||||||
switch overlayerr.statusCode {
|
switch overlayerr.statusCode {
|
||||||
// anchor key does not exist in the resource, skip applying policy
|
// anchor key does not exist in the resource, skip applying policy
|
||||||
case conditionNotPresent:
|
case conditionNotPresent:
|
||||||
log.V(4).Info("skip applying policy", "path", path, "error", overlayerr)
|
glog.V(4).Infof("Mutate rule: skip applying policy: %v at %s", overlayerr, path)
|
||||||
return nil, newOverlayError(overlayerr.statusCode, fmt.Sprintf("Policy not applied, condition tag not present: %v at %s", overlayerr.ErrorMsg(), path))
|
return nil, newOverlayError(overlayerr.statusCode, fmt.Sprintf("Policy not applied, condition tag not present: %v at %s", overlayerr.ErrorMsg(), path))
|
||||||
// anchor key is not satisfied in the resource, skip applying policy
|
// anchor key is not satisfied in the resource, skip applying policy
|
||||||
case conditionFailure:
|
case conditionFailure:
|
||||||
// anchor key is not satisfied in the resource, skip applying policy
|
// anchor key is not satisfied in the resource, skip applying policy
|
||||||
log.V(4).Info("failed to validate condition", "path", path, "error", overlayerr)
|
glog.V(4).Infof("Mutate rule: failed to validate condition at %s, err: %v", path, overlayerr)
|
||||||
return nil, newOverlayError(overlayerr.statusCode, fmt.Sprintf("Policy not applied, conditions are not met at %s, %v", path, overlayerr))
|
return nil, newOverlayError(overlayerr.statusCode, fmt.Sprintf("Policy not applied, conditions are not met at %s, %v", path, overlayerr))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -385,7 +383,7 @@ func prepareJSONValue(overlay interface{}) string {
|
||||||
overlayWithoutAnchors := removeAnchorFromSubTree(overlay)
|
overlayWithoutAnchors := removeAnchorFromSubTree(overlay)
|
||||||
jsonOverlay, err := json.Marshal(overlayWithoutAnchors)
|
jsonOverlay, err := json.Marshal(overlayWithoutAnchors)
|
||||||
if err != nil || hasOnlyAnchors(overlay) {
|
if err != nil || hasOnlyAnchors(overlay) {
|
||||||
log.Log.Error(err, "failed to marshall withoutanchors or has only anchors")
|
glog.V(3).Info(err)
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -411,7 +409,7 @@ func removeAnchorFromSubTree(overlay interface{}) interface{} {
|
||||||
}
|
}
|
||||||
|
|
||||||
func removeAnchroFromMap(overlay map[string]interface{}) map[string]interface{} {
|
func removeAnchroFromMap(overlay map[string]interface{}) map[string]interface{} {
|
||||||
result := make(map[string]interface{})
|
result := make(map[string]interface{}, 0)
|
||||||
for k, v := range overlay {
|
for k, v := range overlay {
|
||||||
result[getRawKeyIfWrappedWithAttributes(k)] = removeAnchorFromSubTree(v)
|
result[getRawKeyIfWrappedWithAttributes(k)] = removeAnchorFromSubTree(v)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,18 +5,17 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
"github.com/golang/glog"
|
||||||
"github.com/nirmata/kyverno/pkg/engine/anchor"
|
"github.com/nirmata/kyverno/pkg/engine/anchor"
|
||||||
"github.com/nirmata/kyverno/pkg/engine/validate"
|
"github.com/nirmata/kyverno/pkg/engine/validate"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func meetConditions(log logr.Logger, resource, overlay interface{}) (string, overlayError) {
|
func meetConditions(resource, overlay interface{}) (string, overlayError) {
|
||||||
return checkConditions(log, resource, overlay, "/")
|
return checkConditions(resource, overlay, "/")
|
||||||
}
|
}
|
||||||
|
|
||||||
// resource and overlay should be the same type
|
// resource and overlay should be the same type
|
||||||
func checkConditions(log logr.Logger, resource, overlay interface{}, path string) (string, overlayError) {
|
func checkConditions(resource, overlay interface{}, path string) (string, overlayError) {
|
||||||
// overlay has no anchor, return true
|
// overlay has no anchor, return true
|
||||||
if !hasNestedAnchors(overlay) {
|
if !hasNestedAnchors(overlay) {
|
||||||
return "", overlayError{}
|
return "", overlayError{}
|
||||||
|
@ -27,7 +26,7 @@ func checkConditions(log logr.Logger, resource, overlay interface{}, path string
|
||||||
// condition never be true in this case
|
// condition never be true in this case
|
||||||
if reflect.TypeOf(resource) != reflect.TypeOf(overlay) {
|
if reflect.TypeOf(resource) != reflect.TypeOf(overlay) {
|
||||||
if hasNestedAnchors(overlay) {
|
if hasNestedAnchors(overlay) {
|
||||||
log.V(4).Info(fmt.Sprintf("Found anchor on different types of element at path %s: overlay %T, resource %T", path, overlay, resource))
|
glog.V(4).Infof("Found anchor on different types of element at path %s: overlay %T, resource %T", path, overlay, resource)
|
||||||
return path, newOverlayError(conditionFailure,
|
return path, newOverlayError(conditionFailure,
|
||||||
fmt.Sprintf("Found anchor on different types of element at path %s: overlay %T %v, resource %T %v", path, overlay, overlay, resource, resource))
|
fmt.Sprintf("Found anchor on different types of element at path %s: overlay %T %v, resource %T %v", path, overlay, overlay, resource, resource))
|
||||||
|
|
||||||
|
@ -45,7 +44,7 @@ func checkConditions(log logr.Logger, resource, overlay interface{}, path string
|
||||||
default:
|
default:
|
||||||
// anchor on non map/array is invalid:
|
// anchor on non map/array is invalid:
|
||||||
// - anchor defined on values
|
// - anchor defined on values
|
||||||
log.Info("Found invalid conditional anchor: anchor defined on values")
|
glog.Warningln("Found invalid conditional anchor: anchor defined on values")
|
||||||
return "", overlayError{}
|
return "", overlayError{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,12 +68,12 @@ func checkConditionOnMap(resourceMap, overlayMap map[string]interface{}, path st
|
||||||
|
|
||||||
func checkConditionOnArray(resource, overlay []interface{}, path string) (string, overlayError) {
|
func checkConditionOnArray(resource, overlay []interface{}, path string) (string, overlayError) {
|
||||||
if 0 == len(overlay) {
|
if 0 == len(overlay) {
|
||||||
log.Log.V(4).Info("Mutate overlay pattern is empty", "path", path)
|
glog.Infof("Mutate overlay pattern is empty, path %s", path)
|
||||||
return "", overlayError{}
|
return "", overlayError{}
|
||||||
}
|
}
|
||||||
|
|
||||||
if reflect.TypeOf(resource[0]) != reflect.TypeOf(overlay[0]) {
|
if reflect.TypeOf(resource[0]) != reflect.TypeOf(overlay[0]) {
|
||||||
log.Log.V(4).Info(fmt.Sprintf("Overlay array and resource array have elements of different types: %T and %T", overlay[0], resource[0]))
|
glog.V(4).Infof("Overlay array and resource array have elements of different types: %T and %T", overlay[0], resource[0])
|
||||||
return path, newOverlayError(conditionFailure,
|
return path, newOverlayError(conditionFailure,
|
||||||
fmt.Sprintf("Overlay array and resource array have elements of different types: %T and %T", overlay[0], resource[0]))
|
fmt.Sprintf("Overlay array and resource array have elements of different types: %T and %T", overlay[0], resource[0]))
|
||||||
}
|
}
|
||||||
|
@ -112,7 +111,7 @@ func validateConditionAnchorMap(resourceMap, anchors map[string]interface{}, pat
|
||||||
// resource - A: B2
|
// resource - A: B2
|
||||||
func compareOverlay(resource, overlay interface{}, path string) (string, overlayError) {
|
func compareOverlay(resource, overlay interface{}, path string) (string, overlayError) {
|
||||||
if reflect.TypeOf(resource) != reflect.TypeOf(overlay) {
|
if reflect.TypeOf(resource) != reflect.TypeOf(overlay) {
|
||||||
log.Log.V(4).Info("Found anchor on different types of element: overlay %T, resource %T", overlay, resource)
|
glog.V(4).Infof("Found anchor on different types of element: overlay %T, resource %T", overlay, resource)
|
||||||
return path, newOverlayError(conditionFailure, fmt.Sprintf("Found anchor on different types of element: overlay %T, resource %T", overlay, resource))
|
return path, newOverlayError(conditionFailure, fmt.Sprintf("Found anchor on different types of element: overlay %T, resource %T", overlay, resource))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,8 +139,8 @@ func compareOverlay(resource, overlay interface{}, path string) (string, overlay
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case string, float64, int, int64, bool, nil:
|
case string, float64, int, int64, bool, nil:
|
||||||
if !validate.ValidateValueWithPattern(log.Log, resource, overlay) {
|
if !validate.ValidateValueWithPattern(resource, overlay) {
|
||||||
log.Log.V(4).Info(fmt.Sprintf("Mutate rule: failed validating value %v with overlay %v", resource, overlay))
|
glog.V(4).Infof("Mutate rule: failed validating value %v with overlay %v", resource, overlay)
|
||||||
return path, newOverlayError(conditionFailure, fmt.Sprintf("Failed validating value %v with overlay %v", resource, overlay))
|
return path, newOverlayError(conditionFailure, fmt.Sprintf("Failed validating value %v with overlay %v", resource, overlay))
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -166,7 +165,7 @@ func validateNonAnchorOverlayMap(resourceMap, overlayWithoutAnchor map[string]in
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if newPath, err := checkConditions(log.Log, resourceValue, overlayValue, curPath); !reflect.DeepEqual(err, overlayError{}) {
|
if newPath, err := checkConditions(resourceValue, overlayValue, curPath); !reflect.DeepEqual(err, overlayError{}) {
|
||||||
return newPath, err
|
return newPath, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -180,7 +179,7 @@ func checkConditionsOnArrayOfSameTypes(resource, overlay []interface{}, path str
|
||||||
default:
|
default:
|
||||||
for i, overlayElement := range overlay {
|
for i, overlayElement := range overlay {
|
||||||
curPath := path + strconv.Itoa(i) + "/"
|
curPath := path + strconv.Itoa(i) + "/"
|
||||||
path, err := checkConditions(log.Log, resource[i], overlayElement, curPath)
|
path, err := checkConditions(resource[i], overlayElement, curPath)
|
||||||
if !reflect.DeepEqual(err, overlayError{}) {
|
if !reflect.DeepEqual(err, overlayError{}) {
|
||||||
return path, err
|
return path, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"gotest.tools/assert"
|
"gotest.tools/assert"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMeetConditions_NoAnchor(t *testing.T) {
|
func TestMeetConditions_NoAnchor(t *testing.T) {
|
||||||
|
@ -27,11 +26,9 @@ func TestMeetConditions_NoAnchor(t *testing.T) {
|
||||||
}`)
|
}`)
|
||||||
var overlay interface{}
|
var overlay interface{}
|
||||||
|
|
||||||
err := json.Unmarshal(overlayRaw, &overlay)
|
json.Unmarshal(overlayRaw, &overlay)
|
||||||
assert.Assert(t, reflect.DeepEqual(err, nil))
|
|
||||||
|
|
||||||
_, err = meetConditions(log.Log, nil, overlay)
|
|
||||||
|
|
||||||
|
_, err := meetConditions(nil, overlay)
|
||||||
assert.Assert(t, reflect.DeepEqual(err, overlayError{}))
|
assert.Assert(t, reflect.DeepEqual(err, overlayError{}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,12 +78,10 @@ func TestMeetConditions_conditionalAnchorOnMap(t *testing.T) {
|
||||||
|
|
||||||
var resource, overlay interface{}
|
var resource, overlay interface{}
|
||||||
|
|
||||||
err := json.Unmarshal(resourceRaw, &resource)
|
json.Unmarshal(resourceRaw, &resource)
|
||||||
assert.NilError(t, err)
|
json.Unmarshal(overlayRaw, &overlay)
|
||||||
err = json.Unmarshal(overlayRaw, &overlay)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
_, err = meetConditions(log.Log, resource, overlay)
|
_, err := meetConditions(resource, overlay)
|
||||||
assert.Assert(t, !reflect.DeepEqual(err, overlayError{}))
|
assert.Assert(t, !reflect.DeepEqual(err, overlayError{}))
|
||||||
|
|
||||||
overlayRaw = []byte(`
|
overlayRaw = []byte(`
|
||||||
|
@ -104,10 +99,9 @@ func TestMeetConditions_conditionalAnchorOnMap(t *testing.T) {
|
||||||
]
|
]
|
||||||
}`)
|
}`)
|
||||||
|
|
||||||
err = json.Unmarshal(overlayRaw, &overlay)
|
json.Unmarshal(overlayRaw, &overlay)
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
_, overlayerr := meetConditions(log.Log, resource, overlay)
|
_, overlayerr := meetConditions(resource, overlay)
|
||||||
assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{}))
|
assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,14 +136,11 @@ func TestMeetConditions_DifferentTypes(t *testing.T) {
|
||||||
}`)
|
}`)
|
||||||
var resource, overlay interface{}
|
var resource, overlay interface{}
|
||||||
|
|
||||||
err := json.Unmarshal(resourceRaw, &resource)
|
json.Unmarshal(resourceRaw, &resource)
|
||||||
assert.NilError(t, err)
|
json.Unmarshal(overlayRaw, &overlay)
|
||||||
err = json.Unmarshal(overlayRaw, &overlay)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
// anchor exist
|
// anchor exist
|
||||||
|
_, err := meetConditions(resource, overlay)
|
||||||
_, err = meetConditions(log.Log, resource, overlay)
|
|
||||||
assert.Assert(t, strings.Contains(err.Error(), "Found anchor on different types of element at path /subsets/"))
|
assert.Assert(t, strings.Contains(err.Error(), "Found anchor on different types of element at path /subsets/"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,12 +190,10 @@ func TestMeetConditions_anchosInSameObject(t *testing.T) {
|
||||||
|
|
||||||
var resource, overlay interface{}
|
var resource, overlay interface{}
|
||||||
|
|
||||||
err := json.Unmarshal(resourceRaw, &resource)
|
json.Unmarshal(resourceRaw, &resource)
|
||||||
assert.NilError(t, err)
|
json.Unmarshal(overlayRaw, &overlay)
|
||||||
err = json.Unmarshal(overlayRaw, &overlay)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
_, err = meetConditions(log.Log, resource, overlay)
|
_, err := meetConditions(resource, overlay)
|
||||||
assert.Error(t, err, "[overlayError:0] Failed validating value 443 with overlay 444")
|
assert.Error(t, err, "[overlayError:0] Failed validating value 443 with overlay 444")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -259,13 +248,10 @@ func TestMeetConditions_anchorOnPeer(t *testing.T) {
|
||||||
|
|
||||||
var resource, overlay interface{}
|
var resource, overlay interface{}
|
||||||
|
|
||||||
err := json.Unmarshal(resourceRaw, &resource)
|
json.Unmarshal(resourceRaw, &resource)
|
||||||
assert.NilError(t, err)
|
json.Unmarshal(overlayRaw, &overlay)
|
||||||
err = json.Unmarshal(overlayRaw, &overlay)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
_, err = meetConditions(log.Log, resource, overlay)
|
|
||||||
|
|
||||||
|
_, err := meetConditions(resource, overlay)
|
||||||
assert.Assert(t, reflect.DeepEqual(err, overlayError{}))
|
assert.Assert(t, reflect.DeepEqual(err, overlayError{}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -339,13 +325,10 @@ func TestMeetConditions_anchorsOnMetaAndSpec(t *testing.T) {
|
||||||
|
|
||||||
var resource, overlay interface{}
|
var resource, overlay interface{}
|
||||||
|
|
||||||
err := json.Unmarshal(resourceRaw, &resource)
|
json.Unmarshal(resourceRaw, &resource)
|
||||||
assert.NilError(t, err)
|
json.Unmarshal(overlayRaw, &overlay)
|
||||||
err = json.Unmarshal(overlayRaw, &overlay)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
_, err = meetConditions(log.Log, resource, overlay)
|
|
||||||
|
|
||||||
|
_, err := meetConditions(resource, overlay)
|
||||||
assert.Assert(t, reflect.DeepEqual(err, overlayError{}))
|
assert.Assert(t, reflect.DeepEqual(err, overlayError{}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -423,13 +406,10 @@ func TestMeetConditions_anchorsOnPeer_single(t *testing.T) {
|
||||||
|
|
||||||
var resource, overlay interface{}
|
var resource, overlay interface{}
|
||||||
|
|
||||||
err := json.Unmarshal(resourceRawAnchorOnPeers, &resource)
|
json.Unmarshal(resourceRawAnchorOnPeers, &resource)
|
||||||
assert.NilError(t, err)
|
json.Unmarshal(overlayRaw, &overlay)
|
||||||
err = json.Unmarshal(overlayRaw, &overlay)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
_, err = meetConditions(log.Log, resource, overlay)
|
|
||||||
|
|
||||||
|
_, err := meetConditions(resource, overlay)
|
||||||
assert.Assert(t, reflect.DeepEqual(err, overlayError{}))
|
assert.Assert(t, reflect.DeepEqual(err, overlayError{}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -460,13 +440,10 @@ func TestMeetConditions_anchorsOnPeer_two(t *testing.T) {
|
||||||
|
|
||||||
var resource, overlay interface{}
|
var resource, overlay interface{}
|
||||||
|
|
||||||
err := json.Unmarshal(resourceRawAnchorOnPeers, &resource)
|
json.Unmarshal(resourceRawAnchorOnPeers, &resource)
|
||||||
assert.NilError(t, err)
|
json.Unmarshal(overlayRaw, &overlay)
|
||||||
err = json.Unmarshal(overlayRaw, &overlay)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
_, err = meetConditions(log.Log, resource, overlay)
|
|
||||||
|
|
||||||
|
_, err := meetConditions(resource, overlay)
|
||||||
assert.Error(t, err, "[overlayError:0] Failed validating value true with overlay false")
|
assert.Error(t, err, "[overlayError:0] Failed validating value true with overlay false")
|
||||||
|
|
||||||
overlayRaw = []byte(`{
|
overlayRaw = []byte(`{
|
||||||
|
@ -493,10 +470,9 @@ func TestMeetConditions_anchorsOnPeer_two(t *testing.T) {
|
||||||
}
|
}
|
||||||
}`)
|
}`)
|
||||||
|
|
||||||
err = json.Unmarshal(overlayRaw, &overlay)
|
json.Unmarshal(overlayRaw, &overlay)
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
_, err = meetConditions(log.Log, resource, overlay)
|
_, err = meetConditions(resource, overlay)
|
||||||
assert.Assert(t, reflect.DeepEqual(err, overlayError{}))
|
assert.Assert(t, reflect.DeepEqual(err, overlayError{}))
|
||||||
|
|
||||||
overlayRaw = []byte(`{
|
overlayRaw = []byte(`{
|
||||||
|
@ -523,10 +499,9 @@ func TestMeetConditions_anchorsOnPeer_two(t *testing.T) {
|
||||||
}
|
}
|
||||||
}`)
|
}`)
|
||||||
|
|
||||||
err = json.Unmarshal(overlayRaw, &overlay)
|
json.Unmarshal(overlayRaw, &overlay)
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
_, err = meetConditions(log.Log, resource, overlay)
|
_, err = meetConditions(resource, overlay)
|
||||||
assert.Assert(t, reflect.DeepEqual(err, overlayError{}))
|
assert.Assert(t, reflect.DeepEqual(err, overlayError{}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -557,13 +532,10 @@ func TestMeetConditions_anchorsOnPeer_multiple(t *testing.T) {
|
||||||
|
|
||||||
var resource, overlay interface{}
|
var resource, overlay interface{}
|
||||||
|
|
||||||
err := json.Unmarshal(resourceRawAnchorOnPeers, &resource)
|
json.Unmarshal(resourceRawAnchorOnPeers, &resource)
|
||||||
assert.NilError(t, err)
|
json.Unmarshal(overlayRaw, &overlay)
|
||||||
err = json.Unmarshal(overlayRaw, &overlay)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
_, err = meetConditions(log.Log, resource, overlay)
|
|
||||||
|
|
||||||
|
_, err := meetConditions(resource, overlay)
|
||||||
assert.Assert(t, reflect.DeepEqual(err, overlayError{}))
|
assert.Assert(t, reflect.DeepEqual(err, overlayError{}))
|
||||||
|
|
||||||
overlayRaw = []byte(`{
|
overlayRaw = []byte(`{
|
||||||
|
@ -590,10 +562,9 @@ func TestMeetConditions_anchorsOnPeer_multiple(t *testing.T) {
|
||||||
}
|
}
|
||||||
}`)
|
}`)
|
||||||
|
|
||||||
err = json.Unmarshal(overlayRaw, &overlay)
|
json.Unmarshal(overlayRaw, &overlay)
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
_, err = meetConditions(log.Log, resource, overlay)
|
_, err = meetConditions(resource, overlay)
|
||||||
assert.Assert(t, reflect.DeepEqual(err, overlayError{}))
|
assert.Assert(t, reflect.DeepEqual(err, overlayError{}))
|
||||||
|
|
||||||
overlayRaw = []byte(`{
|
overlayRaw = []byte(`{
|
||||||
|
@ -620,10 +591,9 @@ func TestMeetConditions_anchorsOnPeer_multiple(t *testing.T) {
|
||||||
}
|
}
|
||||||
}`)
|
}`)
|
||||||
|
|
||||||
err = json.Unmarshal(overlayRaw, &overlay)
|
json.Unmarshal(overlayRaw, &overlay)
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
_, err = meetConditions(log.Log, resource, overlay)
|
_, err = meetConditions(resource, overlay)
|
||||||
assert.Error(t, err, "[overlayError:0] Failed validating value ENV_VALUE with overlay ENV_VALUE1")
|
assert.Error(t, err, "[overlayError:0] Failed validating value ENV_VALUE with overlay ENV_VALUE1")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -679,13 +649,10 @@ func TestMeetConditions_AtleastOneExist(t *testing.T) {
|
||||||
|
|
||||||
var resource, overlay interface{}
|
var resource, overlay interface{}
|
||||||
|
|
||||||
err := json.Unmarshal(resourceRaw, &resource)
|
json.Unmarshal(resourceRaw, &resource)
|
||||||
assert.NilError(t, err)
|
json.Unmarshal(overlayRaw, &overlay)
|
||||||
err = json.Unmarshal(overlayRaw, &overlay)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
path, err := meetConditions(log.Log, resource, overlay)
|
|
||||||
|
|
||||||
|
path, err := meetConditions(resource, overlay)
|
||||||
assert.Assert(t, reflect.DeepEqual(err, overlayError{}))
|
assert.Assert(t, reflect.DeepEqual(err, overlayError{}))
|
||||||
assert.Assert(t, len(path) == 0)
|
assert.Assert(t, len(path) == 0)
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@ import (
|
||||||
jsonpatch "github.com/evanphx/json-patch"
|
jsonpatch "github.com/evanphx/json-patch"
|
||||||
"github.com/nirmata/kyverno/pkg/engine/utils"
|
"github.com/nirmata/kyverno/pkg/engine/utils"
|
||||||
"gotest.tools/assert"
|
"gotest.tools/assert"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func compareJSONAsMap(t *testing.T, expected, actual []byte) {
|
func compareJSONAsMap(t *testing.T, expected, actual []byte) {
|
||||||
|
@ -64,12 +63,10 @@ func TestProcessOverlayPatches_NestedListWithAnchor(t *testing.T) {
|
||||||
|
|
||||||
var resource, overlay interface{}
|
var resource, overlay interface{}
|
||||||
|
|
||||||
err := json.Unmarshal(resourceRaw, &resource)
|
json.Unmarshal(resourceRaw, &resource)
|
||||||
assert.NilError(t, err)
|
json.Unmarshal(overlayRaw, &overlay)
|
||||||
err = json.Unmarshal(overlayRaw, &overlay)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
patches, overlayerr := processOverlayPatches(log.Log, resource, overlay)
|
patches, overlayerr := processOverlayPatches(resource, overlay)
|
||||||
assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{}))
|
assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{}))
|
||||||
assert.Assert(t, patches != nil)
|
assert.Assert(t, patches != nil)
|
||||||
|
|
||||||
|
@ -166,12 +163,10 @@ func TestProcessOverlayPatches_InsertIntoArray(t *testing.T) {
|
||||||
|
|
||||||
var resource, overlay interface{}
|
var resource, overlay interface{}
|
||||||
|
|
||||||
err := json.Unmarshal(resourceRaw, &resource)
|
json.Unmarshal(resourceRaw, &resource)
|
||||||
assert.NilError(t, err)
|
json.Unmarshal(overlayRaw, &overlay)
|
||||||
err = json.Unmarshal(overlayRaw, &overlay)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
patches, overlayerr := processOverlayPatches(log.Log, resource, overlay)
|
patches, overlayerr := processOverlayPatches(resource, overlay)
|
||||||
assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{}))
|
assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{}))
|
||||||
assert.Assert(t, patches != nil)
|
assert.Assert(t, patches != nil)
|
||||||
|
|
||||||
|
@ -289,12 +284,10 @@ func TestProcessOverlayPatches_TestInsertToArray(t *testing.T) {
|
||||||
|
|
||||||
var resource, overlay interface{}
|
var resource, overlay interface{}
|
||||||
|
|
||||||
err := json.Unmarshal(resourceRaw, &resource)
|
json.Unmarshal(resourceRaw, &resource)
|
||||||
assert.NilError(t, err)
|
json.Unmarshal(overlayRaw, &overlay)
|
||||||
err = json.Unmarshal(overlayRaw, &overlay)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
patches, overlayerr := processOverlayPatches(log.Log, resource, overlay)
|
patches, overlayerr := processOverlayPatches(resource, overlay)
|
||||||
assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{}))
|
assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{}))
|
||||||
assert.Assert(t, patches != nil)
|
assert.Assert(t, patches != nil)
|
||||||
|
|
||||||
|
@ -374,12 +367,10 @@ func TestProcessOverlayPatches_ImagePullPolicy(t *testing.T) {
|
||||||
|
|
||||||
var resource, overlay interface{}
|
var resource, overlay interface{}
|
||||||
|
|
||||||
err := json.Unmarshal(resourceRaw, &resource)
|
json.Unmarshal(resourceRaw, &resource)
|
||||||
assert.NilError(t, err)
|
json.Unmarshal(overlayRaw, &overlay)
|
||||||
err = json.Unmarshal(overlayRaw, &overlay)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
patches, overlayerr := processOverlayPatches(log.Log, resource, overlay)
|
patches, overlayerr := processOverlayPatches(resource, overlay)
|
||||||
assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{}))
|
assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{}))
|
||||||
assert.Assert(t, len(patches) != 0)
|
assert.Assert(t, len(patches) != 0)
|
||||||
|
|
||||||
|
@ -465,10 +456,9 @@ func TestProcessOverlayPatches_ImagePullPolicy(t *testing.T) {
|
||||||
}
|
}
|
||||||
}`)
|
}`)
|
||||||
|
|
||||||
err = json.Unmarshal(overlayRaw, &overlay)
|
json.Unmarshal(overlayRaw, &overlay)
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
patches, err = processOverlayPatches(log.Log, resource, overlay)
|
patches, err = processOverlayPatches(resource, overlay)
|
||||||
assert.Assert(t, reflect.DeepEqual(err, overlayError{}))
|
assert.Assert(t, reflect.DeepEqual(err, overlayError{}))
|
||||||
assert.Assert(t, len(patches) != 0)
|
assert.Assert(t, len(patches) != 0)
|
||||||
|
|
||||||
|
@ -502,10 +492,9 @@ func TestProcessOverlayPatches_ImagePullPolicy(t *testing.T) {
|
||||||
}
|
}
|
||||||
}`)
|
}`)
|
||||||
|
|
||||||
err = json.Unmarshal(overlayRaw, &overlay)
|
json.Unmarshal(overlayRaw, &overlay)
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
patches, err = processOverlayPatches(log.Log, resource, overlay)
|
patches, err = processOverlayPatches(resource, overlay)
|
||||||
assert.Error(t, err, "[overlayError:0] Policy not applied, conditions are not met at /spec/template/metadata/labels/app/, [overlayError:0] Failed validating value nginx with overlay nginx1")
|
assert.Error(t, err, "[overlayError:0] Policy not applied, conditions are not met at /spec/template/metadata/labels/app/, [overlayError:0] Failed validating value nginx with overlay nginx1")
|
||||||
assert.Assert(t, len(patches) == 0)
|
assert.Assert(t, len(patches) == 0)
|
||||||
}
|
}
|
||||||
|
@ -531,12 +520,10 @@ func TestProcessOverlayPatches_AddingAnchor(t *testing.T) {
|
||||||
|
|
||||||
var resource, overlay interface{}
|
var resource, overlay interface{}
|
||||||
|
|
||||||
err := json.Unmarshal(resourceRaw, &resource)
|
json.Unmarshal(resourceRaw, &resource)
|
||||||
assert.NilError(t, err)
|
json.Unmarshal(overlayRaw, &overlay)
|
||||||
err = json.Unmarshal(overlayRaw, &overlay)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
patches, overlayerr := processOverlayPatches(log.Log, resource, overlay)
|
patches, overlayerr := processOverlayPatches(resource, overlay)
|
||||||
assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{}))
|
assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{}))
|
||||||
assert.Assert(t, len(patches) != 0)
|
assert.Assert(t, len(patches) != 0)
|
||||||
|
|
||||||
|
@ -618,12 +605,10 @@ func TestProcessOverlayPatches_AddingAnchorInsideListElement(t *testing.T) {
|
||||||
|
|
||||||
var resource, overlay interface{}
|
var resource, overlay interface{}
|
||||||
|
|
||||||
err := json.Unmarshal(resourceRaw, &resource)
|
json.Unmarshal(resourceRaw, &resource)
|
||||||
assert.NilError(t, err)
|
json.Unmarshal(overlayRaw, &overlay)
|
||||||
err = json.Unmarshal(overlayRaw, &overlay)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
patches, overlayerr := processOverlayPatches(log.Log, resource, overlay)
|
patches, overlayerr := processOverlayPatches(resource, overlay)
|
||||||
assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{}))
|
assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{}))
|
||||||
assert.Assert(t, len(patches) != 0)
|
assert.Assert(t, len(patches) != 0)
|
||||||
|
|
||||||
|
@ -699,10 +684,9 @@ func TestProcessOverlayPatches_AddingAnchorInsideListElement(t *testing.T) {
|
||||||
}
|
}
|
||||||
}`)
|
}`)
|
||||||
|
|
||||||
err = json.Unmarshal(overlayRaw, &overlay)
|
json.Unmarshal(overlayRaw, &overlay)
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
patches, err = processOverlayPatches(log.Log, resource, overlay)
|
patches, err = processOverlayPatches(resource, overlay)
|
||||||
assert.Assert(t, reflect.DeepEqual(err, overlayError{}))
|
assert.Assert(t, reflect.DeepEqual(err, overlayError{}))
|
||||||
assert.Assert(t, len(patches) != 0)
|
assert.Assert(t, len(patches) != 0)
|
||||||
|
|
||||||
|
@ -763,12 +747,10 @@ func TestProcessOverlayPatches_anchorOnPeer(t *testing.T) {
|
||||||
|
|
||||||
var resource, overlay interface{}
|
var resource, overlay interface{}
|
||||||
|
|
||||||
err := json.Unmarshal(resourceRaw, &resource)
|
json.Unmarshal(resourceRaw, &resource)
|
||||||
assert.NilError(t, err)
|
json.Unmarshal(overlayRaw, &overlay)
|
||||||
err = json.Unmarshal(overlayRaw, &overlay)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
patches, overlayerr := processOverlayPatches(log.Log, resource, overlay)
|
patches, overlayerr := processOverlayPatches(resource, overlay)
|
||||||
assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{}))
|
assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{}))
|
||||||
assert.Assert(t, len(patches) != 0)
|
assert.Assert(t, len(patches) != 0)
|
||||||
|
|
||||||
|
@ -823,10 +805,9 @@ func TestProcessOverlayPatches_anchorOnPeer(t *testing.T) {
|
||||||
]
|
]
|
||||||
}`)
|
}`)
|
||||||
|
|
||||||
err = json.Unmarshal(overlayRaw, &overlay)
|
json.Unmarshal(overlayRaw, &overlay)
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
patches, err = processOverlayPatches(log.Log, resource, overlay)
|
patches, err = processOverlayPatches(resource, overlay)
|
||||||
assert.Error(t, err, "[overlayError:0] Policy not applied, conditions are not met at /subsets/0/ports/0/port/, [overlayError:0] Failed validating value 443 with overlay 444")
|
assert.Error(t, err, "[overlayError:0] Policy not applied, conditions are not met at /subsets/0/ports/0/port/, [overlayError:0] Failed validating value 443 with overlay 444")
|
||||||
assert.Assert(t, len(patches) == 0)
|
assert.Assert(t, len(patches) == 0)
|
||||||
}
|
}
|
||||||
|
@ -905,12 +886,10 @@ func TestProcessOverlayPatches_insertWithCondition(t *testing.T) {
|
||||||
|
|
||||||
var resource, overlay interface{}
|
var resource, overlay interface{}
|
||||||
|
|
||||||
err := json.Unmarshal(resourceRaw, &resource)
|
json.Unmarshal(resourceRaw, &resource)
|
||||||
assert.NilError(t, err)
|
json.Unmarshal(overlayRaw, &overlay)
|
||||||
err = json.Unmarshal(overlayRaw, &overlay)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
patches, overlayerr := processOverlayPatches(log.Log, resource, overlay)
|
patches, overlayerr := processOverlayPatches(resource, overlay)
|
||||||
assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{}))
|
assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{}))
|
||||||
assert.Assert(t, len(patches) != 0)
|
assert.Assert(t, len(patches) != 0)
|
||||||
|
|
||||||
|
@ -1018,12 +997,10 @@ func TestProcessOverlayPatches_InsertIfNotPresentWithConditions(t *testing.T) {
|
||||||
|
|
||||||
var resource, overlay interface{}
|
var resource, overlay interface{}
|
||||||
|
|
||||||
err := json.Unmarshal(resourceRaw, &resource)
|
json.Unmarshal(resourceRaw, &resource)
|
||||||
assert.NilError(t, err)
|
json.Unmarshal(overlayRaw, &overlay)
|
||||||
err = json.Unmarshal(overlayRaw, &overlay)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
patches, overlayerr := processOverlayPatches(log.Log, resource, overlay)
|
patches, overlayerr := processOverlayPatches(resource, overlay)
|
||||||
assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{}))
|
assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{}))
|
||||||
assert.Assert(t, len(patches) != 0)
|
assert.Assert(t, len(patches) != 0)
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
"github.com/golang/glog"
|
||||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||||
"github.com/nirmata/kyverno/pkg/engine/response"
|
"github.com/nirmata/kyverno/pkg/engine/response"
|
||||||
"github.com/nirmata/kyverno/pkg/engine/utils"
|
"github.com/nirmata/kyverno/pkg/engine/utils"
|
||||||
|
@ -20,22 +20,21 @@ func applyPatch(resource []byte, patchRaw []byte) ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
//ProcessPatches applies the patches on the resource and returns the patched resource
|
//ProcessPatches applies the patches on the resource and returns the patched resource
|
||||||
func ProcessPatches(log logr.Logger, rule kyverno.Rule, resource unstructured.Unstructured) (resp response.RuleResponse, patchedResource unstructured.Unstructured) {
|
func ProcessPatches(rule kyverno.Rule, resource unstructured.Unstructured) (resp response.RuleResponse, patchedResource unstructured.Unstructured) {
|
||||||
logger := log.WithValues("rule", rule.Name)
|
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
logger.V(4).Info("started JSON patch", "startTime", startTime)
|
glog.V(4).Infof("started JSON patch rule %q (%v)", rule.Name, startTime)
|
||||||
resp.Name = rule.Name
|
resp.Name = rule.Name
|
||||||
resp.Type = utils.Mutation.String()
|
resp.Type = utils.Mutation.String()
|
||||||
defer func() {
|
defer func() {
|
||||||
resp.RuleStats.ProcessingTime = time.Since(startTime)
|
resp.RuleStats.ProcessingTime = time.Since(startTime)
|
||||||
logger.V(4).Info("finished JSON patch", "processingTime", resp.RuleStats.ProcessingTime)
|
glog.V(4).Infof("finished JSON patch rule %q (%v)", resp.Name, resp.RuleStats.ProcessingTime)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// convert to RAW
|
// convert to RAW
|
||||||
resourceRaw, err := resource.MarshalJSON()
|
resourceRaw, err := resource.MarshalJSON()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Success = false
|
resp.Success = false
|
||||||
logger.Error(err, "failed to marshal resource")
|
glog.Infof("unable to marshall resource: %v", err)
|
||||||
resp.Message = fmt.Sprintf("failed to process JSON patches: %v", err)
|
resp.Message = fmt.Sprintf("failed to process JSON patches: %v", err)
|
||||||
return resp, resource
|
return resp, resource
|
||||||
}
|
}
|
||||||
|
@ -46,14 +45,14 @@ func ProcessPatches(log logr.Logger, rule kyverno.Rule, resource unstructured.Un
|
||||||
// JSON patch
|
// JSON patch
|
||||||
patchRaw, err := json.Marshal(patch)
|
patchRaw, err := json.Marshal(patch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "failed to marshal JSON patch")
|
glog.V(4).Infof("failed to marshall JSON patch %v: %v", patch, err)
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
patchResource, err := applyPatch(resourceRaw, patchRaw)
|
patchResource, err := applyPatch(resourceRaw, patchRaw)
|
||||||
// TODO: continue on error if one of the patches fails, will add the failure event in such case
|
// TODO: continue on error if one of the patches fails, will add the failure event in such case
|
||||||
if err != nil && patch.Operation == "remove" {
|
if err != nil && patch.Operation == "remove" {
|
||||||
log.Error(err, "failed to process JSON path or patch is a 'remove' operation")
|
glog.Info(err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -78,7 +77,7 @@ func ProcessPatches(log logr.Logger, rule kyverno.Rule, resource unstructured.Un
|
||||||
}
|
}
|
||||||
err = patchedResource.UnmarshalJSON(resourceRaw)
|
err = patchedResource.UnmarshalJSON(resourceRaw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "failed to unmmarshal resource")
|
glog.Infof("failed to unmarshall resource to undstructured: %v", err)
|
||||||
resp.Success = false
|
resp.Success = false
|
||||||
resp.Message = fmt.Sprintf("failed to process JSON patches: %v", err)
|
resp.Message = fmt.Sprintf("failed to process JSON patches: %v", err)
|
||||||
return resp, resource
|
return resp, resource
|
||||||
|
|
|
@ -5,7 +5,6 @@ import (
|
||||||
|
|
||||||
"gotest.tools/assert"
|
"gotest.tools/assert"
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
|
||||||
|
|
||||||
types "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
types "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||||
"github.com/nirmata/kyverno/pkg/engine/utils"
|
"github.com/nirmata/kyverno/pkg/engine/utils"
|
||||||
|
@ -42,7 +41,7 @@ func TestProcessPatches_EmptyPatches(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
rr, _ := ProcessPatches(log.Log, emptyRule, *resourceUnstructured)
|
rr, _ := ProcessPatches(emptyRule, *resourceUnstructured)
|
||||||
assert.Check(t, rr.Success)
|
assert.Check(t, rr.Success)
|
||||||
assert.Assert(t, len(rr.Patches) == 0)
|
assert.Assert(t, len(rr.Patches) == 0)
|
||||||
}
|
}
|
||||||
|
@ -71,14 +70,14 @@ func makeRuleWithPatches(patches []types.Patch) types.Rule {
|
||||||
|
|
||||||
func TestProcessPatches_EmptyDocument(t *testing.T) {
|
func TestProcessPatches_EmptyDocument(t *testing.T) {
|
||||||
rule := makeRuleWithPatch(makeAddIsMutatedLabelPatch())
|
rule := makeRuleWithPatch(makeAddIsMutatedLabelPatch())
|
||||||
rr, _ := ProcessPatches(log.Log, rule, unstructured.Unstructured{})
|
rr, _ := ProcessPatches(rule, unstructured.Unstructured{})
|
||||||
assert.Assert(t, !rr.Success)
|
assert.Assert(t, !rr.Success)
|
||||||
assert.Assert(t, len(rr.Patches) == 0)
|
assert.Assert(t, len(rr.Patches) == 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestProcessPatches_AllEmpty(t *testing.T) {
|
func TestProcessPatches_AllEmpty(t *testing.T) {
|
||||||
emptyRule := types.Rule{}
|
emptyRule := types.Rule{}
|
||||||
rr, _ := ProcessPatches(log.Log, emptyRule, unstructured.Unstructured{})
|
rr, _ := ProcessPatches(emptyRule, unstructured.Unstructured{})
|
||||||
assert.Check(t, !rr.Success)
|
assert.Check(t, !rr.Success)
|
||||||
assert.Assert(t, len(rr.Patches) == 0)
|
assert.Assert(t, len(rr.Patches) == 0)
|
||||||
}
|
}
|
||||||
|
@ -91,7 +90,7 @@ func TestProcessPatches_AddPathDoesntExist(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
rr, _ := ProcessPatches(log.Log, rule, *resourceUnstructured)
|
rr, _ := ProcessPatches(rule, *resourceUnstructured)
|
||||||
assert.Check(t, !rr.Success)
|
assert.Check(t, !rr.Success)
|
||||||
assert.Assert(t, len(rr.Patches) == 0)
|
assert.Assert(t, len(rr.Patches) == 0)
|
||||||
}
|
}
|
||||||
|
@ -103,7 +102,7 @@ func TestProcessPatches_RemovePathDoesntExist(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
rr, _ := ProcessPatches(log.Log, rule, *resourceUnstructured)
|
rr, _ := ProcessPatches(rule, *resourceUnstructured)
|
||||||
assert.Check(t, rr.Success)
|
assert.Check(t, rr.Success)
|
||||||
assert.Assert(t, len(rr.Patches) == 0)
|
assert.Assert(t, len(rr.Patches) == 0)
|
||||||
}
|
}
|
||||||
|
@ -116,7 +115,7 @@ func TestProcessPatches_AddAndRemovePathsDontExist_EmptyResult(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
rr, _ := ProcessPatches(log.Log, rule, *resourceUnstructured)
|
rr, _ := ProcessPatches(rule, *resourceUnstructured)
|
||||||
assert.Check(t, !rr.Success)
|
assert.Check(t, !rr.Success)
|
||||||
assert.Assert(t, len(rr.Patches) == 0)
|
assert.Assert(t, len(rr.Patches) == 0)
|
||||||
}
|
}
|
||||||
|
@ -130,7 +129,7 @@ func TestProcessPatches_AddAndRemovePathsDontExist_ContinueOnError_NotEmptyResul
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
rr, _ := ProcessPatches(log.Log, rule, *resourceUnstructured)
|
rr, _ := ProcessPatches(rule, *resourceUnstructured)
|
||||||
assert.Check(t, rr.Success)
|
assert.Check(t, rr.Success)
|
||||||
assert.Assert(t, len(rr.Patches) != 0)
|
assert.Assert(t, len(rr.Patches) != 0)
|
||||||
assertEqStringAndData(t, `{"path":"/metadata/labels/label3","op":"add","value":"label3Value"}`, rr.Patches[0])
|
assertEqStringAndData(t, `{"path":"/metadata/labels/label3","op":"add","value":"label3Value"}`, rr.Patches[0])
|
||||||
|
@ -143,7 +142,7 @@ func TestProcessPatches_RemovePathDoesntExist_EmptyResult(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
rr, _ := ProcessPatches(log.Log, rule, *resourceUnstructured)
|
rr, _ := ProcessPatches(rule, *resourceUnstructured)
|
||||||
assert.Check(t, rr.Success)
|
assert.Check(t, rr.Success)
|
||||||
assert.Assert(t, len(rr.Patches) == 0)
|
assert.Assert(t, len(rr.Patches) == 0)
|
||||||
}
|
}
|
||||||
|
@ -156,7 +155,7 @@ func TestProcessPatches_RemovePathDoesntExist_NotEmptyResult(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
rr, _ := ProcessPatches(log.Log, rule, *resourceUnstructured)
|
rr, _ := ProcessPatches(rule, *resourceUnstructured)
|
||||||
assert.Check(t, rr.Success)
|
assert.Check(t, rr.Success)
|
||||||
assert.Assert(t, len(rr.Patches) == 1)
|
assert.Assert(t, len(rr.Patches) == 1)
|
||||||
assertEqStringAndData(t, `{"path":"/metadata/labels/label2","op":"add","value":"label2Value"}`, rr.Patches[0])
|
assertEqStringAndData(t, `{"path":"/metadata/labels/label2","op":"add","value":"label2Value"}`, rr.Patches[0])
|
||||||
|
|
|
@ -5,13 +5,12 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
"github.com/golang/glog"
|
||||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||||
"github.com/nirmata/kyverno/pkg/engine/mutate"
|
"github.com/nirmata/kyverno/pkg/engine/mutate"
|
||||||
"github.com/nirmata/kyverno/pkg/engine/response"
|
"github.com/nirmata/kyverno/pkg/engine/response"
|
||||||
"github.com/nirmata/kyverno/pkg/engine/variables"
|
"github.com/nirmata/kyverno/pkg/engine/variables"
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -29,25 +28,26 @@ func Mutate(policyContext PolicyContext) (resp response.EngineResponse) {
|
||||||
policy := policyContext.Policy
|
policy := policyContext.Policy
|
||||||
resource := policyContext.NewResource
|
resource := policyContext.NewResource
|
||||||
ctx := policyContext.Context
|
ctx := policyContext.Context
|
||||||
logger := log.Log.WithName("Mutate").WithValues("policy", policy.Name, "kind", resource.GetKind(), "namespace", resource.GetNamespace(), "name", resource.GetName())
|
|
||||||
logger.V(4).Info("start processing", "startTime", startTime)
|
|
||||||
startMutateResultResponse(&resp, policy, resource)
|
startMutateResultResponse(&resp, policy, resource)
|
||||||
defer endMutateResultResponse(logger, &resp, startTime)
|
glog.V(4).Infof("started applying mutation rules of policy %q (%v)", policy.Name, startTime)
|
||||||
|
defer endMutateResultResponse(&resp, startTime)
|
||||||
|
|
||||||
patchedResource := policyContext.NewResource
|
patchedResource := policyContext.NewResource
|
||||||
for _, rule := range policy.Spec.Rules {
|
for _, rule := range policy.Spec.Rules {
|
||||||
var ruleResponse response.RuleResponse
|
var ruleResponse response.RuleResponse
|
||||||
logger := logger.WithValues("rule", rule.Name)
|
|
||||||
//TODO: to be checked before calling the resources as well
|
//TODO: to be checked before calling the resources as well
|
||||||
if !rule.HasMutate() && !strings.Contains(PodControllers, resource.GetKind()) {
|
if !rule.HasMutate() && !strings.Contains(PodControllers, resource.GetKind()) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
startTime := time.Now()
|
||||||
|
glog.V(4).Infof("Time: Mutate matchAdmissionInfo %v", time.Since(startTime))
|
||||||
|
|
||||||
// check if the resource satisfies the filter conditions defined in the rule
|
// check if the resource satisfies the filter conditions defined in the rule
|
||||||
//TODO: this needs to be extracted, to filter the resource so that we can avoid passing resources that
|
//TODO: this needs to be extracted, to filter the resource so that we can avoid passing resources that
|
||||||
// dont statisfy a policy rule resource description
|
// dont statisfy a policy rule resource description
|
||||||
if err := MatchesResourceDescription(resource, rule, policyContext.AdmissionInfo); err != nil {
|
if err := MatchesResourceDescription(resource, rule, policyContext.AdmissionInfo); err != nil {
|
||||||
logger.V(4).Info("resource fails the match description")
|
glog.V(4).Infof("resource %s/%s does not satisfy the resource description for the rule:\n%s", resource.GetNamespace(), resource.GetName(), err.Error())
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,8 +55,8 @@ func Mutate(policyContext PolicyContext) (resp response.EngineResponse) {
|
||||||
copyConditions := copyConditions(rule.Conditions)
|
copyConditions := copyConditions(rule.Conditions)
|
||||||
// evaluate pre-conditions
|
// evaluate pre-conditions
|
||||||
// - handle variable subsitutions
|
// - handle variable subsitutions
|
||||||
if !variables.EvaluateConditions(logger, ctx, copyConditions) {
|
if !variables.EvaluateConditions(ctx, copyConditions) {
|
||||||
logger.V(4).Info("resource fails the preconditions")
|
glog.V(4).Infof("resource %s/%s does not satisfy the conditions for the rule ", resource.GetNamespace(), resource.GetName())
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ func Mutate(policyContext PolicyContext) (resp response.EngineResponse) {
|
||||||
overlay := mutation.Overlay
|
overlay := mutation.Overlay
|
||||||
// subsiitue the variables
|
// subsiitue the variables
|
||||||
var err error
|
var err error
|
||||||
if overlay, err = variables.SubstituteVars(logger, ctx, overlay); err != nil {
|
if overlay, err = variables.SubstituteVars(ctx, overlay); err != nil {
|
||||||
// variable subsitution failed
|
// variable subsitution failed
|
||||||
ruleResponse.Success = false
|
ruleResponse.Success = false
|
||||||
ruleResponse.Message = err.Error()
|
ruleResponse.Message = err.Error()
|
||||||
|
@ -74,13 +74,15 @@ func Mutate(policyContext PolicyContext) (resp response.EngineResponse) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
ruleResponse, patchedResource = mutate.ProcessOverlay(logger, rule.Name, overlay, patchedResource)
|
ruleResponse, patchedResource = mutate.ProcessOverlay(rule.Name, overlay, patchedResource)
|
||||||
if ruleResponse.Success {
|
if ruleResponse.Success {
|
||||||
// - overlay pattern does not match the resource conditions
|
// - overlay pattern does not match the resource conditions
|
||||||
if ruleResponse.Patches == nil {
|
if ruleResponse.Patches == nil {
|
||||||
|
glog.V(4).Infof(ruleResponse.Message)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
logger.V(4).Info("overlay applied succesfully")
|
|
||||||
|
glog.V(4).Infof("Mutate overlay in rule '%s' successfully applied on %s/%s/%s", rule.Name, resource.GetKind(), resource.GetNamespace(), resource.GetName())
|
||||||
}
|
}
|
||||||
|
|
||||||
resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, ruleResponse)
|
resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, ruleResponse)
|
||||||
|
@ -90,8 +92,8 @@ func Mutate(policyContext PolicyContext) (resp response.EngineResponse) {
|
||||||
// Process Patches
|
// Process Patches
|
||||||
if rule.Mutation.Patches != nil {
|
if rule.Mutation.Patches != nil {
|
||||||
var ruleResponse response.RuleResponse
|
var ruleResponse response.RuleResponse
|
||||||
ruleResponse, patchedResource = mutate.ProcessPatches(logger, rule, patchedResource)
|
ruleResponse, patchedResource = mutate.ProcessPatches(rule, patchedResource)
|
||||||
logger.V(4).Info("patches applied successfully")
|
glog.Infof("Mutate patches in rule '%s' successfully applied on %s/%s/%s", rule.Name, resource.GetKind(), resource.GetNamespace(), resource.GetName())
|
||||||
resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, ruleResponse)
|
resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, ruleResponse)
|
||||||
incrementAppliedRuleCount(&resp)
|
incrementAppliedRuleCount(&resp)
|
||||||
}
|
}
|
||||||
|
@ -104,14 +106,14 @@ func Mutate(policyContext PolicyContext) (resp response.EngineResponse) {
|
||||||
|
|
||||||
if strings.Contains(PodControllers, resource.GetKind()) {
|
if strings.Contains(PodControllers, resource.GetKind()) {
|
||||||
var ruleResponse response.RuleResponse
|
var ruleResponse response.RuleResponse
|
||||||
ruleResponse, patchedResource = mutate.ProcessOverlay(logger, rule.Name, podTemplateRule, patchedResource)
|
ruleResponse, patchedResource = mutate.ProcessOverlay(rule.Name, podTemplateRule, patchedResource)
|
||||||
if !ruleResponse.Success {
|
if !ruleResponse.Success {
|
||||||
logger.Info("failed to insert annotation for podTemplate", "error", ruleResponse.Message)
|
glog.Errorf("Failed to insert annotation to podTemplate of %s/%s/%s: %s", resource.GetKind(), resource.GetNamespace(), resource.GetName(), ruleResponse.Message)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if ruleResponse.Success && ruleResponse.Patches != nil {
|
if ruleResponse.Success && ruleResponse.Patches != nil {
|
||||||
logger.V(2).Info("inserted annotation for podTemplate")
|
glog.V(2).Infof("Inserted annotation to podTemplate of %s/%s/%s: %s", resource.GetKind(), resource.GetNamespace(), resource.GetName(), ruleResponse.Message)
|
||||||
resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, ruleResponse)
|
resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, ruleResponse)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -135,9 +137,10 @@ func startMutateResultResponse(resp *response.EngineResponse, policy kyverno.Clu
|
||||||
// TODO(shuting): set response with mutationFailureAction
|
// TODO(shuting): set response with mutationFailureAction
|
||||||
}
|
}
|
||||||
|
|
||||||
func endMutateResultResponse(logger logr.Logger, resp *response.EngineResponse, startTime time.Time) {
|
func endMutateResultResponse(resp *response.EngineResponse, startTime time.Time) {
|
||||||
resp.PolicyResponse.ProcessingTime = time.Since(startTime)
|
resp.PolicyResponse.ProcessingTime = time.Since(startTime)
|
||||||
logger.V(4).Info("finshed processing", "processingTime", resp.PolicyResponse.ProcessingTime, "mutationRulesApplied", resp.PolicyResponse.RulesAppliedCount)
|
glog.V(4).Infof("finished applying mutation rules policy %v (%v)", resp.PolicyResponse.Policy, resp.PolicyResponse.ProcessingTime)
|
||||||
|
glog.V(4).Infof("Mutation Rules appplied count %v for policy %q", resp.PolicyResponse.RulesAppliedCount, resp.PolicyResponse.Policy)
|
||||||
}
|
}
|
||||||
|
|
||||||
// podTemplateRule mutate pod template with annotation
|
// podTemplateRule mutate pod template with annotation
|
||||||
|
|
|
@ -67,17 +67,11 @@ func Test_VariableSubstitutionOverlay(t *testing.T) {
|
||||||
expectedPatch := []byte(`{ "op": "add", "path": "/metadata/labels", "value":{"appname":"check-root-user"} }`)
|
expectedPatch := []byte(`{ "op": "add", "path": "/metadata/labels", "value":{"appname":"check-root-user"} }`)
|
||||||
|
|
||||||
var policy kyverno.ClusterPolicy
|
var policy kyverno.ClusterPolicy
|
||||||
err := json.Unmarshal(rawPolicy, &policy)
|
json.Unmarshal(rawPolicy, &policy)
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
ctx := context.NewContext()
|
ctx := context.NewContext()
|
||||||
err = ctx.AddResource(rawResource)
|
ctx.AddResource(rawResource)
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
value, err := ctx.Query("request.object.metadata.name")
|
value, err := ctx.Query("request.object.metadata.name")
|
||||||
t.Log(value)
|
t.Log(value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -145,14 +139,12 @@ func Test_variableSubstitutionPathNotExist(t *testing.T) {
|
||||||
}`)
|
}`)
|
||||||
|
|
||||||
var policy kyverno.ClusterPolicy
|
var policy kyverno.ClusterPolicy
|
||||||
err := json.Unmarshal(policyraw, &policy)
|
json.Unmarshal(policyraw, &policy)
|
||||||
assert.NilError(t, err)
|
|
||||||
resourceUnstructured, err := utils.ConvertToUnstructured(resourceRaw)
|
resourceUnstructured, err := utils.ConvertToUnstructured(resourceRaw)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
ctx := context.NewContext()
|
ctx := context.NewContext()
|
||||||
err = ctx.AddResource(resourceRaw)
|
ctx.AddResource(resourceRaw)
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
policyContext := PolicyContext{
|
policyContext := PolicyContext{
|
||||||
Policy: policy,
|
Policy: policy,
|
||||||
|
|
|
@ -9,7 +9,8 @@ import (
|
||||||
"github.com/nirmata/kyverno/pkg/utils"
|
"github.com/nirmata/kyverno/pkg/utils"
|
||||||
authenticationv1 "k8s.io/api/authentication/v1"
|
authenticationv1 "k8s.io/api/authentication/v1"
|
||||||
rbacv1 "k8s.io/api/rbac/v1"
|
rbacv1 "k8s.io/api/rbac/v1"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
|
||||||
|
"github.com/golang/glog"
|
||||||
|
|
||||||
"github.com/minio/minio/pkg/wildcard"
|
"github.com/minio/minio/pkg/wildcard"
|
||||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||||
|
@ -52,7 +53,7 @@ func checkNameSpace(namespaces []string, resourceNameSpace string) bool {
|
||||||
func checkSelector(labelSelector *metav1.LabelSelector, resourceLabels map[string]string) (bool, error) {
|
func checkSelector(labelSelector *metav1.LabelSelector, resourceLabels map[string]string) (bool, error) {
|
||||||
selector, err := metav1.LabelSelectorAsSelector(labelSelector)
|
selector, err := metav1.LabelSelectorAsSelector(labelSelector)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Log.Error(err, "failed to build label selector")
|
glog.Error(err)
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
package validate
|
package validate
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"math"
|
"math"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
"github.com/golang/glog"
|
||||||
"github.com/minio/minio/pkg/wildcard"
|
"github.com/minio/minio/pkg/wildcard"
|
||||||
"github.com/nirmata/kyverno/pkg/engine/operator"
|
"github.com/nirmata/kyverno/pkg/engine/operator"
|
||||||
apiresource "k8s.io/apimachinery/pkg/api/resource"
|
apiresource "k8s.io/apimachinery/pkg/api/resource"
|
||||||
|
@ -22,52 +21,52 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
// ValidateValueWithPattern validates value with operators and wildcards
|
// ValidateValueWithPattern validates value with operators and wildcards
|
||||||
func ValidateValueWithPattern(log logr.Logger, value, pattern interface{}) bool {
|
func ValidateValueWithPattern(value, pattern interface{}) bool {
|
||||||
switch typedPattern := pattern.(type) {
|
switch typedPattern := pattern.(type) {
|
||||||
case bool:
|
case bool:
|
||||||
typedValue, ok := value.(bool)
|
typedValue, ok := value.(bool)
|
||||||
if !ok {
|
if !ok {
|
||||||
log.V(4).Info("Expected type bool", "type", fmt.Sprintf("%T", value), "value", value)
|
glog.V(4).Infof("Expected bool, found %T", value)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return typedPattern == typedValue
|
return typedPattern == typedValue
|
||||||
case int:
|
case int:
|
||||||
return validateValueWithIntPattern(log, value, int64(typedPattern))
|
return validateValueWithIntPattern(value, int64(typedPattern))
|
||||||
case int64:
|
case int64:
|
||||||
return validateValueWithIntPattern(log, value, typedPattern)
|
return validateValueWithIntPattern(value, typedPattern)
|
||||||
case float64:
|
case float64:
|
||||||
return validateValueWithFloatPattern(log, value, typedPattern)
|
return validateValueWithFloatPattern(value, typedPattern)
|
||||||
case string:
|
case string:
|
||||||
return validateValueWithStringPatterns(log, value, typedPattern)
|
return validateValueWithStringPatterns(value, typedPattern)
|
||||||
case nil:
|
case nil:
|
||||||
return validateValueWithNilPattern(log, value)
|
return validateValueWithNilPattern(value)
|
||||||
case map[string]interface{}:
|
case map[string]interface{}:
|
||||||
// TODO: check if this is ever called?
|
// TODO: check if this is ever called?
|
||||||
return validateValueWithMapPattern(log, value, typedPattern)
|
return validateValueWithMapPattern(value, typedPattern)
|
||||||
case []interface{}:
|
case []interface{}:
|
||||||
// TODO: check if this is ever called?
|
// TODO: check if this is ever called?
|
||||||
log.Info("arrays as patterns is not supported")
|
glog.Warning("Arrays as patterns are not supported")
|
||||||
return false
|
return false
|
||||||
default:
|
default:
|
||||||
log.Info("Unkown type", "type", fmt.Sprintf("%T", typedPattern), "value", typedPattern)
|
glog.Warningf("Unknown type as pattern: %v", typedPattern)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateValueWithMapPattern(log logr.Logger, value interface{}, typedPattern map[string]interface{}) bool {
|
func validateValueWithMapPattern(value interface{}, typedPattern map[string]interface{}) bool {
|
||||||
// verify the type of the resource value is map[string]interface,
|
// verify the type of the resource value is map[string]interface,
|
||||||
// we only check for existence of object, not the equality of content and value
|
// we only check for existence of object, not the equality of content and value
|
||||||
//TODO: check if adding
|
//TODO: check if adding
|
||||||
_, ok := value.(map[string]interface{})
|
_, ok := value.(map[string]interface{})
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Info("Expected type map[string]interface{}", "type", fmt.Sprintf("%T", value), "value", value)
|
glog.Warningf("Expected map[string]interface{}, found %T\n", value)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handler for int values during validation process
|
// Handler for int values during validation process
|
||||||
func validateValueWithIntPattern(log logr.Logger, value interface{}, pattern int64) bool {
|
func validateValueWithIntPattern(value interface{}, pattern int64) bool {
|
||||||
switch typedValue := value.(type) {
|
switch typedValue := value.(type) {
|
||||||
case int:
|
case int:
|
||||||
return int64(typedValue) == pattern
|
return int64(typedValue) == pattern
|
||||||
|
@ -79,38 +78,38 @@ func validateValueWithIntPattern(log logr.Logger, value interface{}, pattern int
|
||||||
return int64(typedValue) == pattern
|
return int64(typedValue) == pattern
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info("Expected type int", "type", fmt.Sprintf("%T", typedValue), "value", typedValue)
|
glog.Warningf("Expected int, found float: %f\n", typedValue)
|
||||||
return false
|
return false
|
||||||
case string:
|
case string:
|
||||||
// extract int64 from string
|
// extract int64 from string
|
||||||
int64Num, err := strconv.ParseInt(typedValue, 10, 64)
|
int64Num, err := strconv.ParseInt(typedValue, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err, "Failed to parse int64 from string")
|
glog.Warningf("Failed to parse int64 from string: %v", err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return int64Num == pattern
|
return int64Num == pattern
|
||||||
default:
|
default:
|
||||||
log.Info("Expected type int", "type", fmt.Sprintf("%T", value), "value", value)
|
glog.Warningf("Expected int, found: %T\n", value)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handler for float values during validation process
|
// Handler for float values during validation process
|
||||||
func validateValueWithFloatPattern(log logr.Logger, value interface{}, pattern float64) bool {
|
func validateValueWithFloatPattern(value interface{}, pattern float64) bool {
|
||||||
switch typedValue := value.(type) {
|
switch typedValue := value.(type) {
|
||||||
case int:
|
case int:
|
||||||
// check that float has no fraction
|
// check that float has no fraction
|
||||||
if pattern == math.Trunc(pattern) {
|
if pattern == math.Trunc(pattern) {
|
||||||
return int(pattern) == value
|
return int(pattern) == value
|
||||||
}
|
}
|
||||||
log.Info("Expected type float", "type", fmt.Sprintf("%T", typedValue), "value", typedValue)
|
glog.Warningf("Expected float, found int: %d\n", typedValue)
|
||||||
return false
|
return false
|
||||||
case int64:
|
case int64:
|
||||||
// check that float has no fraction
|
// check that float has no fraction
|
||||||
if pattern == math.Trunc(pattern) {
|
if pattern == math.Trunc(pattern) {
|
||||||
return int64(pattern) == value
|
return int64(pattern) == value
|
||||||
}
|
}
|
||||||
log.Info("Expected type float", "type", fmt.Sprintf("%T", typedValue), "value", typedValue)
|
glog.Warningf("Expected float, found int: %d\n", typedValue)
|
||||||
return false
|
return false
|
||||||
case float64:
|
case float64:
|
||||||
return typedValue == pattern
|
return typedValue == pattern
|
||||||
|
@ -118,18 +117,18 @@ func validateValueWithFloatPattern(log logr.Logger, value interface{}, pattern f
|
||||||
// extract float64 from string
|
// extract float64 from string
|
||||||
float64Num, err := strconv.ParseFloat(typedValue, 64)
|
float64Num, err := strconv.ParseFloat(typedValue, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err, "Failed to parse float64 from string")
|
glog.Warningf("Failed to parse float64 from string: %v", err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return float64Num == pattern
|
return float64Num == pattern
|
||||||
default:
|
default:
|
||||||
log.Info("Expected type float", "type", fmt.Sprintf("%T", value), "value", value)
|
glog.Warningf("Expected float, found: %T\n", value)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handler for nil values during validation process
|
// Handler for nil values during validation process
|
||||||
func validateValueWithNilPattern(log logr.Logger, value interface{}) bool {
|
func validateValueWithNilPattern(value interface{}) bool {
|
||||||
switch typed := value.(type) {
|
switch typed := value.(type) {
|
||||||
case float64:
|
case float64:
|
||||||
return typed == 0.0
|
return typed == 0.0
|
||||||
|
@ -144,20 +143,20 @@ func validateValueWithNilPattern(log logr.Logger, value interface{}) bool {
|
||||||
case nil:
|
case nil:
|
||||||
return true
|
return true
|
||||||
case map[string]interface{}, []interface{}:
|
case map[string]interface{}, []interface{}:
|
||||||
log.Info("Maps and arrays could not be checked with nil pattern")
|
glog.Warningf("Maps and arrays could not be checked with nil pattern")
|
||||||
return false
|
return false
|
||||||
default:
|
default:
|
||||||
log.Info("Unknown type as value when checking for nil pattern", "type", fmt.Sprintf("%T", value), "value", value)
|
glog.Warningf("Unknown type as value when checking for nil pattern: %T\n", value)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handler for pattern values during validation process
|
// Handler for pattern values during validation process
|
||||||
func validateValueWithStringPatterns(log logr.Logger, value interface{}, pattern string) bool {
|
func validateValueWithStringPatterns(value interface{}, pattern string) bool {
|
||||||
statements := strings.Split(pattern, "|")
|
statements := strings.Split(pattern, "|")
|
||||||
for _, statement := range statements {
|
for _, statement := range statements {
|
||||||
statement = strings.Trim(statement, " ")
|
statement = strings.Trim(statement, " ")
|
||||||
if validateValueWithStringPattern(log, value, statement) {
|
if validateValueWithStringPattern(value, statement) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -167,24 +166,24 @@ func validateValueWithStringPatterns(log logr.Logger, value interface{}, pattern
|
||||||
|
|
||||||
// Handler for single pattern value during validation process
|
// Handler for single pattern value during validation process
|
||||||
// Detects if pattern has a number
|
// Detects if pattern has a number
|
||||||
func validateValueWithStringPattern(log logr.Logger, value interface{}, pattern string) bool {
|
func validateValueWithStringPattern(value interface{}, pattern string) bool {
|
||||||
operator := operator.GetOperatorFromStringPattern(pattern)
|
operator := operator.GetOperatorFromStringPattern(pattern)
|
||||||
pattern = pattern[len(operator):]
|
pattern = pattern[len(operator):]
|
||||||
number, str := getNumberAndStringPartsFromPattern(pattern)
|
number, str := getNumberAndStringPartsFromPattern(pattern)
|
||||||
|
|
||||||
if "" == number {
|
if "" == number {
|
||||||
return validateString(log, value, str, operator)
|
return validateString(value, str, operator)
|
||||||
}
|
}
|
||||||
|
|
||||||
return validateNumberWithStr(log, value, pattern, operator)
|
return validateNumberWithStr(value, pattern, operator)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handler for string values
|
// Handler for string values
|
||||||
func validateString(log logr.Logger, value interface{}, pattern string, operatorVariable operator.Operator) bool {
|
func validateString(value interface{}, pattern string, operatorVariable operator.Operator) bool {
|
||||||
if operator.NotEqual == operatorVariable || operator.Equal == operatorVariable {
|
if operator.NotEqual == operatorVariable || operator.Equal == operatorVariable {
|
||||||
strValue, ok := value.(string)
|
strValue, ok := value.(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Info("Expected type string", "type", fmt.Sprintf("%T", value), "value", value)
|
glog.Warningf("Expected string, found %T\n", value)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,16 +195,17 @@ func validateString(log logr.Logger, value interface{}, pattern string, operator
|
||||||
|
|
||||||
return wildcardResult
|
return wildcardResult
|
||||||
}
|
}
|
||||||
log.Info("Operators >, >=, <, <= are not applicable to strings")
|
|
||||||
|
glog.Warningf("Operators >, >=, <, <= are not applicable to strings")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// validateNumberWithStr compares quantity if pattern type is quantity
|
// validateNumberWithStr compares quantity if pattern type is quantity
|
||||||
// or a wildcard match to pattern string
|
// or a wildcard match to pattern string
|
||||||
func validateNumberWithStr(log logr.Logger, value interface{}, pattern string, operator operator.Operator) bool {
|
func validateNumberWithStr(value interface{}, pattern string, operator operator.Operator) bool {
|
||||||
typedValue, err := convertToString(value)
|
typedValue, err := convertToString(value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err, "failed to convert to string")
|
glog.Warning(err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -214,7 +214,7 @@ func validateNumberWithStr(log logr.Logger, value interface{}, pattern string, o
|
||||||
if err == nil {
|
if err == nil {
|
||||||
valueQuan, err := apiresource.ParseQuantity(typedValue)
|
valueQuan, err := apiresource.ParseQuantity(typedValue)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err, "invalid quantity in resource", "type", fmt.Sprintf("%T", typedValue), "value", typedValue)
|
glog.Warningf("Invalid quantity in resource %s, err: %v\n", typedValue, err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,7 +223,7 @@ func validateNumberWithStr(log logr.Logger, value interface{}, pattern string, o
|
||||||
|
|
||||||
// 2. wildcard match
|
// 2. wildcard match
|
||||||
if !wildcard.Match(pattern, typedValue) {
|
if !wildcard.Match(pattern, typedValue) {
|
||||||
log.Info("value failed wildcard check", "type", fmt.Sprintf("%T", typedValue), "value", typedValue, "check", pattern)
|
glog.Warningf("Value '%s' has not passed wildcard check: %s", typedValue, pattern)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
|
|
@ -6,14 +6,13 @@ import (
|
||||||
|
|
||||||
"github.com/nirmata/kyverno/pkg/engine/operator"
|
"github.com/nirmata/kyverno/pkg/engine/operator"
|
||||||
"gotest.tools/assert"
|
"gotest.tools/assert"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestValidateValueWithPattern_Bool(t *testing.T) {
|
func TestValidateValueWithPattern_Bool(t *testing.T) {
|
||||||
assert.Assert(t, ValidateValueWithPattern(log.Log, true, true))
|
assert.Assert(t, ValidateValueWithPattern(true, true))
|
||||||
assert.Assert(t, !ValidateValueWithPattern(log.Log, true, false))
|
assert.Assert(t, !ValidateValueWithPattern(true, false))
|
||||||
assert.Assert(t, !ValidateValueWithPattern(log.Log, false, true))
|
assert.Assert(t, !ValidateValueWithPattern(false, true))
|
||||||
assert.Assert(t, ValidateValueWithPattern(log.Log, false, false))
|
assert.Assert(t, ValidateValueWithPattern(false, false))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateString_AsteriskTest(t *testing.T) {
|
func TestValidateString_AsteriskTest(t *testing.T) {
|
||||||
|
@ -21,8 +20,8 @@ func TestValidateString_AsteriskTest(t *testing.T) {
|
||||||
value := "anything"
|
value := "anything"
|
||||||
empty := ""
|
empty := ""
|
||||||
|
|
||||||
assert.Assert(t, validateString(log.Log, value, pattern, operator.Equal))
|
assert.Assert(t, validateString(value, pattern, operator.Equal))
|
||||||
assert.Assert(t, validateString(log.Log, empty, pattern, operator.Equal))
|
assert.Assert(t, validateString(empty, pattern, operator.Equal))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateString_LeftAsteriskTest(t *testing.T) {
|
func TestValidateString_LeftAsteriskTest(t *testing.T) {
|
||||||
|
@ -30,32 +29,32 @@ func TestValidateString_LeftAsteriskTest(t *testing.T) {
|
||||||
value := "leftright"
|
value := "leftright"
|
||||||
right := "right"
|
right := "right"
|
||||||
|
|
||||||
assert.Assert(t, validateString(log.Log, value, pattern, operator.Equal))
|
assert.Assert(t, validateString(value, pattern, operator.Equal))
|
||||||
assert.Assert(t, validateString(log.Log, right, pattern, operator.Equal))
|
assert.Assert(t, validateString(right, pattern, operator.Equal))
|
||||||
|
|
||||||
value = "leftmiddle"
|
value = "leftmiddle"
|
||||||
middle := "middle"
|
middle := "middle"
|
||||||
|
|
||||||
assert.Assert(t, !validateString(log.Log, value, pattern, operator.Equal))
|
assert.Assert(t, !validateString(value, pattern, operator.Equal))
|
||||||
assert.Assert(t, !validateString(log.Log, middle, pattern, operator.Equal))
|
assert.Assert(t, !validateString(middle, pattern, operator.Equal))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateString_MiddleAsteriskTest(t *testing.T) {
|
func TestValidateString_MiddleAsteriskTest(t *testing.T) {
|
||||||
pattern := "ab*ba"
|
pattern := "ab*ba"
|
||||||
value := "abbeba"
|
value := "abbeba"
|
||||||
assert.Assert(t, validateString(log.Log, value, pattern, operator.Equal))
|
assert.Assert(t, validateString(value, pattern, operator.Equal))
|
||||||
|
|
||||||
value = "abbca"
|
value = "abbca"
|
||||||
assert.Assert(t, !validateString(log.Log, value, pattern, operator.Equal))
|
assert.Assert(t, !validateString(value, pattern, operator.Equal))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateString_QuestionMark(t *testing.T) {
|
func TestValidateString_QuestionMark(t *testing.T) {
|
||||||
pattern := "ab?ba"
|
pattern := "ab?ba"
|
||||||
value := "abbba"
|
value := "abbba"
|
||||||
assert.Assert(t, validateString(log.Log, value, pattern, operator.Equal))
|
assert.Assert(t, validateString(value, pattern, operator.Equal))
|
||||||
|
|
||||||
value = "abbbba"
|
value = "abbbba"
|
||||||
assert.Assert(t, !validateString(log.Log, value, pattern, operator.Equal))
|
assert.Assert(t, !validateString(value, pattern, operator.Equal))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateValueWithPattern_BoolInJson(t *testing.T) {
|
func TestValidateValueWithPattern_BoolInJson(t *testing.T) {
|
||||||
|
@ -77,7 +76,7 @@ func TestValidateValueWithPattern_BoolInJson(t *testing.T) {
|
||||||
err = json.Unmarshal(rawValue, &value)
|
err = json.Unmarshal(rawValue, &value)
|
||||||
assert.Assert(t, err)
|
assert.Assert(t, err)
|
||||||
|
|
||||||
assert.Assert(t, ValidateValueWithPattern(log.Log, value["key"], pattern["key"]))
|
assert.Assert(t, ValidateValueWithPattern(value["key"], pattern["key"]))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateValueWithPattern_NullPatternStringValue(t *testing.T) {
|
func TestValidateValueWithPattern_NullPatternStringValue(t *testing.T) {
|
||||||
|
@ -99,7 +98,7 @@ func TestValidateValueWithPattern_NullPatternStringValue(t *testing.T) {
|
||||||
err = json.Unmarshal(rawValue, &value)
|
err = json.Unmarshal(rawValue, &value)
|
||||||
assert.Assert(t, err)
|
assert.Assert(t, err)
|
||||||
|
|
||||||
assert.Assert(t, !ValidateValueWithPattern(log.Log, value["key"], pattern["key"]))
|
assert.Assert(t, !ValidateValueWithPattern(value["key"], pattern["key"]))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateValueWithPattern_NullPatternDefaultString(t *testing.T) {
|
func TestValidateValueWithPattern_NullPatternDefaultString(t *testing.T) {
|
||||||
|
@ -121,7 +120,7 @@ func TestValidateValueWithPattern_NullPatternDefaultString(t *testing.T) {
|
||||||
err = json.Unmarshal(rawValue, &value)
|
err = json.Unmarshal(rawValue, &value)
|
||||||
assert.Assert(t, err)
|
assert.Assert(t, err)
|
||||||
|
|
||||||
assert.Assert(t, ValidateValueWithPattern(log.Log, value["key"], pattern["key"]))
|
assert.Assert(t, ValidateValueWithPattern(value["key"], pattern["key"]))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateValueWithPattern_NullPatternDefaultFloat(t *testing.T) {
|
func TestValidateValueWithPattern_NullPatternDefaultFloat(t *testing.T) {
|
||||||
|
@ -143,7 +142,7 @@ func TestValidateValueWithPattern_NullPatternDefaultFloat(t *testing.T) {
|
||||||
err = json.Unmarshal(rawValue, &value)
|
err = json.Unmarshal(rawValue, &value)
|
||||||
assert.Assert(t, err)
|
assert.Assert(t, err)
|
||||||
|
|
||||||
assert.Assert(t, ValidateValueWithPattern(log.Log, value["key"], pattern["key"]))
|
assert.Assert(t, ValidateValueWithPattern(value["key"], pattern["key"]))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateValueWithPattern_NullPatternDefaultInt(t *testing.T) {
|
func TestValidateValueWithPattern_NullPatternDefaultInt(t *testing.T) {
|
||||||
|
@ -165,7 +164,7 @@ func TestValidateValueWithPattern_NullPatternDefaultInt(t *testing.T) {
|
||||||
err = json.Unmarshal(rawValue, &value)
|
err = json.Unmarshal(rawValue, &value)
|
||||||
assert.Assert(t, err)
|
assert.Assert(t, err)
|
||||||
|
|
||||||
assert.Assert(t, ValidateValueWithPattern(log.Log, value["key"], pattern["key"]))
|
assert.Assert(t, ValidateValueWithPattern(value["key"], pattern["key"]))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateValueWithPattern_NullPatternDefaultBool(t *testing.T) {
|
func TestValidateValueWithPattern_NullPatternDefaultBool(t *testing.T) {
|
||||||
|
@ -187,77 +186,77 @@ func TestValidateValueWithPattern_NullPatternDefaultBool(t *testing.T) {
|
||||||
err = json.Unmarshal(rawValue, &value)
|
err = json.Unmarshal(rawValue, &value)
|
||||||
assert.Assert(t, err)
|
assert.Assert(t, err)
|
||||||
|
|
||||||
assert.Assert(t, ValidateValueWithPattern(log.Log, value["key"], pattern["key"]))
|
assert.Assert(t, ValidateValueWithPattern(value["key"], pattern["key"]))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateValueWithPattern_StringsLogicalOr(t *testing.T) {
|
func TestValidateValueWithPattern_StringsLogicalOr(t *testing.T) {
|
||||||
pattern := "192.168.88.1 | 10.100.11.*"
|
pattern := "192.168.88.1 | 10.100.11.*"
|
||||||
value := "10.100.11.54"
|
value := "10.100.11.54"
|
||||||
assert.Assert(t, ValidateValueWithPattern(log.Log, value, pattern))
|
assert.Assert(t, ValidateValueWithPattern(value, pattern))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateValueWithPattern_EqualTwoFloats(t *testing.T) {
|
func TestValidateValueWithPattern_EqualTwoFloats(t *testing.T) {
|
||||||
assert.Assert(t, ValidateValueWithPattern(log.Log, 7.0, 7.000))
|
assert.Assert(t, ValidateValueWithPattern(7.0, 7.000))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateValueWithNilPattern_NullPatternStringValue(t *testing.T) {
|
func TestValidateValueWithNilPattern_NullPatternStringValue(t *testing.T) {
|
||||||
assert.Assert(t, !validateValueWithNilPattern(log.Log, "value"))
|
assert.Assert(t, !validateValueWithNilPattern("value"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateValueWithNilPattern_NullPatternDefaultString(t *testing.T) {
|
func TestValidateValueWithNilPattern_NullPatternDefaultString(t *testing.T) {
|
||||||
assert.Assert(t, validateValueWithNilPattern(log.Log, ""))
|
assert.Assert(t, validateValueWithNilPattern(""))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateValueWithNilPattern_NullPatternDefaultFloat(t *testing.T) {
|
func TestValidateValueWithNilPattern_NullPatternDefaultFloat(t *testing.T) {
|
||||||
assert.Assert(t, validateValueWithNilPattern(log.Log, 0.0))
|
assert.Assert(t, validateValueWithNilPattern(0.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateValueWithNilPattern_NullPatternFloat(t *testing.T) {
|
func TestValidateValueWithNilPattern_NullPatternFloat(t *testing.T) {
|
||||||
assert.Assert(t, !validateValueWithNilPattern(log.Log, 0.1))
|
assert.Assert(t, !validateValueWithNilPattern(0.1))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateValueWithNilPattern_NullPatternDefaultInt(t *testing.T) {
|
func TestValidateValueWithNilPattern_NullPatternDefaultInt(t *testing.T) {
|
||||||
assert.Assert(t, validateValueWithNilPattern(log.Log, 0))
|
assert.Assert(t, validateValueWithNilPattern(0))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateValueWithNilPattern_NullPatternInt(t *testing.T) {
|
func TestValidateValueWithNilPattern_NullPatternInt(t *testing.T) {
|
||||||
assert.Assert(t, !validateValueWithNilPattern(log.Log, 1))
|
assert.Assert(t, !validateValueWithNilPattern(1))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateValueWithNilPattern_NullPatternDefaultBool(t *testing.T) {
|
func TestValidateValueWithNilPattern_NullPatternDefaultBool(t *testing.T) {
|
||||||
assert.Assert(t, validateValueWithNilPattern(log.Log, false))
|
assert.Assert(t, validateValueWithNilPattern(false))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateValueWithNilPattern_NullPatternTrueBool(t *testing.T) {
|
func TestValidateValueWithNilPattern_NullPatternTrueBool(t *testing.T) {
|
||||||
assert.Assert(t, !validateValueWithNilPattern(log.Log, true))
|
assert.Assert(t, !validateValueWithNilPattern(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateValueWithFloatPattern_FloatValue(t *testing.T) {
|
func TestValidateValueWithFloatPattern_FloatValue(t *testing.T) {
|
||||||
assert.Assert(t, validateValueWithFloatPattern(log.Log, 7.9914, 7.9914))
|
assert.Assert(t, validateValueWithFloatPattern(7.9914, 7.9914))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateValueWithFloatPattern_FloatValueNotPass(t *testing.T) {
|
func TestValidateValueWithFloatPattern_FloatValueNotPass(t *testing.T) {
|
||||||
assert.Assert(t, !validateValueWithFloatPattern(log.Log, 7.9914, 7.99141))
|
assert.Assert(t, !validateValueWithFloatPattern(7.9914, 7.99141))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateValueWithFloatPattern_FloatPatternWithoutFractionIntValue(t *testing.T) {
|
func TestValidateValueWithFloatPattern_FloatPatternWithoutFractionIntValue(t *testing.T) {
|
||||||
assert.Assert(t, validateValueWithFloatPattern(log.Log, 7, 7.000000))
|
assert.Assert(t, validateValueWithFloatPattern(7, 7.000000))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateValueWithFloatPattern_FloatPatternWithoutFraction(t *testing.T) {
|
func TestValidateValueWithFloatPattern_FloatPatternWithoutFraction(t *testing.T) {
|
||||||
assert.Assert(t, validateValueWithFloatPattern(log.Log, 7.000000, 7.000000))
|
assert.Assert(t, validateValueWithFloatPattern(7.000000, 7.000000))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateValueWithIntPattern_FloatValueWithoutFraction(t *testing.T) {
|
func TestValidateValueWithIntPattern_FloatValueWithoutFraction(t *testing.T) {
|
||||||
assert.Assert(t, validateValueWithFloatPattern(log.Log, 7.000000, 7))
|
assert.Assert(t, validateValueWithFloatPattern(7.000000, 7))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateValueWithIntPattern_FloatValueWitFraction(t *testing.T) {
|
func TestValidateValueWithIntPattern_FloatValueWitFraction(t *testing.T) {
|
||||||
assert.Assert(t, !validateValueWithFloatPattern(log.Log, 7.000001, 7))
|
assert.Assert(t, !validateValueWithFloatPattern(7.000001, 7))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateValueWithIntPattern_NotPass(t *testing.T) {
|
func TestValidateValueWithIntPattern_NotPass(t *testing.T) {
|
||||||
assert.Assert(t, !validateValueWithFloatPattern(log.Log, 8, 7))
|
assert.Assert(t, !validateValueWithFloatPattern(8, 7))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetNumberAndStringPartsFromPattern_NumberAndString(t *testing.T) {
|
func TestGetNumberAndStringPartsFromPattern_NumberAndString(t *testing.T) {
|
||||||
|
@ -291,35 +290,35 @@ func TestGetNumberAndStringPartsFromPattern_Empty(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateNumberWithStr_LessFloatAndInt(t *testing.T) {
|
func TestValidateNumberWithStr_LessFloatAndInt(t *testing.T) {
|
||||||
assert.Assert(t, validateNumberWithStr(log.Log, 7.00001, "7.000001", operator.More))
|
assert.Assert(t, validateNumberWithStr(7.00001, "7.000001", operator.More))
|
||||||
assert.Assert(t, validateNumberWithStr(log.Log, 7.00001, "7", operator.NotEqual))
|
assert.Assert(t, validateNumberWithStr(7.00001, "7", operator.NotEqual))
|
||||||
|
|
||||||
assert.Assert(t, validateNumberWithStr(log.Log, 7.0000, "7", operator.Equal))
|
assert.Assert(t, validateNumberWithStr(7.0000, "7", operator.Equal))
|
||||||
assert.Assert(t, !validateNumberWithStr(log.Log, 6.000000001, "6", operator.Less))
|
assert.Assert(t, !validateNumberWithStr(6.000000001, "6", operator.Less))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateQuantity_InvalidQuantity(t *testing.T) {
|
func TestValidateQuantity_InvalidQuantity(t *testing.T) {
|
||||||
assert.Assert(t, !validateNumberWithStr(log.Log, "1024Gi", "", operator.Equal))
|
assert.Assert(t, !validateNumberWithStr("1024Gi", "", operator.Equal))
|
||||||
assert.Assert(t, !validateNumberWithStr(log.Log, "gii", "1024Gi", operator.Equal))
|
assert.Assert(t, !validateNumberWithStr("gii", "1024Gi", operator.Equal))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateQuantity_Equal(t *testing.T) {
|
func TestValidateQuantity_Equal(t *testing.T) {
|
||||||
assert.Assert(t, validateNumberWithStr(log.Log, "1024Gi", "1024Gi", operator.Equal))
|
assert.Assert(t, validateNumberWithStr("1024Gi", "1024Gi", operator.Equal))
|
||||||
assert.Assert(t, validateNumberWithStr(log.Log, "1024Mi", "1Gi", operator.Equal))
|
assert.Assert(t, validateNumberWithStr("1024Mi", "1Gi", operator.Equal))
|
||||||
assert.Assert(t, validateNumberWithStr(log.Log, "0.2", "200m", operator.Equal))
|
assert.Assert(t, validateNumberWithStr("0.2", "200m", operator.Equal))
|
||||||
assert.Assert(t, validateNumberWithStr(log.Log, "500", "500", operator.Equal))
|
assert.Assert(t, validateNumberWithStr("500", "500", operator.Equal))
|
||||||
assert.Assert(t, !validateNumberWithStr(log.Log, "2048", "1024", operator.Equal))
|
assert.Assert(t, !validateNumberWithStr("2048", "1024", operator.Equal))
|
||||||
assert.Assert(t, validateNumberWithStr(log.Log, 1024, "1024", operator.Equal))
|
assert.Assert(t, validateNumberWithStr(1024, "1024", operator.Equal))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateQuantity_Operation(t *testing.T) {
|
func TestValidateQuantity_Operation(t *testing.T) {
|
||||||
assert.Assert(t, validateNumberWithStr(log.Log, "1Gi", "1000Mi", operator.More))
|
assert.Assert(t, validateNumberWithStr("1Gi", "1000Mi", operator.More))
|
||||||
assert.Assert(t, validateNumberWithStr(log.Log, "1G", "1Gi", operator.Less))
|
assert.Assert(t, validateNumberWithStr("1G", "1Gi", operator.Less))
|
||||||
assert.Assert(t, validateNumberWithStr(log.Log, "500m", "0.5", operator.MoreEqual))
|
assert.Assert(t, validateNumberWithStr("500m", "0.5", operator.MoreEqual))
|
||||||
assert.Assert(t, validateNumberWithStr(log.Log, "1", "500m", operator.MoreEqual))
|
assert.Assert(t, validateNumberWithStr("1", "500m", operator.MoreEqual))
|
||||||
assert.Assert(t, validateNumberWithStr(log.Log, "0.5", ".5", operator.LessEqual))
|
assert.Assert(t, validateNumberWithStr("0.5", ".5", operator.LessEqual))
|
||||||
assert.Assert(t, validateNumberWithStr(log.Log, "0.2", ".5", operator.LessEqual))
|
assert.Assert(t, validateNumberWithStr("0.2", ".5", operator.LessEqual))
|
||||||
assert.Assert(t, validateNumberWithStr(log.Log, "0.2", ".5", operator.NotEqual))
|
assert.Assert(t, validateNumberWithStr("0.2", ".5", operator.NotEqual))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetOperatorFromStringPattern_OneChar(t *testing.T) {
|
func TestGetOperatorFromStringPattern_OneChar(t *testing.T) {
|
||||||
|
|
|
@ -8,15 +8,15 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
"github.com/golang/glog"
|
||||||
"github.com/nirmata/kyverno/pkg/engine/anchor"
|
"github.com/nirmata/kyverno/pkg/engine/anchor"
|
||||||
"github.com/nirmata/kyverno/pkg/engine/operator"
|
"github.com/nirmata/kyverno/pkg/engine/operator"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ValidateResourceWithPattern is a start of element-by-element validation process
|
// ValidateResourceWithPattern is a start of element-by-element validation process
|
||||||
// It assumes that validation is started from root, so "/" is passed
|
// It assumes that validation is started from root, so "/" is passed
|
||||||
func ValidateResourceWithPattern(log logr.Logger, resource, pattern interface{}) (string, error) {
|
func ValidateResourceWithPattern(resource, pattern interface{}) (string, error) {
|
||||||
path, err := validateResourceElement(log, resource, pattern, pattern, "/")
|
path, err := validateResourceElement(resource, pattern, pattern, "/")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return path, err
|
return path, err
|
||||||
}
|
}
|
||||||
|
@ -27,44 +27,44 @@ func ValidateResourceWithPattern(log logr.Logger, resource, pattern interface{})
|
||||||
// validateResourceElement detects the element type (map, array, nil, string, int, bool, float)
|
// validateResourceElement detects the element type (map, array, nil, string, int, bool, float)
|
||||||
// and calls corresponding handler
|
// and calls corresponding handler
|
||||||
// Pattern tree and resource tree can have different structure. In this case validation fails
|
// Pattern tree and resource tree can have different structure. In this case validation fails
|
||||||
func validateResourceElement(log logr.Logger, resourceElement, patternElement, originPattern interface{}, path string) (string, error) {
|
func validateResourceElement(resourceElement, patternElement, originPattern interface{}, path string) (string, error) {
|
||||||
var err error
|
var err error
|
||||||
switch typedPatternElement := patternElement.(type) {
|
switch typedPatternElement := patternElement.(type) {
|
||||||
// map
|
// map
|
||||||
case map[string]interface{}:
|
case map[string]interface{}:
|
||||||
typedResourceElement, ok := resourceElement.(map[string]interface{})
|
typedResourceElement, ok := resourceElement.(map[string]interface{})
|
||||||
if !ok {
|
if !ok {
|
||||||
log.V(4).Info("Pattern and resource have different structures.", "path", path, "expected", fmt.Sprintf("%T", patternElement), "current", fmt.Sprintf("%T", resourceElement))
|
glog.V(4).Infof("Pattern and resource have different structures. Path: %s. Expected %T, found %T", path, patternElement, resourceElement)
|
||||||
return path, fmt.Errorf("Pattern and resource have different structures. Path: %s. Expected %T, found %T", path, patternElement, resourceElement)
|
return path, fmt.Errorf("Pattern and resource have different structures. Path: %s. Expected %T, found %T", path, patternElement, resourceElement)
|
||||||
}
|
}
|
||||||
|
|
||||||
return validateMap(log, typedResourceElement, typedPatternElement, originPattern, path)
|
return validateMap(typedResourceElement, typedPatternElement, originPattern, path)
|
||||||
// array
|
// array
|
||||||
case []interface{}:
|
case []interface{}:
|
||||||
typedResourceElement, ok := resourceElement.([]interface{})
|
typedResourceElement, ok := resourceElement.([]interface{})
|
||||||
if !ok {
|
if !ok {
|
||||||
log.V(4).Info("Pattern and resource have different structures.", "path", path, "expected", fmt.Sprintf("%T", patternElement), "current", fmt.Sprintf("%T", resourceElement))
|
glog.V(4).Infof("Pattern and resource have different structures. Path: %s. Expected %T, found %T", path, patternElement, resourceElement)
|
||||||
return path, fmt.Errorf("Validation rule Failed at path %s, resource does not satisfy the expected overlay pattern", path)
|
return path, fmt.Errorf("Validation rule Failed at path %s, resource does not satisfy the expected overlay pattern", path)
|
||||||
}
|
}
|
||||||
|
|
||||||
return validateArray(log, typedResourceElement, typedPatternElement, originPattern, path)
|
return validateArray(typedResourceElement, typedPatternElement, originPattern, path)
|
||||||
// elementary values
|
// elementary values
|
||||||
case string, float64, int, int64, bool, nil:
|
case string, float64, int, int64, bool, nil:
|
||||||
/*Analyze pattern */
|
/*Analyze pattern */
|
||||||
if checkedPattern := reflect.ValueOf(patternElement); checkedPattern.Kind() == reflect.String {
|
if checkedPattern := reflect.ValueOf(patternElement); checkedPattern.Kind() == reflect.String {
|
||||||
if isStringIsReference(checkedPattern.String()) { //check for $ anchor
|
if isStringIsReference(checkedPattern.String()) { //check for $ anchor
|
||||||
patternElement, err = actualizePattern(log, originPattern, checkedPattern.String(), path)
|
patternElement, err = actualizePattern(originPattern, checkedPattern.String(), path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return path, err
|
return path, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !ValidateValueWithPattern(log, resourceElement, patternElement) {
|
if !ValidateValueWithPattern(resourceElement, patternElement) {
|
||||||
return path, fmt.Errorf("Validation rule failed at '%s' to validate value '%v' with pattern '%v'", path, resourceElement, patternElement)
|
return path, fmt.Errorf("Validation rule failed at '%s' to validate value '%v' with pattern '%v'", path, resourceElement, patternElement)
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
log.V(4).Info("Pattern contains unknown type", "path", path, "current", fmt.Sprintf("%T", patternElement))
|
glog.V(4).Infof("Pattern contains unknown type %T. Path: %s", patternElement, path)
|
||||||
return path, fmt.Errorf("Validation rule failed at '%s', pattern contains unknown type", path)
|
return path, fmt.Errorf("Validation rule failed at '%s', pattern contains unknown type", path)
|
||||||
}
|
}
|
||||||
return "", nil
|
return "", nil
|
||||||
|
@ -72,7 +72,7 @@ func validateResourceElement(log logr.Logger, resourceElement, patternElement, o
|
||||||
|
|
||||||
// If validateResourceElement detects map element inside resource and pattern trees, it goes to validateMap
|
// If validateResourceElement detects map element inside resource and pattern trees, it goes to validateMap
|
||||||
// For each element of the map we must detect the type again, so we pass these elements to validateResourceElement
|
// For each element of the map we must detect the type again, so we pass these elements to validateResourceElement
|
||||||
func validateMap(log logr.Logger, resourceMap, patternMap map[string]interface{}, origPattern interface{}, path string) (string, error) {
|
func validateMap(resourceMap, patternMap map[string]interface{}, origPattern interface{}, path string) (string, error) {
|
||||||
// check if there is anchor in pattern
|
// check if there is anchor in pattern
|
||||||
// Phase 1 : Evaluate all the anchors
|
// Phase 1 : Evaluate all the anchors
|
||||||
// Phase 2 : Evaluate non-anchors
|
// Phase 2 : Evaluate non-anchors
|
||||||
|
@ -91,7 +91,7 @@ func validateMap(log logr.Logger, resourceMap, patternMap map[string]interface{}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// If Conditional anchor fails then we dont process the resources
|
// If Conditional anchor fails then we dont process the resources
|
||||||
if anchor.IsConditionAnchor(key) {
|
if anchor.IsConditionAnchor(key) {
|
||||||
log.Error(err, "condition anchor did not satisfy, wont process the resource")
|
glog.V(4).Infof("condition anchor did not satisfy, wont process the resources: %s", err)
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
return handlerPath, err
|
return handlerPath, err
|
||||||
|
@ -109,7 +109,7 @@ func validateMap(log logr.Logger, resourceMap, patternMap map[string]interface{}
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateArray(log logr.Logger, resourceArray, patternArray []interface{}, originPattern interface{}, path string) (string, error) {
|
func validateArray(resourceArray, patternArray []interface{}, originPattern interface{}, path string) (string, error) {
|
||||||
|
|
||||||
if 0 == len(patternArray) {
|
if 0 == len(patternArray) {
|
||||||
return path, fmt.Errorf("Pattern Array empty")
|
return path, fmt.Errorf("Pattern Array empty")
|
||||||
|
@ -119,7 +119,7 @@ func validateArray(log logr.Logger, resourceArray, patternArray []interface{}, o
|
||||||
case map[string]interface{}:
|
case map[string]interface{}:
|
||||||
// This is special case, because maps in arrays can have anchors that must be
|
// This is special case, because maps in arrays can have anchors that must be
|
||||||
// processed with the special way affecting the entire array
|
// processed with the special way affecting the entire array
|
||||||
path, err := validateArrayOfMaps(log, resourceArray, typedPatternElement, originPattern, path)
|
path, err := validateArrayOfMaps(resourceArray, typedPatternElement, originPattern, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return path, err
|
return path, err
|
||||||
}
|
}
|
||||||
|
@ -127,7 +127,7 @@ func validateArray(log logr.Logger, resourceArray, patternArray []interface{}, o
|
||||||
// In all other cases - detect type and handle each array element with validateResourceElement
|
// In all other cases - detect type and handle each array element with validateResourceElement
|
||||||
for i, patternElement := range patternArray {
|
for i, patternElement := range patternArray {
|
||||||
currentPath := path + strconv.Itoa(i) + "/"
|
currentPath := path + strconv.Itoa(i) + "/"
|
||||||
path, err := validateResourceElement(log, resourceArray[i], patternElement, originPattern, currentPath)
|
path, err := validateResourceElement(resourceArray[i], patternElement, originPattern, currentPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return path, err
|
return path, err
|
||||||
}
|
}
|
||||||
|
@ -137,7 +137,7 @@ func validateArray(log logr.Logger, resourceArray, patternArray []interface{}, o
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func actualizePattern(log logr.Logger, origPattern interface{}, referencePattern, absolutePath string) (interface{}, error) {
|
func actualizePattern(origPattern interface{}, referencePattern, absolutePath string) (interface{}, error) {
|
||||||
var foundValue interface{}
|
var foundValue interface{}
|
||||||
|
|
||||||
referencePattern = strings.Trim(referencePattern, "$()")
|
referencePattern = strings.Trim(referencePattern, "$()")
|
||||||
|
@ -155,7 +155,7 @@ func actualizePattern(log logr.Logger, origPattern interface{}, referencePattern
|
||||||
// value :=
|
// value :=
|
||||||
actualPath := formAbsolutePath(referencePattern, absolutePath)
|
actualPath := formAbsolutePath(referencePattern, absolutePath)
|
||||||
|
|
||||||
valFromReference, err := getValueFromReference(log, origPattern, actualPath)
|
valFromReference, err := getValueFromReference(origPattern, actualPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err, nil
|
return err, nil
|
||||||
}
|
}
|
||||||
|
@ -196,15 +196,15 @@ func formAbsolutePath(referencePath, absolutePath string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
//Prepares original pattern, path to value, and call traverse function
|
//Prepares original pattern, path to value, and call traverse function
|
||||||
func getValueFromReference(log logr.Logger, origPattern interface{}, reference string) (interface{}, error) {
|
func getValueFromReference(origPattern interface{}, reference string) (interface{}, error) {
|
||||||
originalPatternMap := origPattern.(map[string]interface{})
|
originalPatternMap := origPattern.(map[string]interface{})
|
||||||
reference = reference[1:]
|
reference = reference[1:]
|
||||||
statements := strings.Split(reference, "/")
|
statements := strings.Split(reference, "/")
|
||||||
|
|
||||||
return getValueFromPattern(log, originalPatternMap, statements, 0)
|
return getValueFromPattern(originalPatternMap, statements, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getValueFromPattern(log logr.Logger, patternMap map[string]interface{}, keys []string, currentKeyIndex int) (interface{}, error) {
|
func getValueFromPattern(patternMap map[string]interface{}, keys []string, currentKeyIndex int) (interface{}, error) {
|
||||||
|
|
||||||
for key, pattern := range patternMap {
|
for key, pattern := range patternMap {
|
||||||
rawKey := getRawKeyIfWrappedWithAttributes(key)
|
rawKey := getRawKeyIfWrappedWithAttributes(key)
|
||||||
|
@ -221,21 +221,19 @@ func getValueFromPattern(log logr.Logger, patternMap map[string]interface{}, key
|
||||||
for i, value := range typedPattern {
|
for i, value := range typedPattern {
|
||||||
resourceMap, ok := value.(map[string]interface{})
|
resourceMap, ok := value.(map[string]interface{})
|
||||||
if !ok {
|
if !ok {
|
||||||
log.V(4).Info("Pattern and resource have different structures.", "expected", fmt.Sprintf("%T", pattern), "current", fmt.Sprintf("%T", value))
|
glog.V(4).Infof("Pattern and resource have different structures. Expected %T, found %T", pattern, value)
|
||||||
return nil, fmt.Errorf("Validation rule failed, resource does not have expected pattern %v", patternMap)
|
return nil, fmt.Errorf("Validation rule failed, resource does not have expected pattern %v", patternMap)
|
||||||
}
|
}
|
||||||
if keys[currentKeyIndex+1] == strconv.Itoa(i) {
|
if keys[currentKeyIndex+1] == strconv.Itoa(i) {
|
||||||
return getValueFromPattern(log, resourceMap, keys, currentKeyIndex+2)
|
return getValueFromPattern(resourceMap, keys, currentKeyIndex+2)
|
||||||
}
|
}
|
||||||
// TODO : SA4004: the surrounding loop is unconditionally terminated (staticcheck)
|
|
||||||
return nil, errors.New("Reference to non-existent place in the document")
|
return nil, errors.New("Reference to non-existent place in the document")
|
||||||
}
|
}
|
||||||
return nil, nil // Just a hack to fix the lint
|
|
||||||
}
|
}
|
||||||
return nil, errors.New("Reference to non-existent place in the document")
|
return nil, errors.New("Reference to non-existent place in the document")
|
||||||
case map[string]interface{}:
|
case map[string]interface{}:
|
||||||
if keys[currentKeyIndex] == rawKey {
|
if keys[currentKeyIndex] == rawKey {
|
||||||
return getValueFromPattern(log, typedPattern, keys, currentKeyIndex+1)
|
return getValueFromPattern(typedPattern, keys, currentKeyIndex+1)
|
||||||
}
|
}
|
||||||
return nil, errors.New("Reference to non-existent place in the document")
|
return nil, errors.New("Reference to non-existent place in the document")
|
||||||
case string, float64, int, int64, bool, nil:
|
case string, float64, int, int64, bool, nil:
|
||||||
|
@ -253,12 +251,12 @@ func getValueFromPattern(log logr.Logger, patternMap map[string]interface{}, key
|
||||||
|
|
||||||
// validateArrayOfMaps gets anchors from pattern array map element, applies anchors logic
|
// validateArrayOfMaps gets anchors from pattern array map element, applies anchors logic
|
||||||
// and then validates each map due to the pattern
|
// and then validates each map due to the pattern
|
||||||
func validateArrayOfMaps(log logr.Logger, resourceMapArray []interface{}, patternMap map[string]interface{}, originPattern interface{}, path string) (string, error) {
|
func validateArrayOfMaps(resourceMapArray []interface{}, patternMap map[string]interface{}, originPattern interface{}, path string) (string, error) {
|
||||||
for i, resourceElement := range resourceMapArray {
|
for i, resourceElement := range resourceMapArray {
|
||||||
// check the types of resource element
|
// check the types of resource element
|
||||||
// expect it to be map, but can be anything ?:(
|
// expect it to be map, but can be anything ?:(
|
||||||
currentPath := path + strconv.Itoa(i) + "/"
|
currentPath := path + strconv.Itoa(i) + "/"
|
||||||
returnpath, err := validateResourceElement(log, resourceElement, patternMap, originPattern, currentPath)
|
returnpath, err := validateResourceElement(resourceElement, patternMap, originPattern, currentPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return returnpath, err
|
return returnpath, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"gotest.tools/assert"
|
"gotest.tools/assert"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestValidateMap(t *testing.T) {
|
func TestValidateMap(t *testing.T) {
|
||||||
|
@ -101,7 +100,7 @@ func TestValidateMap(t *testing.T) {
|
||||||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||||
|
|
||||||
path, err := validateMap(log.Log, resource, pattern, pattern, "/")
|
path, err := validateMap(resource, pattern, pattern, "/")
|
||||||
assert.Equal(t, path, "")
|
assert.Equal(t, path, "")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
}
|
}
|
||||||
|
@ -197,7 +196,7 @@ func TestValidateMap_AsteriskForInt(t *testing.T) {
|
||||||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||||
|
|
||||||
path, err := validateMap(log.Log, resource, pattern, pattern, "/")
|
path, err := validateMap(resource, pattern, pattern, "/")
|
||||||
t.Log(path)
|
t.Log(path)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
}
|
}
|
||||||
|
@ -290,7 +289,7 @@ func TestValidateMap_AsteriskForMap(t *testing.T) {
|
||||||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||||
|
|
||||||
path, err := validateMap(log.Log, resource, pattern, pattern, "/")
|
path, err := validateMap(resource, pattern, pattern, "/")
|
||||||
assert.Equal(t, path, "")
|
assert.Equal(t, path, "")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
}
|
}
|
||||||
|
@ -378,7 +377,7 @@ func TestValidateMap_AsteriskForArray(t *testing.T) {
|
||||||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||||
|
|
||||||
path, err := validateMap(log.Log, resource, pattern, pattern, "/")
|
path, err := validateMap(resource, pattern, pattern, "/")
|
||||||
assert.Equal(t, path, "")
|
assert.Equal(t, path, "")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
}
|
}
|
||||||
|
@ -469,7 +468,7 @@ func TestValidateMap_AsteriskFieldIsMissing(t *testing.T) {
|
||||||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||||
|
|
||||||
path, err := validateMap(log.Log, resource, pattern, pattern, "/")
|
path, err := validateMap(resource, pattern, pattern, "/")
|
||||||
assert.Equal(t, path, "/spec/template/spec/containers/0/")
|
assert.Equal(t, path, "/spec/template/spec/containers/0/")
|
||||||
assert.Assert(t, err != nil)
|
assert.Assert(t, err != nil)
|
||||||
}
|
}
|
||||||
|
@ -558,10 +557,9 @@ func TestValidateMap_livenessProbeIsNull(t *testing.T) {
|
||||||
|
|
||||||
var pattern, resource map[string]interface{}
|
var pattern, resource map[string]interface{}
|
||||||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||||
err := json.Unmarshal(rawMap, &resource)
|
json.Unmarshal(rawMap, &resource)
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
path, err := validateMap(log.Log, resource, pattern, pattern, "/")
|
path, err := validateMap(resource, pattern, pattern, "/")
|
||||||
assert.Equal(t, path, "")
|
assert.Equal(t, path, "")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
}
|
}
|
||||||
|
@ -651,7 +649,7 @@ func TestValidateMap_livenessProbeIsMissing(t *testing.T) {
|
||||||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||||
|
|
||||||
path, err := validateMap(log.Log, resource, pattern, pattern, "/")
|
path, err := validateMap(resource, pattern, pattern, "/")
|
||||||
assert.Equal(t, path, "")
|
assert.Equal(t, path, "")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
}
|
}
|
||||||
|
@ -697,7 +695,7 @@ func TestValidateMapElement_TwoElementsInArrayOnePass(t *testing.T) {
|
||||||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||||
|
|
||||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/")
|
path, err := validateResourceElement(resource, pattern, pattern, "/")
|
||||||
assert.Equal(t, path, "")
|
assert.Equal(t, path, "")
|
||||||
// assert.Equal(t, path, "/1/object/0/key2/")
|
// assert.Equal(t, path, "/1/object/0/key2/")
|
||||||
// assert.NilError(t, err)
|
// assert.NilError(t, err)
|
||||||
|
@ -732,7 +730,7 @@ func TestValidateMapElement_OneElementInArrayPass(t *testing.T) {
|
||||||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||||
|
|
||||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/")
|
path, err := validateResourceElement(resource, pattern, pattern, "/")
|
||||||
assert.Equal(t, path, "")
|
assert.Equal(t, path, "")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
}
|
}
|
||||||
|
@ -786,7 +784,7 @@ func TestValidateMap_CorrectRelativePathInConfig(t *testing.T) {
|
||||||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||||
|
|
||||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/")
|
path, err := validateResourceElement(resource, pattern, pattern, "/")
|
||||||
assert.Equal(t, path, "")
|
assert.Equal(t, path, "")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
}
|
}
|
||||||
|
@ -840,7 +838,7 @@ func TestValidateMap_RelativePathDoesNotExists(t *testing.T) {
|
||||||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||||
|
|
||||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/")
|
path, err := validateResourceElement(resource, pattern, pattern, "/")
|
||||||
assert.Equal(t, path, "/spec/containers/0/resources/requests/memory/")
|
assert.Equal(t, path, "/spec/containers/0/resources/requests/memory/")
|
||||||
assert.Assert(t, err != nil)
|
assert.Assert(t, err != nil)
|
||||||
}
|
}
|
||||||
|
@ -894,7 +892,7 @@ func TestValidateMap_OnlyAnchorsInPath(t *testing.T) {
|
||||||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||||
|
|
||||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/")
|
path, err := validateResourceElement(resource, pattern, pattern, "/")
|
||||||
assert.Equal(t, path, "/spec/containers/0/resources/requests/memory/")
|
assert.Equal(t, path, "/spec/containers/0/resources/requests/memory/")
|
||||||
assert.Assert(t, err != nil)
|
assert.Assert(t, err != nil)
|
||||||
}
|
}
|
||||||
|
@ -948,7 +946,7 @@ func TestValidateMap_MalformedReferenceOnlyDolarMark(t *testing.T) {
|
||||||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||||
|
|
||||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/")
|
path, err := validateResourceElement(resource, pattern, pattern, "/")
|
||||||
assert.Equal(t, path, "/spec/containers/0/resources/requests/memory/")
|
assert.Equal(t, path, "/spec/containers/0/resources/requests/memory/")
|
||||||
assert.Assert(t, err != nil)
|
assert.Assert(t, err != nil)
|
||||||
}
|
}
|
||||||
|
@ -1002,7 +1000,7 @@ func TestValidateMap_RelativePathWithParentheses(t *testing.T) {
|
||||||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||||
|
|
||||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/")
|
path, err := validateResourceElement(resource, pattern, pattern, "/")
|
||||||
assert.Equal(t, path, "")
|
assert.Equal(t, path, "")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
}
|
}
|
||||||
|
@ -1056,7 +1054,7 @@ func TestValidateMap_MalformedPath(t *testing.T) {
|
||||||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||||
|
|
||||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/")
|
path, err := validateResourceElement(resource, pattern, pattern, "/")
|
||||||
assert.Equal(t, path, "/spec/containers/0/resources/requests/memory/")
|
assert.Equal(t, path, "/spec/containers/0/resources/requests/memory/")
|
||||||
assert.Assert(t, err != nil)
|
assert.Assert(t, err != nil)
|
||||||
}
|
}
|
||||||
|
@ -1110,7 +1108,7 @@ func TestValidateMap_AbosolutePathExists(t *testing.T) {
|
||||||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||||
|
|
||||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/")
|
path, err := validateResourceElement(resource, pattern, pattern, "/")
|
||||||
assert.Equal(t, path, "")
|
assert.Equal(t, path, "")
|
||||||
assert.Assert(t, err == nil)
|
assert.Assert(t, err == nil)
|
||||||
}
|
}
|
||||||
|
@ -1151,7 +1149,7 @@ func TestValidateMap_AbsolutePathToMetadata(t *testing.T) {
|
||||||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||||
|
|
||||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/")
|
path, err := validateResourceElement(resource, pattern, pattern, "/")
|
||||||
assert.Equal(t, path, "")
|
assert.Equal(t, path, "")
|
||||||
assert.Assert(t, err == nil)
|
assert.Assert(t, err == nil)
|
||||||
}
|
}
|
||||||
|
@ -1193,7 +1191,7 @@ func TestValidateMap_AbsolutePathToMetadata_fail(t *testing.T) {
|
||||||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||||
|
|
||||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/")
|
path, err := validateResourceElement(resource, pattern, pattern, "/")
|
||||||
assert.Equal(t, path, "/spec/containers/0/image/")
|
assert.Equal(t, path, "/spec/containers/0/image/")
|
||||||
assert.Assert(t, err != nil)
|
assert.Assert(t, err != nil)
|
||||||
}
|
}
|
||||||
|
@ -1247,7 +1245,7 @@ func TestValidateMap_AbosolutePathDoesNotExists(t *testing.T) {
|
||||||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||||
|
|
||||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/")
|
path, err := validateResourceElement(resource, pattern, pattern, "/")
|
||||||
assert.Equal(t, path, "/spec/containers/0/resources/requests/memory/")
|
assert.Equal(t, path, "/spec/containers/0/resources/requests/memory/")
|
||||||
assert.Assert(t, err != nil)
|
assert.Assert(t, err != nil)
|
||||||
}
|
}
|
||||||
|
@ -1278,7 +1276,7 @@ func TestActualizePattern_GivenRelativePathThatExists(t *testing.T) {
|
||||||
|
|
||||||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||||
|
|
||||||
pattern, err := actualizePattern(log.Log, pattern, referencePath, absolutePath)
|
pattern, err := actualizePattern(pattern, referencePath, absolutePath)
|
||||||
|
|
||||||
assert.Assert(t, err == nil)
|
assert.Assert(t, err == nil)
|
||||||
}
|
}
|
||||||
|
@ -1346,12 +1344,10 @@ func TestValidateMapElement_OneElementInArrayNotPass(t *testing.T) {
|
||||||
]`)
|
]`)
|
||||||
|
|
||||||
var pattern, resource interface{}
|
var pattern, resource interface{}
|
||||||
err := json.Unmarshal(rawPattern, &pattern)
|
json.Unmarshal(rawPattern, &pattern)
|
||||||
assert.NilError(t, err)
|
json.Unmarshal(rawMap, &resource)
|
||||||
err = json.Unmarshal(rawMap, &resource)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/")
|
path, err := validateResourceElement(resource, pattern, pattern, "/")
|
||||||
assert.Equal(t, path, "/0/object/0/key2/")
|
assert.Equal(t, path, "/0/object/0/key2/")
|
||||||
assert.Assert(t, err != nil)
|
assert.Assert(t, err != nil)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
"github.com/golang/glog"
|
||||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||||
"github.com/nirmata/kyverno/pkg/engine/context"
|
"github.com/nirmata/kyverno/pkg/engine/context"
|
||||||
"github.com/nirmata/kyverno/pkg/engine/response"
|
"github.com/nirmata/kyverno/pkg/engine/response"
|
||||||
|
@ -13,7 +13,6 @@ import (
|
||||||
"github.com/nirmata/kyverno/pkg/engine/validate"
|
"github.com/nirmata/kyverno/pkg/engine/validate"
|
||||||
"github.com/nirmata/kyverno/pkg/engine/variables"
|
"github.com/nirmata/kyverno/pkg/engine/variables"
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
//Validate applies validation rules from policy on the resource
|
//Validate applies validation rules from policy on the resource
|
||||||
|
@ -24,18 +23,17 @@ func Validate(policyContext PolicyContext) (resp response.EngineResponse) {
|
||||||
oldR := policyContext.OldResource
|
oldR := policyContext.OldResource
|
||||||
ctx := policyContext.Context
|
ctx := policyContext.Context
|
||||||
admissionInfo := policyContext.AdmissionInfo
|
admissionInfo := policyContext.AdmissionInfo
|
||||||
logger := log.Log.WithName("Validate").WithValues("policy", policy.Name, "kind", newR.GetKind(), "namespace", newR.GetNamespace(), "name", newR.GetName())
|
|
||||||
|
|
||||||
// policy information
|
// policy information
|
||||||
logger.V(4).Info("start processing", "startTime", startTime)
|
glog.V(4).Infof("started applying validation rules of policy %q (%v)", policy.Name, startTime)
|
||||||
|
|
||||||
// Process new & old resource
|
// Process new & old resource
|
||||||
if reflect.DeepEqual(oldR, unstructured.Unstructured{}) {
|
if reflect.DeepEqual(oldR, unstructured.Unstructured{}) {
|
||||||
// Create Mode
|
// Create Mode
|
||||||
// Operate on New Resource only
|
// Operate on New Resource only
|
||||||
resp := validateResource(logger, ctx, policy, newR, admissionInfo)
|
resp := validateResource(ctx, policy, newR, admissionInfo)
|
||||||
startResultResponse(resp, policy, newR)
|
startResultResponse(resp, policy, newR)
|
||||||
defer endResultResponse(logger, resp, startTime)
|
defer endResultResponse(resp, startTime)
|
||||||
// set PatchedResource with origin resource if empty
|
// set PatchedResource with origin resource if empty
|
||||||
// in order to create policy violation
|
// in order to create policy violation
|
||||||
if reflect.DeepEqual(resp.PatchedResource, unstructured.Unstructured{}) {
|
if reflect.DeepEqual(resp.PatchedResource, unstructured.Unstructured{}) {
|
||||||
|
@ -46,14 +44,14 @@ func Validate(policyContext PolicyContext) (resp response.EngineResponse) {
|
||||||
// Update Mode
|
// Update Mode
|
||||||
// Operate on New and Old Resource only
|
// Operate on New and Old Resource only
|
||||||
// New resource
|
// New resource
|
||||||
oldResponse := validateResource(logger, ctx, policy, oldR, admissionInfo)
|
oldResponse := validateResource(ctx, policy, oldR, admissionInfo)
|
||||||
newResponse := validateResource(logger, ctx, policy, newR, admissionInfo)
|
newResponse := validateResource(ctx, policy, newR, admissionInfo)
|
||||||
|
|
||||||
// if the old and new response is same then return empty response
|
// if the old and new response is same then return empty response
|
||||||
if !isSameResponse(oldResponse, newResponse) {
|
if !isSameResponse(oldResponse, newResponse) {
|
||||||
// there are changes send response
|
// there are changes send response
|
||||||
startResultResponse(newResponse, policy, newR)
|
startResultResponse(newResponse, policy, newR)
|
||||||
defer endResultResponse(logger, newResponse, startTime)
|
defer endResultResponse(newResponse, startTime)
|
||||||
if reflect.DeepEqual(newResponse.PatchedResource, unstructured.Unstructured{}) {
|
if reflect.DeepEqual(newResponse.PatchedResource, unstructured.Unstructured{}) {
|
||||||
newResponse.PatchedResource = newR
|
newResponse.PatchedResource = newR
|
||||||
}
|
}
|
||||||
|
@ -75,9 +73,10 @@ func startResultResponse(resp *response.EngineResponse, policy kyverno.ClusterPo
|
||||||
resp.PolicyResponse.ValidationFailureAction = policy.Spec.ValidationFailureAction
|
resp.PolicyResponse.ValidationFailureAction = policy.Spec.ValidationFailureAction
|
||||||
}
|
}
|
||||||
|
|
||||||
func endResultResponse(log logr.Logger, resp *response.EngineResponse, startTime time.Time) {
|
func endResultResponse(resp *response.EngineResponse, startTime time.Time) {
|
||||||
resp.PolicyResponse.ProcessingTime = time.Since(startTime)
|
resp.PolicyResponse.ProcessingTime = time.Since(startTime)
|
||||||
log.V(4).Info("finshed processing", "processingTime", resp.PolicyResponse.ProcessingTime, "validationRulesApplied", resp.PolicyResponse.RulesAppliedCount)
|
glog.V(4).Infof("Finished applying validation rules policy %v (%v)", resp.PolicyResponse.Policy, resp.PolicyResponse.ProcessingTime)
|
||||||
|
glog.V(4).Infof("Validation Rules appplied successfully count %v for policy %q", resp.PolicyResponse.RulesAppliedCount, resp.PolicyResponse.Policy)
|
||||||
}
|
}
|
||||||
|
|
||||||
func incrementAppliedCount(resp *response.EngineResponse) {
|
func incrementAppliedCount(resp *response.EngineResponse) {
|
||||||
|
@ -85,18 +84,20 @@ func incrementAppliedCount(resp *response.EngineResponse) {
|
||||||
resp.PolicyResponse.RulesAppliedCount++
|
resp.PolicyResponse.RulesAppliedCount++
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateResource(log logr.Logger, ctx context.EvalInterface, policy kyverno.ClusterPolicy, resource unstructured.Unstructured, admissionInfo kyverno.RequestInfo) *response.EngineResponse {
|
func validateResource(ctx context.EvalInterface, policy kyverno.ClusterPolicy, resource unstructured.Unstructured, admissionInfo kyverno.RequestInfo) *response.EngineResponse {
|
||||||
resp := &response.EngineResponse{}
|
resp := &response.EngineResponse{}
|
||||||
for _, rule := range policy.Spec.Rules {
|
for _, rule := range policy.Spec.Rules {
|
||||||
if !rule.HasValidate() {
|
if !rule.HasValidate() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
startTime := time.Now()
|
||||||
|
glog.V(4).Infof("Time: Validate matchAdmissionInfo %v", time.Since(startTime))
|
||||||
|
|
||||||
// check if the resource satisfies the filter conditions defined in the rule
|
// check if the resource satisfies the filter conditions defined in the rule
|
||||||
// TODO: this needs to be extracted, to filter the resource so that we can avoid passing resources that
|
// TODO: this needs to be extracted, to filter the resource so that we can avoid passing resources that
|
||||||
// dont statisfy a policy rule resource description
|
// dont statisfy a policy rule resource description
|
||||||
if err := MatchesResourceDescription(resource, rule, admissionInfo); err != nil {
|
if err := MatchesResourceDescription(resource, rule, admissionInfo); err != nil {
|
||||||
log.V(4).Info("resource fails the match description")
|
glog.V(4).Infof("resource %s/%s does not satisfy the resource description for the rule:\n%s", resource.GetNamespace(), resource.GetName(), err.Error())
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,13 +105,13 @@ func validateResource(log logr.Logger, ctx context.EvalInterface, policy kyverno
|
||||||
copyConditions := copyConditions(rule.Conditions)
|
copyConditions := copyConditions(rule.Conditions)
|
||||||
// evaluate pre-conditions
|
// evaluate pre-conditions
|
||||||
// - handle variable subsitutions
|
// - handle variable subsitutions
|
||||||
if !variables.EvaluateConditions(log, ctx, copyConditions) {
|
if !variables.EvaluateConditions(ctx, copyConditions) {
|
||||||
log.V(4).Info("resource fails the preconditions")
|
glog.V(4).Infof("resource %s/%s does not satisfy the conditions for the rule ", resource.GetNamespace(), resource.GetName())
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if rule.Validation.Pattern != nil || rule.Validation.AnyPattern != nil {
|
if rule.Validation.Pattern != nil || rule.Validation.AnyPattern != nil {
|
||||||
ruleResponse := validatePatterns(log, ctx, resource, rule)
|
ruleResponse := validatePatterns(ctx, resource, rule)
|
||||||
incrementAppliedCount(resp)
|
incrementAppliedCount(resp)
|
||||||
resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, ruleResponse)
|
resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, ruleResponse)
|
||||||
}
|
}
|
||||||
|
@ -158,15 +159,14 @@ func isSameRules(oldRules []response.RuleResponse, newRules []response.RuleRespo
|
||||||
}
|
}
|
||||||
|
|
||||||
// validatePatterns validate pattern and anyPattern
|
// validatePatterns validate pattern and anyPattern
|
||||||
func validatePatterns(log logr.Logger, ctx context.EvalInterface, resource unstructured.Unstructured, rule kyverno.Rule) (resp response.RuleResponse) {
|
func validatePatterns(ctx context.EvalInterface, resource unstructured.Unstructured, rule kyverno.Rule) (resp response.RuleResponse) {
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
logger := log.WithValues("rule", rule.Name)
|
glog.V(4).Infof("started applying validation rule %q (%v)", rule.Name, startTime)
|
||||||
logger.V(4).Info("start processing rule", "startTime", startTime)
|
|
||||||
resp.Name = rule.Name
|
resp.Name = rule.Name
|
||||||
resp.Type = utils.Validation.String()
|
resp.Type = utils.Validation.String()
|
||||||
defer func() {
|
defer func() {
|
||||||
resp.RuleStats.ProcessingTime = time.Since(startTime)
|
resp.RuleStats.ProcessingTime = time.Since(startTime)
|
||||||
logger.V(4).Info("finshed processing", "processingTime", resp.RuleStats.ProcessingTime)
|
glog.V(4).Infof("finished applying validation rule %q (%v)", resp.Name, resp.RuleStats.ProcessingTime)
|
||||||
}()
|
}()
|
||||||
// work on a copy of validation rule
|
// work on a copy of validation rule
|
||||||
validationRule := rule.Validation.DeepCopy()
|
validationRule := rule.Validation.DeepCopy()
|
||||||
|
@ -176,7 +176,7 @@ func validatePatterns(log logr.Logger, ctx context.EvalInterface, resource unstr
|
||||||
// substitute variables in the pattern
|
// substitute variables in the pattern
|
||||||
pattern := validationRule.Pattern
|
pattern := validationRule.Pattern
|
||||||
var err error
|
var err error
|
||||||
if pattern, err = variables.SubstituteVars(logger, ctx, pattern); err != nil {
|
if pattern, err = variables.SubstituteVars(ctx, pattern); err != nil {
|
||||||
// variable subsitution failed
|
// variable subsitution failed
|
||||||
resp.Success = false
|
resp.Success = false
|
||||||
resp.Message = fmt.Sprintf("Validation error: %s; Validation rule '%s' failed. '%s'",
|
resp.Message = fmt.Sprintf("Validation error: %s; Validation rule '%s' failed. '%s'",
|
||||||
|
@ -184,7 +184,7 @@ func validatePatterns(log logr.Logger, ctx context.EvalInterface, resource unstr
|
||||||
return resp
|
return resp
|
||||||
}
|
}
|
||||||
|
|
||||||
if path, err := validate.ValidateResourceWithPattern(logger, resource.Object, pattern); err != nil {
|
if path, err := validate.ValidateResourceWithPattern(resource.Object, pattern); err != nil {
|
||||||
// validation failed
|
// validation failed
|
||||||
resp.Success = false
|
resp.Success = false
|
||||||
resp.Message = fmt.Sprintf("Validation error: %s; Validation rule '%s' failed at path '%s'",
|
resp.Message = fmt.Sprintf("Validation error: %s; Validation rule '%s' failed at path '%s'",
|
||||||
|
@ -192,7 +192,7 @@ func validatePatterns(log logr.Logger, ctx context.EvalInterface, resource unstr
|
||||||
return resp
|
return resp
|
||||||
}
|
}
|
||||||
// rule application successful
|
// rule application successful
|
||||||
logger.V(4).Info("successfully processed rule")
|
glog.V(4).Infof("rule %s pattern validated successfully on resource %s/%s/%s", rule.Name, resource.GetKind(), resource.GetNamespace(), resource.GetName())
|
||||||
resp.Success = true
|
resp.Success = true
|
||||||
resp.Message = fmt.Sprintf("Validation rule '%s' succeeded.", rule.Name)
|
resp.Message = fmt.Sprintf("Validation rule '%s' succeeded.", rule.Name)
|
||||||
return resp
|
return resp
|
||||||
|
@ -203,18 +203,19 @@ func validatePatterns(log logr.Logger, ctx context.EvalInterface, resource unstr
|
||||||
var failedAnyPatternsErrors []error
|
var failedAnyPatternsErrors []error
|
||||||
var err error
|
var err error
|
||||||
for idx, pattern := range validationRule.AnyPattern {
|
for idx, pattern := range validationRule.AnyPattern {
|
||||||
if pattern, err = variables.SubstituteVars(logger, ctx, pattern); err != nil {
|
if pattern, err = variables.SubstituteVars(ctx, pattern); err != nil {
|
||||||
// variable subsitution failed
|
// variable subsitution failed
|
||||||
failedSubstitutionsErrors = append(failedSubstitutionsErrors, err)
|
failedSubstitutionsErrors = append(failedSubstitutionsErrors, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
_, err := validate.ValidateResourceWithPattern(logger, resource.Object, pattern)
|
_, err := validate.ValidateResourceWithPattern(resource.Object, pattern)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
resp.Success = true
|
resp.Success = true
|
||||||
resp.Message = fmt.Sprintf("Validation rule '%s' anyPattern[%d] succeeded.", rule.Name, idx)
|
resp.Message = fmt.Sprintf("Validation rule '%s' anyPattern[%d] succeeded.", rule.Name, idx)
|
||||||
return resp
|
return resp
|
||||||
}
|
}
|
||||||
logger.V(4).Info(fmt.Sprintf("validation rule failed for anyPattern[%d]", idx), "message", rule.Validation.Message)
|
glog.V(4).Infof("Validation error: %s; Validation rule %s anyPattern[%d] for %s/%s/%s",
|
||||||
|
rule.Validation.Message, rule.Name, idx, resource.GetKind(), resource.GetNamespace(), resource.GetName())
|
||||||
patternErr := fmt.Errorf("anyPattern[%d] failed; %s", idx, err)
|
patternErr := fmt.Errorf("anyPattern[%d] failed; %s", idx, err)
|
||||||
failedAnyPatternsErrors = append(failedAnyPatternsErrors, patternErr)
|
failedAnyPatternsErrors = append(failedAnyPatternsErrors, patternErr)
|
||||||
}
|
}
|
||||||
|
@ -233,7 +234,7 @@ func validatePatterns(log logr.Logger, ctx context.EvalInterface, resource unstr
|
||||||
errorStr = append(errorStr, err.Error())
|
errorStr = append(errorStr, err.Error())
|
||||||
}
|
}
|
||||||
resp.Success = false
|
resp.Success = false
|
||||||
log.V(4).Info(fmt.Sprintf("Validation rule '%s' failed. %s", rule.Name, errorStr))
|
glog.V(4).Infof("Validation rule '%s' failed. %s", rule.Name, errorStr)
|
||||||
if rule.Validation.Message == "" {
|
if rule.Validation.Message == "" {
|
||||||
resp.Message = fmt.Sprintf("Validation rule '%s' has failed", rule.Name)
|
resp.Message = fmt.Sprintf("Validation rule '%s' has failed", rule.Name)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -23,8 +23,7 @@ func TestGetAnchorsFromMap_ThereAreAnchors(t *testing.T) {
|
||||||
}`)
|
}`)
|
||||||
|
|
||||||
var unmarshalled map[string]interface{}
|
var unmarshalled map[string]interface{}
|
||||||
err := json.Unmarshal(rawMap, &unmarshalled)
|
json.Unmarshal(rawMap, &unmarshalled)
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
actualMap := utils.GetAnchorsFromMap(unmarshalled)
|
actualMap := utils.GetAnchorsFromMap(unmarshalled)
|
||||||
assert.Equal(t, len(actualMap), 2)
|
assert.Equal(t, len(actualMap), 2)
|
||||||
|
@ -115,8 +114,7 @@ func TestValidate_image_tag_fail(t *testing.T) {
|
||||||
`)
|
`)
|
||||||
|
|
||||||
var policy kyverno.ClusterPolicy
|
var policy kyverno.ClusterPolicy
|
||||||
err := json.Unmarshal(rawPolicy, &policy)
|
json.Unmarshal(rawPolicy, &policy)
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
@ -214,8 +212,7 @@ func TestValidate_image_tag_pass(t *testing.T) {
|
||||||
`)
|
`)
|
||||||
|
|
||||||
var policy kyverno.ClusterPolicy
|
var policy kyverno.ClusterPolicy
|
||||||
err := json.Unmarshal(rawPolicy, &policy)
|
json.Unmarshal(rawPolicy, &policy)
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
@ -292,8 +289,7 @@ func TestValidate_Fail_anyPattern(t *testing.T) {
|
||||||
`)
|
`)
|
||||||
|
|
||||||
var policy kyverno.ClusterPolicy
|
var policy kyverno.ClusterPolicy
|
||||||
err := json.Unmarshal(rawPolicy, &policy)
|
json.Unmarshal(rawPolicy, &policy)
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
@ -374,8 +370,7 @@ func TestValidate_host_network_port(t *testing.T) {
|
||||||
`)
|
`)
|
||||||
|
|
||||||
var policy kyverno.ClusterPolicy
|
var policy kyverno.ClusterPolicy
|
||||||
err := json.Unmarshal(rawPolicy, &policy)
|
json.Unmarshal(rawPolicy, &policy)
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
@ -464,8 +459,7 @@ func TestValidate_anchor_arraymap_pass(t *testing.T) {
|
||||||
} `)
|
} `)
|
||||||
|
|
||||||
var policy kyverno.ClusterPolicy
|
var policy kyverno.ClusterPolicy
|
||||||
err := json.Unmarshal(rawPolicy, &policy)
|
json.Unmarshal(rawPolicy, &policy)
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
@ -553,8 +547,8 @@ func TestValidate_anchor_arraymap_fail(t *testing.T) {
|
||||||
} `)
|
} `)
|
||||||
|
|
||||||
var policy kyverno.ClusterPolicy
|
var policy kyverno.ClusterPolicy
|
||||||
err := json.Unmarshal(rawPolicy, &policy)
|
json.Unmarshal(rawPolicy, &policy)
|
||||||
assert.NilError(t, err)
|
|
||||||
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
er := Validate(PolicyContext{Policy: policy, NewResource: *resourceUnstructured})
|
er := Validate(PolicyContext{Policy: policy, NewResource: *resourceUnstructured})
|
||||||
|
@ -622,8 +616,7 @@ func TestValidate_anchor_map_notfound(t *testing.T) {
|
||||||
`)
|
`)
|
||||||
|
|
||||||
var policy kyverno.ClusterPolicy
|
var policy kyverno.ClusterPolicy
|
||||||
err := json.Unmarshal(rawPolicy, &policy)
|
json.Unmarshal(rawPolicy, &policy)
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
@ -695,8 +688,7 @@ func TestValidate_anchor_map_found_valid(t *testing.T) {
|
||||||
`)
|
`)
|
||||||
|
|
||||||
var policy kyverno.ClusterPolicy
|
var policy kyverno.ClusterPolicy
|
||||||
err := json.Unmarshal(rawPolicy, &policy)
|
json.Unmarshal(rawPolicy, &policy)
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
@ -768,8 +760,7 @@ func TestValidate_anchor_map_found_invalid(t *testing.T) {
|
||||||
`)
|
`)
|
||||||
|
|
||||||
var policy kyverno.ClusterPolicy
|
var policy kyverno.ClusterPolicy
|
||||||
err := json.Unmarshal(rawPolicy, &policy)
|
json.Unmarshal(rawPolicy, &policy)
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
@ -843,8 +834,7 @@ func TestValidate_AnchorList_pass(t *testing.T) {
|
||||||
`)
|
`)
|
||||||
|
|
||||||
var policy kyverno.ClusterPolicy
|
var policy kyverno.ClusterPolicy
|
||||||
err := json.Unmarshal(rawPolicy, &policy)
|
json.Unmarshal(rawPolicy, &policy)
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
@ -918,8 +908,7 @@ func TestValidate_AnchorList_fail(t *testing.T) {
|
||||||
`)
|
`)
|
||||||
|
|
||||||
var policy kyverno.ClusterPolicy
|
var policy kyverno.ClusterPolicy
|
||||||
err := json.Unmarshal(rawPolicy, &policy)
|
json.Unmarshal(rawPolicy, &policy)
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
@ -993,8 +982,7 @@ func TestValidate_existenceAnchor_fail(t *testing.T) {
|
||||||
`)
|
`)
|
||||||
|
|
||||||
var policy kyverno.ClusterPolicy
|
var policy kyverno.ClusterPolicy
|
||||||
err := json.Unmarshal(rawPolicy, &policy)
|
json.Unmarshal(rawPolicy, &policy)
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
@ -1069,8 +1057,7 @@ func TestValidate_existenceAnchor_pass(t *testing.T) {
|
||||||
`)
|
`)
|
||||||
|
|
||||||
var policy kyverno.ClusterPolicy
|
var policy kyverno.ClusterPolicy
|
||||||
err := json.Unmarshal(rawPolicy, &policy)
|
json.Unmarshal(rawPolicy, &policy)
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
@ -1157,8 +1144,7 @@ func TestValidate_negationAnchor_deny(t *testing.T) {
|
||||||
} `)
|
} `)
|
||||||
|
|
||||||
var policy kyverno.ClusterPolicy
|
var policy kyverno.ClusterPolicy
|
||||||
err := json.Unmarshal(rawPolicy, &policy)
|
json.Unmarshal(rawPolicy, &policy)
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
@ -1244,8 +1230,7 @@ func TestValidate_negationAnchor_pass(t *testing.T) {
|
||||||
`)
|
`)
|
||||||
|
|
||||||
var policy kyverno.ClusterPolicy
|
var policy kyverno.ClusterPolicy
|
||||||
err := json.Unmarshal(rawPolicy, &policy)
|
json.Unmarshal(rawPolicy, &policy)
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
@ -1312,14 +1297,12 @@ func Test_VariableSubstitutionPathNotExistInPattern(t *testing.T) {
|
||||||
}`)
|
}`)
|
||||||
|
|
||||||
var policy kyverno.ClusterPolicy
|
var policy kyverno.ClusterPolicy
|
||||||
err := json.Unmarshal(policyraw, &policy)
|
json.Unmarshal(policyraw, &policy)
|
||||||
assert.NilError(t, err)
|
|
||||||
resourceUnstructured, err := utils.ConvertToUnstructured(resourceRaw)
|
resourceUnstructured, err := utils.ConvertToUnstructured(resourceRaw)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
ctx := context.NewContext()
|
ctx := context.NewContext()
|
||||||
err = ctx.AddResource(resourceRaw)
|
ctx.AddResource(resourceRaw)
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
policyContext := PolicyContext{
|
policyContext := PolicyContext{
|
||||||
Policy: policy,
|
Policy: policy,
|
||||||
|
@ -1409,8 +1392,7 @@ func Test_VariableSubstitutionPathNotExistInAnyPattern_OnePatternStatisfies(t *t
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
ctx := context.NewContext()
|
ctx := context.NewContext()
|
||||||
err = ctx.AddResource(resourceRaw)
|
ctx.AddResource(resourceRaw)
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
policyContext := PolicyContext{
|
policyContext := PolicyContext{
|
||||||
Policy: policy,
|
Policy: policy,
|
||||||
|
@ -1500,8 +1482,7 @@ func Test_VariableSubstitutionPathNotExistInAnyPattern_AllPathNotPresent(t *test
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
ctx := context.NewContext()
|
ctx := context.NewContext()
|
||||||
err = ctx.AddResource(resourceRaw)
|
ctx.AddResource(resourceRaw)
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
policyContext := PolicyContext{
|
policyContext := PolicyContext{
|
||||||
Policy: policy,
|
Policy: policy,
|
||||||
|
@ -1591,8 +1572,7 @@ func Test_VariableSubstitutionPathNotExistInAnyPattern_AllPathPresent_NonePatter
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
ctx := context.NewContext()
|
ctx := context.NewContext()
|
||||||
err = ctx.AddResource(resourceRaw)
|
ctx.AddResource(resourceRaw)
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
policyContext := PolicyContext{
|
policyContext := PolicyContext{
|
||||||
Policy: policy,
|
Policy: policy,
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
package variables
|
|
||||||
|
|
||||||
import "regexp"
|
|
||||||
|
|
||||||
//IsVariable returns true if the element contains a 'valid' variable {{}}
|
|
||||||
func IsVariable(element string) bool {
|
|
||||||
validRegex := regexp.MustCompile(variableRegex)
|
|
||||||
groups := validRegex.FindAllStringSubmatch(element, -1)
|
|
||||||
return len(groups) != 0
|
|
||||||
}
|
|
|
@ -1,16 +1,16 @@
|
||||||
package variables
|
package variables
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/go-logr/logr"
|
"github.com/golang/glog"
|
||||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||||
"github.com/nirmata/kyverno/pkg/engine/context"
|
"github.com/nirmata/kyverno/pkg/engine/context"
|
||||||
"github.com/nirmata/kyverno/pkg/engine/variables/operator"
|
"github.com/nirmata/kyverno/pkg/engine/variables/operator"
|
||||||
)
|
)
|
||||||
|
|
||||||
//Evaluate evaluates the condition
|
//Evaluate evaluates the condition
|
||||||
func Evaluate(log logr.Logger, ctx context.EvalInterface, condition kyverno.Condition) bool {
|
func Evaluate(ctx context.EvalInterface, condition kyverno.Condition) bool {
|
||||||
// get handler for the operator
|
// get handler for the operator
|
||||||
handle := operator.CreateOperatorHandler(log, ctx, condition.Operator, SubstituteVars)
|
handle := operator.CreateOperatorHandler(ctx, condition.Operator, SubstituteVars)
|
||||||
if handle == nil {
|
if handle == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -18,10 +18,11 @@ func Evaluate(log logr.Logger, ctx context.EvalInterface, condition kyverno.Cond
|
||||||
}
|
}
|
||||||
|
|
||||||
//EvaluateConditions evaluates multiple conditions
|
//EvaluateConditions evaluates multiple conditions
|
||||||
func EvaluateConditions(log logr.Logger, ctx context.EvalInterface, conditions []kyverno.Condition) bool {
|
func EvaluateConditions(ctx context.EvalInterface, conditions []kyverno.Condition) bool {
|
||||||
// AND the conditions
|
// AND the conditions
|
||||||
for _, condition := range conditions {
|
for _, condition := range conditions {
|
||||||
if !Evaluate(log, ctx, condition) {
|
if !Evaluate(ctx, condition) {
|
||||||
|
glog.V(4).Infof("condition %v failed", condition)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ import (
|
||||||
|
|
||||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||||
"github.com/nirmata/kyverno/pkg/engine/context"
|
"github.com/nirmata/kyverno/pkg/engine/context"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// STRINGS
|
// STRINGS
|
||||||
|
@ -19,7 +18,7 @@ func Test_Eval_Equal_Const_String_Pass(t *testing.T) {
|
||||||
Value: "name",
|
Value: "name",
|
||||||
}
|
}
|
||||||
|
|
||||||
if !Evaluate(log.Log, ctx, condition) {
|
if !Evaluate(ctx, condition) {
|
||||||
t.Error("expected to pass")
|
t.Error("expected to pass")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,7 +32,7 @@ func Test_Eval_Equal_Const_String_Fail(t *testing.T) {
|
||||||
Value: "name1",
|
Value: "name1",
|
||||||
}
|
}
|
||||||
|
|
||||||
if Evaluate(log.Log, ctx, condition) {
|
if Evaluate(ctx, condition) {
|
||||||
t.Error("expected to fail")
|
t.Error("expected to fail")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,7 +46,7 @@ func Test_Eval_NoEqual_Const_String_Pass(t *testing.T) {
|
||||||
Value: "name1",
|
Value: "name1",
|
||||||
}
|
}
|
||||||
|
|
||||||
if !Evaluate(log.Log, ctx, condition) {
|
if !Evaluate(ctx, condition) {
|
||||||
t.Error("expected to pass")
|
t.Error("expected to pass")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,7 +60,7 @@ func Test_Eval_NoEqual_Const_String_Fail(t *testing.T) {
|
||||||
Value: "name",
|
Value: "name",
|
||||||
}
|
}
|
||||||
|
|
||||||
if Evaluate(log.Log, ctx, condition) {
|
if Evaluate(ctx, condition) {
|
||||||
t.Error("expected to fail")
|
t.Error("expected to fail")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,7 +76,7 @@ func Test_Eval_Equal_Const_Bool_Pass(t *testing.T) {
|
||||||
Value: true,
|
Value: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
if !Evaluate(log.Log, ctx, condition) {
|
if !Evaluate(ctx, condition) {
|
||||||
t.Error("expected to pass")
|
t.Error("expected to pass")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,7 +90,7 @@ func Test_Eval_Equal_Const_Bool_Fail(t *testing.T) {
|
||||||
Value: false,
|
Value: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
if Evaluate(log.Log, ctx, condition) {
|
if Evaluate(ctx, condition) {
|
||||||
t.Error("expected to fail")
|
t.Error("expected to fail")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -105,7 +104,7 @@ func Test_Eval_NoEqual_Const_Bool_Pass(t *testing.T) {
|
||||||
Value: false,
|
Value: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
if !Evaluate(log.Log, ctx, condition) {
|
if !Evaluate(ctx, condition) {
|
||||||
t.Error("expected to pass")
|
t.Error("expected to pass")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -119,7 +118,7 @@ func Test_Eval_NoEqual_Const_Bool_Fail(t *testing.T) {
|
||||||
Value: true,
|
Value: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
if Evaluate(log.Log, ctx, condition) {
|
if Evaluate(ctx, condition) {
|
||||||
t.Error("expected to fail")
|
t.Error("expected to fail")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -134,7 +133,7 @@ func Test_Eval_Equal_Const_int_Pass(t *testing.T) {
|
||||||
Value: 1,
|
Value: 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
if !Evaluate(log.Log, ctx, condition) {
|
if !Evaluate(ctx, condition) {
|
||||||
t.Error("expected to pass")
|
t.Error("expected to pass")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -148,7 +147,7 @@ func Test_Eval_Equal_Const_int_Fail(t *testing.T) {
|
||||||
Value: 2,
|
Value: 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
if Evaluate(log.Log, ctx, condition) {
|
if Evaluate(ctx, condition) {
|
||||||
t.Error("expected to fail")
|
t.Error("expected to fail")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -162,7 +161,7 @@ func Test_Eval_NoEqual_Const_int_Pass(t *testing.T) {
|
||||||
Value: 2,
|
Value: 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
if !Evaluate(log.Log, ctx, condition) {
|
if !Evaluate(ctx, condition) {
|
||||||
t.Error("expected to pass")
|
t.Error("expected to pass")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -176,7 +175,7 @@ func Test_Eval_NoEqual_Const_int_Fail(t *testing.T) {
|
||||||
Value: 1,
|
Value: 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
if Evaluate(log.Log, ctx, condition) {
|
if Evaluate(ctx, condition) {
|
||||||
t.Error("expected to fail")
|
t.Error("expected to fail")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -191,7 +190,7 @@ func Test_Eval_Equal_Const_int64_Pass(t *testing.T) {
|
||||||
Value: int64(1),
|
Value: int64(1),
|
||||||
}
|
}
|
||||||
|
|
||||||
if !Evaluate(log.Log, ctx, condition) {
|
if !Evaluate(ctx, condition) {
|
||||||
t.Error("expected to pass")
|
t.Error("expected to pass")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -205,7 +204,7 @@ func Test_Eval_Equal_Const_int64_Fail(t *testing.T) {
|
||||||
Value: int64(2),
|
Value: int64(2),
|
||||||
}
|
}
|
||||||
|
|
||||||
if Evaluate(log.Log, ctx, condition) {
|
if Evaluate(ctx, condition) {
|
||||||
t.Error("expected to fail")
|
t.Error("expected to fail")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -219,7 +218,7 @@ func Test_Eval_NoEqual_Const_int64_Pass(t *testing.T) {
|
||||||
Value: int64(2),
|
Value: int64(2),
|
||||||
}
|
}
|
||||||
|
|
||||||
if !Evaluate(log.Log, ctx, condition) {
|
if !Evaluate(ctx, condition) {
|
||||||
t.Error("expected to pass")
|
t.Error("expected to pass")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -233,7 +232,7 @@ func Test_Eval_NoEqual_Const_int64_Fail(t *testing.T) {
|
||||||
Value: int64(1),
|
Value: int64(1),
|
||||||
}
|
}
|
||||||
|
|
||||||
if Evaluate(log.Log, ctx, condition) {
|
if Evaluate(ctx, condition) {
|
||||||
t.Error("expected to fail")
|
t.Error("expected to fail")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -249,7 +248,7 @@ func Test_Eval_Equal_Const_float64_Pass(t *testing.T) {
|
||||||
Value: 1.5,
|
Value: 1.5,
|
||||||
}
|
}
|
||||||
|
|
||||||
if !Evaluate(log.Log, ctx, condition) {
|
if !Evaluate(ctx, condition) {
|
||||||
t.Error("expected to pass")
|
t.Error("expected to pass")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -263,7 +262,7 @@ func Test_Eval_Equal_Const_float64_Fail(t *testing.T) {
|
||||||
Value: 1.6,
|
Value: 1.6,
|
||||||
}
|
}
|
||||||
|
|
||||||
if Evaluate(log.Log, ctx, condition) {
|
if Evaluate(ctx, condition) {
|
||||||
t.Error("expected to fail")
|
t.Error("expected to fail")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -277,7 +276,7 @@ func Test_Eval_NoEqual_Const_float64_Pass(t *testing.T) {
|
||||||
Value: 1.6,
|
Value: 1.6,
|
||||||
}
|
}
|
||||||
|
|
||||||
if !Evaluate(log.Log, ctx, condition) {
|
if !Evaluate(ctx, condition) {
|
||||||
t.Error("expected to pass")
|
t.Error("expected to pass")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -291,7 +290,7 @@ func Test_Eval_NoEqual_Const_float64_Fail(t *testing.T) {
|
||||||
Value: 1.5,
|
Value: 1.5,
|
||||||
}
|
}
|
||||||
|
|
||||||
if Evaluate(log.Log, ctx, condition) {
|
if Evaluate(ctx, condition) {
|
||||||
t.Error("expected to fail")
|
t.Error("expected to fail")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -321,7 +320,7 @@ func Test_Eval_Equal_Const_object_Pass(t *testing.T) {
|
||||||
Value: obj2,
|
Value: obj2,
|
||||||
}
|
}
|
||||||
|
|
||||||
if !Evaluate(log.Log, ctx, condition) {
|
if !Evaluate(ctx, condition) {
|
||||||
t.Error("expected to pass")
|
t.Error("expected to pass")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -349,7 +348,7 @@ func Test_Eval_Equal_Const_object_Fail(t *testing.T) {
|
||||||
Value: obj2,
|
Value: obj2,
|
||||||
}
|
}
|
||||||
|
|
||||||
if Evaluate(log.Log, ctx, condition) {
|
if Evaluate(ctx, condition) {
|
||||||
t.Error("expected to fail")
|
t.Error("expected to fail")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -377,7 +376,7 @@ func Test_Eval_NotEqual_Const_object_Pass(t *testing.T) {
|
||||||
Value: obj2,
|
Value: obj2,
|
||||||
}
|
}
|
||||||
|
|
||||||
if !Evaluate(log.Log, ctx, condition) {
|
if !Evaluate(ctx, condition) {
|
||||||
t.Error("expected to pass")
|
t.Error("expected to pass")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -405,7 +404,7 @@ func Test_Eval_NotEqual_Const_object_Fail(t *testing.T) {
|
||||||
Value: obj2,
|
Value: obj2,
|
||||||
}
|
}
|
||||||
|
|
||||||
if Evaluate(log.Log, ctx, condition) {
|
if Evaluate(ctx, condition) {
|
||||||
t.Error("expected to fail")
|
t.Error("expected to fail")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -435,7 +434,7 @@ func Test_Eval_Equal_Const_list_Pass(t *testing.T) {
|
||||||
Value: obj2,
|
Value: obj2,
|
||||||
}
|
}
|
||||||
|
|
||||||
if !Evaluate(log.Log, ctx, condition) {
|
if !Evaluate(ctx, condition) {
|
||||||
t.Error("expected to pass")
|
t.Error("expected to pass")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -461,7 +460,7 @@ func Test_Eval_Equal_Const_list_Fail(t *testing.T) {
|
||||||
Value: obj2,
|
Value: obj2,
|
||||||
}
|
}
|
||||||
|
|
||||||
if Evaluate(log.Log, ctx, condition) {
|
if Evaluate(ctx, condition) {
|
||||||
t.Error("expected to fail")
|
t.Error("expected to fail")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -487,7 +486,7 @@ func Test_Eval_NotEqual_Const_list_Pass(t *testing.T) {
|
||||||
Value: obj2,
|
Value: obj2,
|
||||||
}
|
}
|
||||||
|
|
||||||
if !Evaluate(log.Log, ctx, condition) {
|
if !Evaluate(ctx, condition) {
|
||||||
t.Error("expected to pass")
|
t.Error("expected to pass")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -513,7 +512,7 @@ func Test_Eval_NotEqual_Const_list_Fail(t *testing.T) {
|
||||||
Value: obj2,
|
Value: obj2,
|
||||||
}
|
}
|
||||||
|
|
||||||
if Evaluate(log.Log, ctx, condition) {
|
if Evaluate(ctx, condition) {
|
||||||
t.Error("expected to fail")
|
t.Error("expected to fail")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -546,7 +545,7 @@ func Test_Eval_Equal_Var_Pass(t *testing.T) {
|
||||||
Value: "temp",
|
Value: "temp",
|
||||||
}
|
}
|
||||||
|
|
||||||
if !Evaluate(log.Log, ctx, condition) {
|
if !Evaluate(ctx, condition) {
|
||||||
t.Error("expected to pass")
|
t.Error("expected to pass")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -577,7 +576,7 @@ func Test_Eval_Equal_Var_Fail(t *testing.T) {
|
||||||
Value: "temp1",
|
Value: "temp1",
|
||||||
}
|
}
|
||||||
|
|
||||||
if Evaluate(log.Log, ctx, condition) {
|
if Evaluate(ctx, condition) {
|
||||||
t.Error("expected to fail")
|
t.Error("expected to fail")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,19 @@
|
||||||
package operator
|
package operator
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"math"
|
"math"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
"github.com/golang/glog"
|
||||||
"github.com/nirmata/kyverno/pkg/engine/context"
|
"github.com/nirmata/kyverno/pkg/engine/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
//NewEqualHandler returns handler to manage Equal operations
|
//NewEqualHandler returns handler to manage Equal operations
|
||||||
func NewEqualHandler(log logr.Logger, ctx context.EvalInterface, subHandler VariableSubstitutionHandler) OperatorHandler {
|
func NewEqualHandler(ctx context.EvalInterface, subHandler VariableSubstitutionHandler) OperatorHandler {
|
||||||
return EqualHandler{
|
return EqualHandler{
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
subHandler: subHandler,
|
subHandler: subHandler,
|
||||||
log: log,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +21,6 @@ func NewEqualHandler(log logr.Logger, ctx context.EvalInterface, subHandler Vari
|
||||||
type EqualHandler struct {
|
type EqualHandler struct {
|
||||||
ctx context.EvalInterface
|
ctx context.EvalInterface
|
||||||
subHandler VariableSubstitutionHandler
|
subHandler VariableSubstitutionHandler
|
||||||
log logr.Logger
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Evaluate evaluates expression with Equal Operator
|
//Evaluate evaluates expression with Equal Operator
|
||||||
|
@ -31,14 +28,14 @@ func (eh EqualHandler) Evaluate(key, value interface{}) bool {
|
||||||
var err error
|
var err error
|
||||||
//TODO: decouple variables from evaluation
|
//TODO: decouple variables from evaluation
|
||||||
// substitute the variables
|
// substitute the variables
|
||||||
if key, err = eh.subHandler(eh.log, eh.ctx, key); err != nil {
|
if key, err = eh.subHandler(eh.ctx, key); err != nil {
|
||||||
// Failed to resolve the variable
|
// Failed to resolve the variable
|
||||||
eh.log.Error(err, "Failed to resolve variable", "variable", key)
|
glog.Infof("Failed to resolve variables in key: %s: %v", key, err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if value, err = eh.subHandler(eh.log, eh.ctx, value); err != nil {
|
if value, err = eh.subHandler(eh.ctx, value); err != nil {
|
||||||
// Failed to resolve the variable
|
// Failed to resolve the variable
|
||||||
eh.log.Error(err, "Failed to resolve variable", "variable", value)
|
glog.Infof("Failed to resolve variables in value: %s: %v", value, err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,7 +56,7 @@ func (eh EqualHandler) Evaluate(key, value interface{}) bool {
|
||||||
case []interface{}:
|
case []interface{}:
|
||||||
return eh.validateValueWithSlicePattern(typedKey, value)
|
return eh.validateValueWithSlicePattern(typedKey, value)
|
||||||
default:
|
default:
|
||||||
eh.log.Info("Unsupported type", "value", typedKey, "type", fmt.Sprintf("%T", typedKey))
|
glog.Errorf("Unsupported type %v", typedKey)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,7 +65,7 @@ func (eh EqualHandler) validateValueWithSlicePattern(key []interface{}, value in
|
||||||
if val, ok := value.([]interface{}); ok {
|
if val, ok := value.([]interface{}); ok {
|
||||||
return reflect.DeepEqual(key, val)
|
return reflect.DeepEqual(key, val)
|
||||||
}
|
}
|
||||||
eh.log.Info("Expected type []interface{}", "value", value, "type", fmt.Sprintf("%T", value))
|
glog.Warningf("Expected []interface{}, %v is of type %T", value, value)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,7 +73,7 @@ func (eh EqualHandler) validateValueWithMapPattern(key map[string]interface{}, v
|
||||||
if val, ok := value.(map[string]interface{}); ok {
|
if val, ok := value.(map[string]interface{}); ok {
|
||||||
return reflect.DeepEqual(key, val)
|
return reflect.DeepEqual(key, val)
|
||||||
}
|
}
|
||||||
eh.log.Info("Expected type map[string]interface{}", "value", value, "type", fmt.Sprintf("%T", value))
|
glog.Warningf("Expected map[string]interface{}, %v is of type %T", value, value)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,8 +81,7 @@ func (eh EqualHandler) validateValuewithStringPattern(key string, value interfac
|
||||||
if val, ok := value.(string); ok {
|
if val, ok := value.(string); ok {
|
||||||
return key == val
|
return key == val
|
||||||
}
|
}
|
||||||
|
glog.Warningf("Expected string, %v is of type %T", value, value)
|
||||||
eh.log.Info("Expected type string", "value", value, "type", fmt.Sprintf("%T", value))
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,25 +92,25 @@ func (eh EqualHandler) validateValuewithFloatPattern(key float64, value interfac
|
||||||
if key == math.Trunc(key) {
|
if key == math.Trunc(key) {
|
||||||
return int(key) == typedValue
|
return int(key) == typedValue
|
||||||
}
|
}
|
||||||
eh.log.Info("Expected type float, found int", "typedValue", typedValue)
|
glog.Warningf("Expected float, found int: %d\n", typedValue)
|
||||||
case int64:
|
case int64:
|
||||||
// check that float has not fraction
|
// check that float has not fraction
|
||||||
if key == math.Trunc(key) {
|
if key == math.Trunc(key) {
|
||||||
return int64(key) == typedValue
|
return int64(key) == typedValue
|
||||||
}
|
}
|
||||||
eh.log.Info("Expected type float, found int", "typedValue", typedValue)
|
glog.Warningf("Expected float, found int: %d\n", typedValue)
|
||||||
case float64:
|
case float64:
|
||||||
return typedValue == key
|
return typedValue == key
|
||||||
case string:
|
case string:
|
||||||
// extract float from string
|
// extract float from string
|
||||||
float64Num, err := strconv.ParseFloat(typedValue, 64)
|
float64Num, err := strconv.ParseFloat(typedValue, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
eh.log.Error(err, "Failed to parse float64 from string")
|
glog.Warningf("Failed to parse float64 from string: %v", err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return float64Num == key
|
return float64Num == key
|
||||||
default:
|
default:
|
||||||
eh.log.Info("Expected type float", "value", value, "type", fmt.Sprintf("%T", value))
|
glog.Warningf("Expected float, found: %T\n", value)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
@ -123,7 +119,7 @@ func (eh EqualHandler) validateValuewithFloatPattern(key float64, value interfac
|
||||||
func (eh EqualHandler) validateValuewithBoolPattern(key bool, value interface{}) bool {
|
func (eh EqualHandler) validateValuewithBoolPattern(key bool, value interface{}) bool {
|
||||||
typedValue, ok := value.(bool)
|
typedValue, ok := value.(bool)
|
||||||
if !ok {
|
if !ok {
|
||||||
eh.log.Info("Expected type bool", "value", value, "type", fmt.Sprintf("%T", value))
|
glog.Error("Expected bool, found %V", value)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return key == typedValue
|
return key == typedValue
|
||||||
|
@ -140,18 +136,18 @@ func (eh EqualHandler) validateValuewithIntPattern(key int64, value interface{})
|
||||||
if typedValue == math.Trunc(typedValue) {
|
if typedValue == math.Trunc(typedValue) {
|
||||||
return int64(typedValue) == key
|
return int64(typedValue) == key
|
||||||
}
|
}
|
||||||
eh.log.Info("Expected type int, found float", "value", typedValue, "type", fmt.Sprintf("%T", typedValue))
|
glog.Warningf("Expected int, found float: %f", typedValue)
|
||||||
return false
|
return false
|
||||||
case string:
|
case string:
|
||||||
// extract in64 from string
|
// extract in64 from string
|
||||||
int64Num, err := strconv.ParseInt(typedValue, 10, 64)
|
int64Num, err := strconv.ParseInt(typedValue, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
eh.log.Error(err, "Failed to parse int64 from string")
|
glog.Warningf("Failed to parse int64 from string: %v", err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return int64Num == key
|
return int64Num == key
|
||||||
default:
|
default:
|
||||||
eh.log.Info("Expected type int", "value", value, "type", fmt.Sprintf("%T", value))
|
glog.Warningf("Expected int, %v is of type %T", value, value)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,19 @@
|
||||||
package operator
|
package operator
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"math"
|
"math"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
"github.com/golang/glog"
|
||||||
"github.com/nirmata/kyverno/pkg/engine/context"
|
"github.com/nirmata/kyverno/pkg/engine/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
//NewNotEqualHandler returns handler to manage NotEqual operations
|
//NewNotEqualHandler returns handler to manage NotEqual operations
|
||||||
func NewNotEqualHandler(log logr.Logger, ctx context.EvalInterface, subHandler VariableSubstitutionHandler) OperatorHandler {
|
func NewNotEqualHandler(ctx context.EvalInterface, subHandler VariableSubstitutionHandler) OperatorHandler {
|
||||||
return NotEqualHandler{
|
return NotEqualHandler{
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
subHandler: subHandler,
|
subHandler: subHandler,
|
||||||
log: log,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +21,6 @@ func NewNotEqualHandler(log logr.Logger, ctx context.EvalInterface, subHandler V
|
||||||
type NotEqualHandler struct {
|
type NotEqualHandler struct {
|
||||||
ctx context.EvalInterface
|
ctx context.EvalInterface
|
||||||
subHandler VariableSubstitutionHandler
|
subHandler VariableSubstitutionHandler
|
||||||
log logr.Logger
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Evaluate evaluates expression with NotEqual Operator
|
//Evaluate evaluates expression with NotEqual Operator
|
||||||
|
@ -31,14 +28,14 @@ func (neh NotEqualHandler) Evaluate(key, value interface{}) bool {
|
||||||
var err error
|
var err error
|
||||||
//TODO: decouple variables from evaluation
|
//TODO: decouple variables from evaluation
|
||||||
// substitute the variables
|
// substitute the variables
|
||||||
if key, err = neh.subHandler(neh.log, neh.ctx, key); err != nil {
|
if key, err = neh.subHandler(neh.ctx, key); err != nil {
|
||||||
// Failed to resolve the variable
|
// Failed to resolve the variable
|
||||||
neh.log.Error(err, "Failed to resolve variable", "variable", key)
|
glog.Infof("Failed to resolve variables in key: %s: %v", key, err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if value, err = neh.subHandler(neh.log, neh.ctx, value); err != nil {
|
if value, err = neh.subHandler(neh.ctx, value); err != nil {
|
||||||
// Failed to resolve the variable
|
// Failed to resolve the variable
|
||||||
neh.log.Error(err, "Failed to resolve variable", "variable", value)
|
glog.Infof("Failed to resolve variables in value: %s: %v", value, err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
// key and value need to be of same type
|
// key and value need to be of same type
|
||||||
|
@ -58,7 +55,7 @@ func (neh NotEqualHandler) Evaluate(key, value interface{}) bool {
|
||||||
case []interface{}:
|
case []interface{}:
|
||||||
return neh.validateValueWithSlicePattern(typedKey, value)
|
return neh.validateValueWithSlicePattern(typedKey, value)
|
||||||
default:
|
default:
|
||||||
neh.log.Info("Unsupported type", "value", typedKey, "type", fmt.Sprintf("%T", typedKey))
|
glog.Error("Unsupported type %V", typedKey)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,7 +64,7 @@ func (neh NotEqualHandler) validateValueWithSlicePattern(key []interface{}, valu
|
||||||
if val, ok := value.([]interface{}); ok {
|
if val, ok := value.([]interface{}); ok {
|
||||||
return !reflect.DeepEqual(key, val)
|
return !reflect.DeepEqual(key, val)
|
||||||
}
|
}
|
||||||
neh.log.Info("Expected type []interface{}", "value", value, "type", fmt.Sprintf("%T", value))
|
glog.Warningf("Expected []interface{}, %v is of type %T", value, value)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,7 +72,7 @@ func (neh NotEqualHandler) validateValueWithMapPattern(key map[string]interface{
|
||||||
if val, ok := value.(map[string]interface{}); ok {
|
if val, ok := value.(map[string]interface{}); ok {
|
||||||
return !reflect.DeepEqual(key, val)
|
return !reflect.DeepEqual(key, val)
|
||||||
}
|
}
|
||||||
neh.log.Info("Expected type map[string]interface{}", "value", value, "type", fmt.Sprintf("%T", value))
|
glog.Warningf("Expected map[string]interface{}, %v is of type %T", value, value)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,7 +80,7 @@ func (neh NotEqualHandler) validateValuewithStringPattern(key string, value inte
|
||||||
if val, ok := value.(string); ok {
|
if val, ok := value.(string); ok {
|
||||||
return key != val
|
return key != val
|
||||||
}
|
}
|
||||||
neh.log.Info("Expected type string", "value", value, "type", fmt.Sprintf("%T", value))
|
glog.Warningf("Expected string, %v is of type %T", value, value)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,25 +91,25 @@ func (neh NotEqualHandler) validateValuewithFloatPattern(key float64, value inte
|
||||||
if key == math.Trunc(key) {
|
if key == math.Trunc(key) {
|
||||||
return int(key) != typedValue
|
return int(key) != typedValue
|
||||||
}
|
}
|
||||||
neh.log.Info("Expected type float, found int", "typedValue", typedValue)
|
glog.Warningf("Expected float, found int: %d\n", typedValue)
|
||||||
case int64:
|
case int64:
|
||||||
// check that float has not fraction
|
// check that float has not fraction
|
||||||
if key == math.Trunc(key) {
|
if key == math.Trunc(key) {
|
||||||
return int64(key) != typedValue
|
return int64(key) != typedValue
|
||||||
}
|
}
|
||||||
neh.log.Info("Expected type float, found int", "typedValue", typedValue)
|
glog.Warningf("Expected float, found int: %d\n", typedValue)
|
||||||
case float64:
|
case float64:
|
||||||
return typedValue != key
|
return typedValue != key
|
||||||
case string:
|
case string:
|
||||||
// extract float from string
|
// extract float from string
|
||||||
float64Num, err := strconv.ParseFloat(typedValue, 64)
|
float64Num, err := strconv.ParseFloat(typedValue, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
neh.log.Error(err, "Failed to parse float64 from string")
|
glog.Warningf("Failed to parse float64 from string: %v", err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return float64Num != key
|
return float64Num != key
|
||||||
default:
|
default:
|
||||||
neh.log.Info("Expected type float", "value", value, "type", fmt.Sprintf("%T", value))
|
glog.Warningf("Expected float, found: %T\n", value)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
@ -121,7 +118,7 @@ func (neh NotEqualHandler) validateValuewithFloatPattern(key float64, value inte
|
||||||
func (neh NotEqualHandler) validateValuewithBoolPattern(key bool, value interface{}) bool {
|
func (neh NotEqualHandler) validateValuewithBoolPattern(key bool, value interface{}) bool {
|
||||||
typedValue, ok := value.(bool)
|
typedValue, ok := value.(bool)
|
||||||
if !ok {
|
if !ok {
|
||||||
neh.log.Info("Expected type bool", "value", value, "type", fmt.Sprintf("%T", value))
|
glog.Error("Expected bool, found %V", value)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return key != typedValue
|
return key != typedValue
|
||||||
|
@ -138,18 +135,18 @@ func (neh NotEqualHandler) validateValuewithIntPattern(key int64, value interfac
|
||||||
if typedValue == math.Trunc(typedValue) {
|
if typedValue == math.Trunc(typedValue) {
|
||||||
return int64(typedValue) != key
|
return int64(typedValue) != key
|
||||||
}
|
}
|
||||||
neh.log.Info("Expected type int, found float", "value", typedValue, "type", fmt.Sprintf("%T", typedValue))
|
glog.Warningf("Expected int, found float: %f\n", typedValue)
|
||||||
return false
|
return false
|
||||||
case string:
|
case string:
|
||||||
// extract in64 from string
|
// extract in64 from string
|
||||||
int64Num, err := strconv.ParseInt(typedValue, 10, 64)
|
int64Num, err := strconv.ParseInt(typedValue, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
neh.log.Error(err, "Failed to parse int64 from string")
|
glog.Warningf("Failed to parse int64 from string: %v", err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return int64Num != key
|
return int64Num != key
|
||||||
default:
|
default:
|
||||||
neh.log.Info("Expected type int", "value", value, "type", fmt.Sprintf("%T", value))
|
glog.Warningf("Expected int, %v is of type %T", value, value)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package operator
|
package operator
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/go-logr/logr"
|
"github.com/golang/glog"
|
||||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||||
"github.com/nirmata/kyverno/pkg/engine/context"
|
"github.com/nirmata/kyverno/pkg/engine/context"
|
||||||
)
|
)
|
||||||
|
@ -17,17 +17,17 @@ type OperatorHandler interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
//VariableSubstitutionHandler defines the handler function for variable substitution
|
//VariableSubstitutionHandler defines the handler function for variable substitution
|
||||||
type VariableSubstitutionHandler = func(log logr.Logger, ctx context.EvalInterface, pattern interface{}) (interface{}, error)
|
type VariableSubstitutionHandler = func(ctx context.EvalInterface, pattern interface{}) (interface{}, error)
|
||||||
|
|
||||||
//CreateOperatorHandler returns the operator handler based on the operator used in condition
|
//CreateOperatorHandler returns the operator handler based on the operator used in condition
|
||||||
func CreateOperatorHandler(log logr.Logger, ctx context.EvalInterface, op kyverno.ConditionOperator, subHandler VariableSubstitutionHandler) OperatorHandler {
|
func CreateOperatorHandler(ctx context.EvalInterface, op kyverno.ConditionOperator, subHandler VariableSubstitutionHandler) OperatorHandler {
|
||||||
switch op {
|
switch op {
|
||||||
case kyverno.Equal:
|
case kyverno.Equal:
|
||||||
return NewEqualHandler(log, ctx, subHandler)
|
return NewEqualHandler(ctx, subHandler)
|
||||||
case kyverno.NotEqual:
|
case kyverno.NotEqual:
|
||||||
return NewNotEqualHandler(log, ctx, subHandler)
|
return NewNotEqualHandler(ctx, subHandler)
|
||||||
default:
|
default:
|
||||||
log.Info("operator not supported", "operator", string(op))
|
glog.Errorf("unsupported operator: %s", string(op))
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ import (
|
||||||
|
|
||||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||||
authenticationv1 "k8s.io/api/authentication/v1"
|
authenticationv1 "k8s.io/api/authentication/v1"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
|
||||||
|
|
||||||
"github.com/nirmata/kyverno/pkg/engine/context"
|
"github.com/nirmata/kyverno/pkg/engine/context"
|
||||||
)
|
)
|
||||||
|
@ -85,7 +84,7 @@ func Test_variablesub1(t *testing.T) {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := SubstituteVars(log.Log, ctx, patternCopy); err != nil {
|
if _, err := SubstituteVars(ctx, patternCopy); err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
resultRaw, err := json.Marshal(patternCopy)
|
resultRaw, err := json.Marshal(patternCopy)
|
||||||
|
@ -175,7 +174,7 @@ func Test_variablesub_multiple(t *testing.T) {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := SubstituteVars(log.Log, ctx, patternCopy); err != nil {
|
if _, err := SubstituteVars(ctx, patternCopy); err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
resultRaw, err := json.Marshal(patternCopy)
|
resultRaw, err := json.Marshal(patternCopy)
|
||||||
|
@ -262,7 +261,7 @@ func Test_variablesubstitution(t *testing.T) {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := SubstituteVars(log.Log, ctx, patternCopy); err != nil {
|
if _, err := SubstituteVars(ctx, patternCopy); err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
resultRaw, err := json.Marshal(patternCopy)
|
resultRaw, err := json.Marshal(patternCopy)
|
||||||
|
@ -323,7 +322,7 @@ func Test_variableSubstitutionValue(t *testing.T) {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := SubstituteVars(log.Log, ctx, patternCopy); err != nil {
|
if _, err := SubstituteVars(ctx, patternCopy); err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
resultRaw, err := json.Marshal(patternCopy)
|
resultRaw, err := json.Marshal(patternCopy)
|
||||||
|
@ -381,7 +380,7 @@ func Test_variableSubstitutionValueOperatorNotEqual(t *testing.T) {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := SubstituteVars(log.Log, ctx, patternCopy); err != nil {
|
if _, err := SubstituteVars(ctx, patternCopy); err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
resultRaw, err := json.Marshal(patternCopy)
|
resultRaw, err := json.Marshal(patternCopy)
|
||||||
|
@ -440,7 +439,7 @@ func Test_variableSubstitutionValueFail(t *testing.T) {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := SubstituteVars(log.Log, ctx, patternCopy); err == nil {
|
if _, err := SubstituteVars(ctx, patternCopy); err == nil {
|
||||||
t.Log("expected to fails")
|
t.Log("expected to fails")
|
||||||
t.Fail()
|
t.Fail()
|
||||||
}
|
}
|
||||||
|
@ -498,7 +497,7 @@ func Test_variableSubstitutionObject(t *testing.T) {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := SubstituteVars(log.Log, ctx, patternCopy); err != nil {
|
if _, err := SubstituteVars(ctx, patternCopy); err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
resultRaw, err := json.Marshal(patternCopy)
|
resultRaw, err := json.Marshal(patternCopy)
|
||||||
|
@ -562,7 +561,7 @@ func Test_variableSubstitutionObjectOperatorNotEqualFail(t *testing.T) {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := SubstituteVars(log.Log, ctx, patternCopy); err == nil {
|
if _, err := SubstituteVars(ctx, patternCopy); err == nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -621,7 +620,7 @@ func Test_variableSubstitutionMultipleObject(t *testing.T) {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := SubstituteVars(log.Log, ctx, patternCopy); err != nil {
|
if _, err := SubstituteVars(ctx, patternCopy); err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
resultRaw, err := json.Marshal(patternCopy)
|
resultRaw, err := json.Marshal(patternCopy)
|
||||||
|
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
"github.com/golang/glog"
|
||||||
"github.com/nirmata/kyverno/pkg/engine/context"
|
"github.com/nirmata/kyverno/pkg/engine/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -17,9 +17,9 @@ const (
|
||||||
|
|
||||||
//SubstituteVars replaces the variables with the values defined in the context
|
//SubstituteVars replaces the variables with the values defined in the context
|
||||||
// - if any variable is invaid or has nil value, it is considered as a failed varable substitution
|
// - if any variable is invaid or has nil value, it is considered as a failed varable substitution
|
||||||
func SubstituteVars(log logr.Logger, ctx context.EvalInterface, pattern interface{}) (interface{}, error) {
|
func SubstituteVars(ctx context.EvalInterface, pattern interface{}) (interface{}, error) {
|
||||||
errs := []error{}
|
errs := []error{}
|
||||||
pattern = subVars(log, ctx, pattern, "", &errs)
|
pattern = subVars(ctx, pattern, "", &errs)
|
||||||
if len(errs) == 0 {
|
if len(errs) == 0 {
|
||||||
// no error while parsing the pattern
|
// no error while parsing the pattern
|
||||||
return pattern, nil
|
return pattern, nil
|
||||||
|
@ -27,40 +27,40 @@ func SubstituteVars(log logr.Logger, ctx context.EvalInterface, pattern interfac
|
||||||
return pattern, fmt.Errorf("%v", errs)
|
return pattern, fmt.Errorf("%v", errs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func subVars(log logr.Logger, ctx context.EvalInterface, pattern interface{}, path string, errs *[]error) interface{} {
|
func subVars(ctx context.EvalInterface, pattern interface{}, path string, errs *[]error) interface{} {
|
||||||
switch typedPattern := pattern.(type) {
|
switch typedPattern := pattern.(type) {
|
||||||
case map[string]interface{}:
|
case map[string]interface{}:
|
||||||
return subMap(log, ctx, typedPattern, path, errs)
|
return subMap(ctx, typedPattern, path, errs)
|
||||||
case []interface{}:
|
case []interface{}:
|
||||||
return subArray(log, ctx, typedPattern, path, errs)
|
return subArray(ctx, typedPattern, path, errs)
|
||||||
case string:
|
case string:
|
||||||
return subValR(log, ctx, typedPattern, path, errs)
|
return subValR(ctx, typedPattern, path, errs)
|
||||||
default:
|
default:
|
||||||
return pattern
|
return pattern
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func subMap(log logr.Logger, ctx context.EvalInterface, patternMap map[string]interface{}, path string, errs *[]error) map[string]interface{} {
|
func subMap(ctx context.EvalInterface, patternMap map[string]interface{}, path string, errs *[]error) map[string]interface{} {
|
||||||
for key, patternElement := range patternMap {
|
for key, patternElement := range patternMap {
|
||||||
curPath := path + "/" + key
|
curPath := path + "/" + key
|
||||||
value := subVars(log, ctx, patternElement, curPath, errs)
|
value := subVars(ctx, patternElement, curPath, errs)
|
||||||
patternMap[key] = value
|
patternMap[key] = value
|
||||||
|
|
||||||
}
|
}
|
||||||
return patternMap
|
return patternMap
|
||||||
}
|
}
|
||||||
|
|
||||||
func subArray(log logr.Logger, ctx context.EvalInterface, patternList []interface{}, path string, errs *[]error) []interface{} {
|
func subArray(ctx context.EvalInterface, patternList []interface{}, path string, errs *[]error) []interface{} {
|
||||||
for idx, patternElement := range patternList {
|
for idx, patternElement := range patternList {
|
||||||
curPath := path + "/" + strconv.Itoa(idx)
|
curPath := path + "/" + strconv.Itoa(idx)
|
||||||
value := subVars(log, ctx, patternElement, curPath, errs)
|
value := subVars(ctx, patternElement, curPath, errs)
|
||||||
patternList[idx] = value
|
patternList[idx] = value
|
||||||
}
|
}
|
||||||
return patternList
|
return patternList
|
||||||
}
|
}
|
||||||
|
|
||||||
// subValR resolves the variables if defined
|
// subValR resolves the variables if defined
|
||||||
func subValR(log logr.Logger, ctx context.EvalInterface, valuePattern string, path string, errs *[]error) interface{} {
|
func subValR(ctx context.EvalInterface, valuePattern string, path string, errs *[]error) interface{} {
|
||||||
|
|
||||||
// variable values can be scalar values(string,int, float) or they can be obects(map,slice)
|
// variable values can be scalar values(string,int, float) or they can be obects(map,slice)
|
||||||
// - {{variable}}
|
// - {{variable}}
|
||||||
|
@ -73,7 +73,7 @@ func subValR(log logr.Logger, ctx context.EvalInterface, valuePattern string, pa
|
||||||
// since this might be a potential place for error, required better error reporting and handling
|
// since this might be a potential place for error, required better error reporting and handling
|
||||||
|
|
||||||
// object values are only suported for single variable substitution
|
// object values are only suported for single variable substitution
|
||||||
if ok, retVal := processIfSingleVariable(log, ctx, valuePattern, path, errs); ok {
|
if ok, retVal := processIfSingleVariable(ctx, valuePattern, path, errs); ok {
|
||||||
return retVal
|
return retVal
|
||||||
}
|
}
|
||||||
// var emptyInterface interface{}
|
// var emptyInterface interface{}
|
||||||
|
@ -82,7 +82,7 @@ func subValR(log logr.Logger, ctx context.EvalInterface, valuePattern string, pa
|
||||||
for {
|
for {
|
||||||
valueStr := valuePattern
|
valueStr := valuePattern
|
||||||
if len(failedVars) != 0 {
|
if len(failedVars) != 0 {
|
||||||
log.Info("failed to resolve variablesl short-circuiting")
|
glog.Info("some failed variables short-circuiting")
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
// get variables at this level
|
// get variables at this level
|
||||||
|
@ -123,7 +123,7 @@ func subValR(log logr.Logger, ctx context.EvalInterface, valuePattern string, pa
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// if type is not scalar then consider this as a failed variable
|
// if type is not scalar then consider this as a failed variable
|
||||||
log.Info("variable resolves to non-scalar value. Non-Scalar values are not supported for nested variables", "variable", k, "value", v)
|
glog.Infof("variable %s resolves to non-scalar value %v. Non-Scalar values are not supported for nested variables", k, v)
|
||||||
failedVars = append(failedVars, k)
|
failedVars = append(failedVars, k)
|
||||||
}
|
}
|
||||||
valuePattern = newVal
|
valuePattern = newVal
|
||||||
|
@ -143,10 +143,10 @@ func subValR(log logr.Logger, ctx context.EvalInterface, valuePattern string, pa
|
||||||
// if the value can be evaluted return the value
|
// if the value can be evaluted return the value
|
||||||
// -> return value can be scalar or object type
|
// -> return value can be scalar or object type
|
||||||
// -> if the variable is not present in the context then add an error and dont process further
|
// -> if the variable is not present in the context then add an error and dont process further
|
||||||
func processIfSingleVariable(log logr.Logger, ctx context.EvalInterface, valuePattern interface{}, path string, errs *[]error) (bool, interface{}) {
|
func processIfSingleVariable(ctx context.EvalInterface, valuePattern interface{}, path string, errs *[]error) (bool, interface{}) {
|
||||||
valueStr, ok := valuePattern.(string)
|
valueStr, ok := valuePattern.(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Info("failed to convert to string", "pattern", valuePattern)
|
glog.Infof("failed to convert %v to string", valuePattern)
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
// get variables at this level
|
// get variables at this level
|
||||||
|
|
|
@ -6,7 +6,6 @@ import (
|
||||||
|
|
||||||
"github.com/nirmata/kyverno/pkg/engine/context"
|
"github.com/nirmata/kyverno/pkg/engine/context"
|
||||||
"gotest.tools/assert"
|
"gotest.tools/assert"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_subVars_success(t *testing.T) {
|
func Test_subVars_success(t *testing.T) {
|
||||||
|
@ -65,7 +64,7 @@ func Test_subVars_success(t *testing.T) {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := SubstituteVars(log.Log, ctx, pattern); err != nil {
|
if _, err := SubstituteVars(ctx, pattern); err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,7 +125,7 @@ func Test_subVars_failed(t *testing.T) {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := SubstituteVars(log.Log, ctx, pattern); err == nil {
|
if _, err := SubstituteVars(ctx, pattern); err == nil {
|
||||||
t.Error("error is expected")
|
t.Error("error is expected")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -153,5 +152,5 @@ func Test_SubvarRecursive(t *testing.T) {
|
||||||
ctx := context.NewContext()
|
ctx := context.NewContext()
|
||||||
assert.Assert(t, ctx.AddResource(resourceRaw))
|
assert.Assert(t, ctx.AddResource(resourceRaw))
|
||||||
errs := []error{}
|
errs := []error{}
|
||||||
subValR(log.Log, ctx, string(patternRaw), "/", &errs)
|
subValR(ctx, string(patternRaw), "/", &errs)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ package event
|
||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
"github.com/golang/glog"
|
||||||
|
|
||||||
"github.com/nirmata/kyverno/pkg/client/clientset/versioned/scheme"
|
"github.com/nirmata/kyverno/pkg/client/clientset/versioned/scheme"
|
||||||
kyvernoinformer "github.com/nirmata/kyverno/pkg/client/informers/externalversions/kyverno/v1"
|
kyvernoinformer "github.com/nirmata/kyverno/pkg/client/informers/externalversions/kyverno/v1"
|
||||||
|
@ -17,7 +17,6 @@ import (
|
||||||
"k8s.io/client-go/tools/cache"
|
"k8s.io/client-go/tools/cache"
|
||||||
"k8s.io/client-go/tools/record"
|
"k8s.io/client-go/tools/record"
|
||||||
"k8s.io/client-go/util/workqueue"
|
"k8s.io/client-go/util/workqueue"
|
||||||
"k8s.io/klog"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
//Generator generate events
|
//Generator generate events
|
||||||
|
@ -35,7 +34,6 @@ type Generator struct {
|
||||||
admissionCtrRecorder record.EventRecorder
|
admissionCtrRecorder record.EventRecorder
|
||||||
// events generated at namespaced policy controller to process 'generate' rule
|
// events generated at namespaced policy controller to process 'generate' rule
|
||||||
genPolicyRecorder record.EventRecorder
|
genPolicyRecorder record.EventRecorder
|
||||||
log logr.Logger
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Interface to generate event
|
//Interface to generate event
|
||||||
|
@ -44,33 +42,32 @@ type Interface interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
//NewEventGenerator to generate a new event controller
|
//NewEventGenerator to generate a new event controller
|
||||||
func NewEventGenerator(client *client.Client, pInformer kyvernoinformer.ClusterPolicyInformer, log logr.Logger) *Generator {
|
func NewEventGenerator(client *client.Client, pInformer kyvernoinformer.ClusterPolicyInformer) *Generator {
|
||||||
|
|
||||||
gen := Generator{
|
gen := Generator{
|
||||||
client: client,
|
client: client,
|
||||||
pLister: pInformer.Lister(),
|
pLister: pInformer.Lister(),
|
||||||
queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), eventWorkQueueName),
|
queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), eventWorkQueueName),
|
||||||
pSynced: pInformer.Informer().HasSynced,
|
pSynced: pInformer.Informer().HasSynced,
|
||||||
policyCtrRecorder: initRecorder(client, PolicyController, log),
|
policyCtrRecorder: initRecorder(client, PolicyController),
|
||||||
admissionCtrRecorder: initRecorder(client, AdmissionController, log),
|
admissionCtrRecorder: initRecorder(client, AdmissionController),
|
||||||
genPolicyRecorder: initRecorder(client, GeneratePolicyController, log),
|
genPolicyRecorder: initRecorder(client, GeneratePolicyController),
|
||||||
log: log,
|
|
||||||
}
|
}
|
||||||
return &gen
|
return &gen
|
||||||
}
|
}
|
||||||
|
|
||||||
func initRecorder(client *client.Client, eventSource Source, log logr.Logger) record.EventRecorder {
|
func initRecorder(client *client.Client, eventSource Source) record.EventRecorder {
|
||||||
// Initliaze Event Broadcaster
|
// Initliaze Event Broadcaster
|
||||||
err := scheme.AddToScheme(scheme.Scheme)
|
err := scheme.AddToScheme(scheme.Scheme)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err, "failed to add to scheme")
|
glog.Error(err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
eventBroadcaster := record.NewBroadcaster()
|
eventBroadcaster := record.NewBroadcaster()
|
||||||
eventBroadcaster.StartLogging(klog.Infof)
|
eventBroadcaster.StartLogging(glog.V(4).Infof)
|
||||||
eventInterface, err := client.GetEventsInterface()
|
eventInterface, err := client.GetEventsInterface()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err, "failed to get event interface for logging")
|
glog.Error(err) // TODO: add more specific error
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
eventBroadcaster.StartRecordingToSink(
|
eventBroadcaster.StartRecordingToSink(
|
||||||
|
@ -84,12 +81,11 @@ func initRecorder(client *client.Client, eventSource Source, log logr.Logger) re
|
||||||
|
|
||||||
//Add queues an event for generation
|
//Add queues an event for generation
|
||||||
func (gen *Generator) Add(infos ...Info) {
|
func (gen *Generator) Add(infos ...Info) {
|
||||||
logger := gen.log
|
|
||||||
for _, info := range infos {
|
for _, info := range infos {
|
||||||
if info.Name == "" {
|
if info.Name == "" {
|
||||||
// dont create event for resources with generateName
|
// dont create event for resources with generateName
|
||||||
// as the name is not generated yet
|
// as the name is not generated yet
|
||||||
logger.V(4).Info("not creating an event as the resource has not been assigned a name yet", "kind", info.Kind, "name", info.Name, "namespace", info.Namespace)
|
glog.V(4).Infof("received info %v, not creating an event as the resource has not been assigned a name yet", info)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
gen.queue.Add(info)
|
gen.queue.Add(info)
|
||||||
|
@ -98,14 +94,12 @@ func (gen *Generator) Add(infos ...Info) {
|
||||||
|
|
||||||
// Run begins generator
|
// Run begins generator
|
||||||
func (gen *Generator) Run(workers int, stopCh <-chan struct{}) {
|
func (gen *Generator) Run(workers int, stopCh <-chan struct{}) {
|
||||||
logger := gen.log
|
|
||||||
defer utilruntime.HandleCrash()
|
defer utilruntime.HandleCrash()
|
||||||
|
glog.Info("Starting event generator")
|
||||||
logger.Info("start")
|
defer glog.Info("Shutting down event generator")
|
||||||
defer logger.Info("shutting down")
|
|
||||||
|
|
||||||
if !cache.WaitForCacheSync(stopCh, gen.pSynced) {
|
if !cache.WaitForCacheSync(stopCh, gen.pSynced) {
|
||||||
logger.Info("failed to sync informer cache")
|
glog.Error("event generator: failed to sync informer cache")
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < workers; i++ {
|
for i := 0; i < workers; i++ {
|
||||||
|
@ -120,25 +114,24 @@ func (gen *Generator) runWorker() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gen *Generator) handleErr(err error, key interface{}) {
|
func (gen *Generator) handleErr(err error, key interface{}) {
|
||||||
logger := gen.log
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
gen.queue.Forget(key)
|
gen.queue.Forget(key)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// This controller retries if something goes wrong. After that, it stops trying.
|
// This controller retries if something goes wrong. After that, it stops trying.
|
||||||
if gen.queue.NumRequeues(key) < workQueueRetryLimit {
|
if gen.queue.NumRequeues(key) < workQueueRetryLimit {
|
||||||
logger.Error(err, "Error syncing events;re-queuing request,the resource might not have been created yet", "key", key)
|
glog.Warningf("Error syncing events %v(re-queuing request, the resource might not have been created yet): %v", key, err)
|
||||||
// Re-enqueue the key rate limited. Based on the rate limiter on the
|
// Re-enqueue the key rate limited. Based on the rate limiter on the
|
||||||
// queue and the re-enqueue history, the key will be processed later again.
|
// queue and the re-enqueue history, the key will be processed later again.
|
||||||
gen.queue.AddRateLimited(key)
|
gen.queue.AddRateLimited(key)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
gen.queue.Forget(key)
|
gen.queue.Forget(key)
|
||||||
logger.Error(err, "dropping the key out of queue", "key", key)
|
glog.Error(err)
|
||||||
|
glog.Warningf("Dropping the key out of the queue: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gen *Generator) processNextWorkItem() bool {
|
func (gen *Generator) processNextWorkItem() bool {
|
||||||
logger := gen.log
|
|
||||||
obj, shutdown := gen.queue.Get()
|
obj, shutdown := gen.queue.Get()
|
||||||
if shutdown {
|
if shutdown {
|
||||||
return false
|
return false
|
||||||
|
@ -151,7 +144,7 @@ func (gen *Generator) processNextWorkItem() bool {
|
||||||
|
|
||||||
if key, ok = obj.(Info); !ok {
|
if key, ok = obj.(Info); !ok {
|
||||||
gen.queue.Forget(obj)
|
gen.queue.Forget(obj)
|
||||||
logger.Info("Incorrect type; expected type 'info'", "obj", obj)
|
glog.Warningf("Expecting type info by got %v\n", obj)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
err := gen.syncHandler(key)
|
err := gen.syncHandler(key)
|
||||||
|
@ -159,14 +152,13 @@ func (gen *Generator) processNextWorkItem() bool {
|
||||||
return nil
|
return nil
|
||||||
}(obj)
|
}(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "failed to process next work item")
|
glog.Error(err)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gen *Generator) syncHandler(key Info) error {
|
func (gen *Generator) syncHandler(key Info) error {
|
||||||
logger := gen.log
|
|
||||||
var robj runtime.Object
|
var robj runtime.Object
|
||||||
var err error
|
var err error
|
||||||
switch key.Kind {
|
switch key.Kind {
|
||||||
|
@ -174,13 +166,13 @@ func (gen *Generator) syncHandler(key Info) error {
|
||||||
//TODO: policy is clustered resource so wont need namespace
|
//TODO: policy is clustered resource so wont need namespace
|
||||||
robj, err = gen.pLister.Get(key.Name)
|
robj, err = gen.pLister.Get(key.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "failed to get policy", "name", key.Name)
|
glog.V(4).Infof("Error creating event: unable to get policy %s, will retry ", key.Name)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
robj, err = gen.client.GetResource(key.Kind, key.Namespace, key.Name)
|
robj, err = gen.client.GetResource(key.Kind, key.Namespace, key.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "failed to get resource", "kind", key.Kind, "name", key.Name, "namespace", key.Namespace)
|
glog.V(4).Infof("Error creating event: unable to get resource %s/%s/%s, will retry ", key.Kind, key.Namespace, key.Name)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -200,14 +192,13 @@ func (gen *Generator) syncHandler(key Info) error {
|
||||||
case GeneratePolicyController:
|
case GeneratePolicyController:
|
||||||
gen.genPolicyRecorder.Event(robj, eventType, key.Reason, key.Message)
|
gen.genPolicyRecorder.Event(robj, eventType, key.Reason, key.Message)
|
||||||
default:
|
default:
|
||||||
logger.Info("info.source not defined for the request")
|
glog.Info("info.source not defined for the event generator request")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//NewEvent builds a event creation request
|
//NewEvent builds a event creation request
|
||||||
func NewEvent(
|
func NewEvent(
|
||||||
log logr.Logger,
|
|
||||||
rkind,
|
rkind,
|
||||||
rapiVersion,
|
rapiVersion,
|
||||||
rnamespace,
|
rnamespace,
|
||||||
|
@ -218,7 +209,7 @@ func NewEvent(
|
||||||
args ...interface{}) Info {
|
args ...interface{}) Info {
|
||||||
msgText, err := getEventMsg(message, args...)
|
msgText, err := getEventMsg(message, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err, "failed to get event message")
|
glog.Error(err)
|
||||||
}
|
}
|
||||||
return Info{
|
return Info{
|
||||||
Kind: rkind,
|
Kind: rkind,
|
||||||
|
|
|
@ -1,20 +1,19 @@
|
||||||
package cleanup
|
package cleanup
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/go-logr/logr"
|
"github.com/golang/glog"
|
||||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||||
dclient "github.com/nirmata/kyverno/pkg/dclient"
|
dclient "github.com/nirmata/kyverno/pkg/dclient"
|
||||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Controller) processGR(gr kyverno.GenerateRequest) error {
|
func (c *Controller) processGR(gr kyverno.GenerateRequest) error {
|
||||||
logger := c.log.WithValues("kind", gr.Kind, "namespace", gr.Namespace, "name", gr.Name)
|
|
||||||
// 1- Corresponding policy has been deleted
|
// 1- Corresponding policy has been deleted
|
||||||
// then we dont delete the generated resources
|
// then we dont delete the generated resources
|
||||||
|
|
||||||
// 2- The trigger resource is deleted, then delete the generated resources
|
// 2- The trigger resource is deleted, then delete the generated resources
|
||||||
if !ownerResourceExists(logger, c.client, gr) {
|
if !ownerResourceExists(c.client, gr) {
|
||||||
if err := deleteGeneratedResources(logger, c.client, gr); err != nil {
|
if err := deleteGeneratedResources(c.client, gr); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// - trigger-resource is deleted
|
// - trigger-resource is deleted
|
||||||
|
@ -25,25 +24,25 @@ func (c *Controller) processGR(gr kyverno.GenerateRequest) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ownerResourceExists(log logr.Logger, client *dclient.Client, gr kyverno.GenerateRequest) bool {
|
func ownerResourceExists(client *dclient.Client, gr kyverno.GenerateRequest) bool {
|
||||||
_, err := client.GetResource(gr.Spec.Resource.Kind, gr.Spec.Resource.Namespace, gr.Spec.Resource.Name)
|
_, err := client.GetResource(gr.Spec.Resource.Kind, gr.Spec.Resource.Namespace, gr.Spec.Resource.Name)
|
||||||
// trigger resources has been deleted
|
// trigger resources has been deleted
|
||||||
if apierrors.IsNotFound(err) {
|
if apierrors.IsNotFound(err) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err, "failed to get resource", "genKind", gr.Spec.Resource.Kind, "genNamespace", gr.Spec.Resource.Namespace, "genName", gr.Spec.Resource.Name)
|
glog.V(4).Infof("Failed to get resource %s/%s/%s: error : %s", gr.Spec.Resource.Kind, gr.Spec.Resource.Namespace, gr.Spec.Resource.Name, err)
|
||||||
}
|
}
|
||||||
// if there was an error while querying the resources we dont delete the generated resources
|
// if there was an error while querying the resources we dont delete the generated resources
|
||||||
// but expect the deletion in next reconciliation loop
|
// but expect the deletion in next reconciliation loop
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteGeneratedResources(log logr.Logger, client *dclient.Client, gr kyverno.GenerateRequest) error {
|
func deleteGeneratedResources(client *dclient.Client, gr kyverno.GenerateRequest) error {
|
||||||
for _, genResource := range gr.Status.GeneratedResources {
|
for _, genResource := range gr.Status.GeneratedResources {
|
||||||
err := client.DeleteResource(genResource.Kind, genResource.Namespace, genResource.Name, false)
|
err := client.DeleteResource(genResource.Kind, genResource.Namespace, genResource.Name, false)
|
||||||
if apierrors.IsNotFound(err) {
|
if apierrors.IsNotFound(err) {
|
||||||
log.Error(err, "resource not foundl will not delete", "genKind", gr.Spec.Resource.Kind, "genNamespace", gr.Spec.Resource.Namespace, "genName", gr.Spec.Resource.Name)
|
glog.V(4).Infof("resource %s/%s/%s not found, will no delete", genResource.Kind, genResource.Namespace, genResource.Name)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
package cleanup
|
package cleanup
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
"github.com/golang/glog"
|
||||||
|
|
||||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||||
kyvernoclient "github.com/nirmata/kyverno/pkg/client/clientset/versioned"
|
kyvernoclient "github.com/nirmata/kyverno/pkg/client/clientset/versioned"
|
||||||
kyvernoinformer "github.com/nirmata/kyverno/pkg/client/informers/externalversions/kyverno/v1"
|
kyvernoinformer "github.com/nirmata/kyverno/pkg/client/informers/externalversions/kyverno/v1"
|
||||||
|
@ -51,7 +53,6 @@ type Controller struct {
|
||||||
//TODO: list of generic informers
|
//TODO: list of generic informers
|
||||||
// only support Namespaces for deletion of resource
|
// only support Namespaces for deletion of resource
|
||||||
nsInformer informers.GenericInformer
|
nsInformer informers.GenericInformer
|
||||||
log logr.Logger
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//NewController returns a new controller instance to manage generate-requests
|
//NewController returns a new controller instance to manage generate-requests
|
||||||
|
@ -61,7 +62,6 @@ func NewController(
|
||||||
pInformer kyvernoinformer.ClusterPolicyInformer,
|
pInformer kyvernoinformer.ClusterPolicyInformer,
|
||||||
grInformer kyvernoinformer.GenerateRequestInformer,
|
grInformer kyvernoinformer.GenerateRequestInformer,
|
||||||
dynamicInformer dynamicinformer.DynamicSharedInformerFactory,
|
dynamicInformer dynamicinformer.DynamicSharedInformerFactory,
|
||||||
log logr.Logger,
|
|
||||||
) *Controller {
|
) *Controller {
|
||||||
c := Controller{
|
c := Controller{
|
||||||
kyvernoClient: kyvernoclient,
|
kyvernoClient: kyvernoclient,
|
||||||
|
@ -70,7 +70,6 @@ func NewController(
|
||||||
// as we dont want a deleted GR to be re-queue
|
// as we dont want a deleted GR to be re-queue
|
||||||
queue: workqueue.NewNamedRateLimitingQueue(workqueue.NewItemExponentialFailureRateLimiter(1, 30), "generate-request-cleanup"),
|
queue: workqueue.NewNamedRateLimitingQueue(workqueue.NewItemExponentialFailureRateLimiter(1, 30), "generate-request-cleanup"),
|
||||||
dynamicInformer: dynamicInformer,
|
dynamicInformer: dynamicInformer,
|
||||||
log: log,
|
|
||||||
}
|
}
|
||||||
c.control = Control{client: kyvernoclient}
|
c.control = Control{client: kyvernoclient}
|
||||||
c.enqueueGR = c.enqueue
|
c.enqueueGR = c.enqueue
|
||||||
|
@ -103,11 +102,10 @@ func NewController(
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) deleteGenericResource(obj interface{}) {
|
func (c *Controller) deleteGenericResource(obj interface{}) {
|
||||||
logger := c.log
|
|
||||||
r := obj.(*unstructured.Unstructured)
|
r := obj.(*unstructured.Unstructured)
|
||||||
grs, err := c.grLister.GetGenerateRequestsForResource(r.GetKind(), r.GetNamespace(), r.GetName())
|
grs, err := c.grLister.GetGenerateRequestsForResource(r.GetKind(), r.GetNamespace(), r.GetName())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "failed to get generate request CR for resource", "kind", r.GetKind(), "namespace", r.GetNamespace(), "name", r.GetName())
|
glog.Errorf("failed to Generate Requests for resource %s/%s/%s: %v", r.GetKind(), r.GetNamespace(), r.GetName(), err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// re-evaluate the GR as the resource was deleted
|
// re-evaluate the GR as the resource was deleted
|
||||||
|
@ -117,27 +115,26 @@ func (c *Controller) deleteGenericResource(obj interface{}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) deletePolicy(obj interface{}) {
|
func (c *Controller) deletePolicy(obj interface{}) {
|
||||||
logger := c.log
|
|
||||||
p, ok := obj.(*kyverno.ClusterPolicy)
|
p, ok := obj.(*kyverno.ClusterPolicy)
|
||||||
if !ok {
|
if !ok {
|
||||||
tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
|
tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
|
||||||
if !ok {
|
if !ok {
|
||||||
logger.Info("ouldn't get object from tombstone", "obj", obj)
|
glog.Info(fmt.Errorf("Couldn't get object from tombstone %#v", obj))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_, ok = tombstone.Obj.(*kyverno.ClusterPolicy)
|
_, ok = tombstone.Obj.(*kyverno.ClusterPolicy)
|
||||||
if !ok {
|
if !ok {
|
||||||
logger.Info("Tombstone contained object that is not a Generate Request", "obj", obj)
|
glog.Info(fmt.Errorf("Tombstone contained object that is not a Generate Request %#v", obj))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.V(4).Info("deleting policy", "name", p.Name)
|
glog.V(4).Infof("Deleting Policy %s", p.Name)
|
||||||
// clean up the GR
|
// clean up the GR
|
||||||
// Get the corresponding GR
|
// Get the corresponding GR
|
||||||
// get the list of GR for the current Policy version
|
// get the list of GR for the current Policy version
|
||||||
grs, err := c.grLister.GetGenerateRequestsForClusterPolicy(p.Name)
|
grs, err := c.grLister.GetGenerateRequestsForClusterPolicy(p.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "failed to generate request CR for the policy", "name", p.Name)
|
glog.Errorf("failed to Generate Requests for policy %s: %v", p.Name, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for _, gr := range grs {
|
for _, gr := range grs {
|
||||||
|
@ -156,46 +153,44 @@ func (c *Controller) updateGR(old, cur interface{}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) deleteGR(obj interface{}) {
|
func (c *Controller) deleteGR(obj interface{}) {
|
||||||
logger := c.log
|
|
||||||
gr, ok := obj.(*kyverno.GenerateRequest)
|
gr, ok := obj.(*kyverno.GenerateRequest)
|
||||||
if !ok {
|
if !ok {
|
||||||
tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
|
tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
|
||||||
if !ok {
|
if !ok {
|
||||||
logger.Info("Couldn't get object from tombstone", "obj", obj)
|
glog.Info(fmt.Errorf("Couldn't get object from tombstone %#v", obj))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_, ok = tombstone.Obj.(*kyverno.GenerateRequest)
|
_, ok = tombstone.Obj.(*kyverno.GenerateRequest)
|
||||||
if !ok {
|
if !ok {
|
||||||
logger.Info("ombstone contained object that is not a Generate Request", "obj", obj)
|
glog.Info(fmt.Errorf("Tombstone contained object that is not a Generate Request %#v", obj))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.V(4).Info("deleting Generate Request CR", "name", gr.Name)
|
glog.V(4).Infof("Deleting GR %s", gr.Name)
|
||||||
// sync Handler will remove it from the queue
|
// sync Handler will remove it from the queue
|
||||||
c.enqueueGR(gr)
|
c.enqueueGR(gr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) enqueue(gr *kyverno.GenerateRequest) {
|
func (c *Controller) enqueue(gr *kyverno.GenerateRequest) {
|
||||||
logger := c.log
|
|
||||||
key, err := cache.MetaNamespaceKeyFunc(gr)
|
key, err := cache.MetaNamespaceKeyFunc(gr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "failed to extract key")
|
glog.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
logger.V(4).Info("eneque generate request", "name", gr.Name)
|
glog.V(4).Infof("cleanup enqueu: %v", gr.Name)
|
||||||
c.queue.Add(key)
|
c.queue.Add(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
//Run starts the generate-request re-conciliation loop
|
//Run starts the generate-request re-conciliation loop
|
||||||
func (c *Controller) Run(workers int, stopCh <-chan struct{}) {
|
func (c *Controller) Run(workers int, stopCh <-chan struct{}) {
|
||||||
logger := c.log
|
|
||||||
defer utilruntime.HandleCrash()
|
defer utilruntime.HandleCrash()
|
||||||
defer c.queue.ShutDown()
|
defer c.queue.ShutDown()
|
||||||
logger.Info("starting")
|
|
||||||
defer logger.Info("shutting down")
|
glog.Info("Starting generate-policy-cleanup controller")
|
||||||
|
defer glog.Info("Shutting down generate-policy-cleanup controller")
|
||||||
|
|
||||||
if !cache.WaitForCacheSync(stopCh, c.pSynced, c.grSynced) {
|
if !cache.WaitForCacheSync(stopCh, c.pSynced, c.grSynced) {
|
||||||
logger.Info("failed to sync informer cache")
|
glog.Error("generate-policy-cleanup controller: failed to sync informer cache")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for i := 0; i < workers; i++ {
|
for i := 0; i < workers; i++ {
|
||||||
|
@ -224,33 +219,31 @@ func (c *Controller) processNextWorkItem() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) handleErr(err error, key interface{}) {
|
func (c *Controller) handleErr(err error, key interface{}) {
|
||||||
logger := c.log
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
c.queue.Forget(key)
|
c.queue.Forget(key)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.queue.NumRequeues(key) < maxRetries {
|
if c.queue.NumRequeues(key) < maxRetries {
|
||||||
logger.Error(err, "failed to sync generate request", "key", key)
|
glog.Errorf("Error syncing Generate Request %v: %v", key, err)
|
||||||
c.queue.AddRateLimited(key)
|
c.queue.AddRateLimited(key)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
utilruntime.HandleError(err)
|
utilruntime.HandleError(err)
|
||||||
logger.Error(err, "dropping generate request out of the queue", "key", key)
|
glog.Infof("Dropping generate request %q out of the queue: %v", key, err)
|
||||||
c.queue.Forget(key)
|
c.queue.Forget(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) syncGenerateRequest(key string) error {
|
func (c *Controller) syncGenerateRequest(key string) error {
|
||||||
logger := c.log.WithValues("key", key)
|
|
||||||
var err error
|
var err error
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
logger.Info("started syncing generate request", "startTime", startTime)
|
glog.V(4).Infof("Started syncing GR %q (%v)", key, startTime)
|
||||||
defer func() {
|
defer func() {
|
||||||
logger.V(4).Info("finished syncying generate request", "processingTIme", time.Since(startTime))
|
glog.V(4).Infof("Finished syncing GR %q (%v)", key, time.Since(startTime))
|
||||||
}()
|
}()
|
||||||
_, grName, err := cache.SplitMetaNamespaceKey(key)
|
_, grName, err := cache.SplitMetaNamespaceKey(key)
|
||||||
if errors.IsNotFound(err) {
|
if errors.IsNotFound(err) {
|
||||||
logger.Info("generate request has been deleted")
|
glog.Infof("Generate Request %s has been deleted", key)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
package generate
|
package generate
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
"github.com/golang/glog"
|
||||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||||
kyvernoclient "github.com/nirmata/kyverno/pkg/client/clientset/versioned"
|
kyvernoclient "github.com/nirmata/kyverno/pkg/client/clientset/versioned"
|
||||||
kyvernoinformer "github.com/nirmata/kyverno/pkg/client/informers/externalversions/kyverno/v1"
|
kyvernoinformer "github.com/nirmata/kyverno/pkg/client/informers/externalversions/kyverno/v1"
|
||||||
|
@ -56,9 +57,9 @@ type Controller struct {
|
||||||
dynamicInformer dynamicinformer.DynamicSharedInformerFactory
|
dynamicInformer dynamicinformer.DynamicSharedInformerFactory
|
||||||
//TODO: list of generic informers
|
//TODO: list of generic informers
|
||||||
// only support Namespaces for re-evalutation on resource updates
|
// only support Namespaces for re-evalutation on resource updates
|
||||||
nsInformer informers.GenericInformer
|
nsInformer informers.GenericInformer
|
||||||
|
|
||||||
policyStatusListener policystatus.Listener
|
policyStatusListener policystatus.Listener
|
||||||
log logr.Logger
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//NewController returns an instance of the Generate-Request Controller
|
//NewController returns an instance of the Generate-Request Controller
|
||||||
|
@ -71,7 +72,6 @@ func NewController(
|
||||||
pvGenerator policyviolation.GeneratorInterface,
|
pvGenerator policyviolation.GeneratorInterface,
|
||||||
dynamicInformer dynamicinformer.DynamicSharedInformerFactory,
|
dynamicInformer dynamicinformer.DynamicSharedInformerFactory,
|
||||||
policyStatus policystatus.Listener,
|
policyStatus policystatus.Listener,
|
||||||
log logr.Logger,
|
|
||||||
) *Controller {
|
) *Controller {
|
||||||
c := Controller{
|
c := Controller{
|
||||||
client: client,
|
client: client,
|
||||||
|
@ -82,7 +82,6 @@ func NewController(
|
||||||
// as we dont want a deleted GR to be re-queue
|
// as we dont want a deleted GR to be re-queue
|
||||||
queue: workqueue.NewNamedRateLimitingQueue(workqueue.NewItemExponentialFailureRateLimiter(1, 30), "generate-request"),
|
queue: workqueue.NewNamedRateLimitingQueue(workqueue.NewItemExponentialFailureRateLimiter(1, 30), "generate-request"),
|
||||||
dynamicInformer: dynamicInformer,
|
dynamicInformer: dynamicInformer,
|
||||||
log: log,
|
|
||||||
policyStatusListener: policyStatus,
|
policyStatusListener: policyStatus,
|
||||||
}
|
}
|
||||||
c.statusControl = StatusControl{client: kyvernoclient}
|
c.statusControl = StatusControl{client: kyvernoclient}
|
||||||
|
@ -118,12 +117,11 @@ func NewController(
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) updateGenericResource(old, cur interface{}) {
|
func (c *Controller) updateGenericResource(old, cur interface{}) {
|
||||||
logger := c.log
|
|
||||||
curR := cur.(*unstructured.Unstructured)
|
curR := cur.(*unstructured.Unstructured)
|
||||||
|
|
||||||
grs, err := c.grLister.GetGenerateRequestsForResource(curR.GetKind(), curR.GetNamespace(), curR.GetName())
|
grs, err := c.grLister.GetGenerateRequestsForResource(curR.GetKind(), curR.GetNamespace(), curR.GetName())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "failed to get generate request CR for the resoource", "kind", curR.GetKind(), "name", curR.GetName(), "namespace", curR.GetNamespace())
|
glog.Errorf("failed to Generate Requests for resource %s/%s/%s: %v", curR.GetKind(), curR.GetNamespace(), curR.GetName(), err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// re-evaluate the GR as the resource was updated
|
// re-evaluate the GR as the resource was updated
|
||||||
|
@ -136,14 +134,13 @@ func (c *Controller) updateGenericResource(old, cur interface{}) {
|
||||||
func (c *Controller) enqueue(gr *kyverno.GenerateRequest) {
|
func (c *Controller) enqueue(gr *kyverno.GenerateRequest) {
|
||||||
key, err := cache.MetaNamespaceKeyFunc(gr)
|
key, err := cache.MetaNamespaceKeyFunc(gr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.log.Error(err, "failed to extract name")
|
glog.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.queue.Add(key)
|
c.queue.Add(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) updatePolicy(old, cur interface{}) {
|
func (c *Controller) updatePolicy(old, cur interface{}) {
|
||||||
logger := c.log
|
|
||||||
oldP := old.(*kyverno.ClusterPolicy)
|
oldP := old.(*kyverno.ClusterPolicy)
|
||||||
curP := cur.(*kyverno.ClusterPolicy)
|
curP := cur.(*kyverno.ClusterPolicy)
|
||||||
if oldP.ResourceVersion == curP.ResourceVersion {
|
if oldP.ResourceVersion == curP.ResourceVersion {
|
||||||
|
@ -151,11 +148,11 @@ func (c *Controller) updatePolicy(old, cur interface{}) {
|
||||||
// Two different versions of the same replica set will always have different RVs.
|
// Two different versions of the same replica set will always have different RVs.
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
logger.V(4).Info("updating policy", "name", oldP.Name)
|
glog.V(4).Infof("Updating Policy %s", oldP.Name)
|
||||||
// get the list of GR for the current Policy version
|
// get the list of GR for the current Policy version
|
||||||
grs, err := c.grLister.GetGenerateRequestsForClusterPolicy(curP.Name)
|
grs, err := c.grLister.GetGenerateRequestsForClusterPolicy(curP.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "failed to generate request for policy", "name", curP.Name)
|
glog.Errorf("failed to Generate Requests for policy %s: %v", curP.Name, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// re-evaluate the GR as the policy was updated
|
// re-evaluate the GR as the policy was updated
|
||||||
|
@ -186,36 +183,34 @@ func (c *Controller) updateGR(old, cur interface{}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) deleteGR(obj interface{}) {
|
func (c *Controller) deleteGR(obj interface{}) {
|
||||||
logger := c.log
|
|
||||||
gr, ok := obj.(*kyverno.GenerateRequest)
|
gr, ok := obj.(*kyverno.GenerateRequest)
|
||||||
if !ok {
|
if !ok {
|
||||||
tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
|
tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
|
||||||
if !ok {
|
if !ok {
|
||||||
logger.Info("Couldn't get object from tombstone", "obj", obj)
|
glog.Info(fmt.Errorf("Couldn't get object from tombstone %#v", obj))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_, ok = tombstone.Obj.(*kyverno.GenerateRequest)
|
_, ok = tombstone.Obj.(*kyverno.GenerateRequest)
|
||||||
if !ok {
|
if !ok {
|
||||||
logger.Info("tombstone contained object that is not a Generate Request CR", "obj", obj)
|
glog.Info(fmt.Errorf("Tombstone contained object that is not a Generate Request %#v", obj))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.Info("deleting generate request", "name", gr.Name)
|
glog.V(4).Infof("Deleting GR %s", gr.Name)
|
||||||
// sync Handler will remove it from the queue
|
// sync Handler will remove it from the queue
|
||||||
c.enqueueGR(gr)
|
c.enqueueGR(gr)
|
||||||
}
|
}
|
||||||
|
|
||||||
//Run ...
|
//Run ...
|
||||||
func (c *Controller) Run(workers int, stopCh <-chan struct{}) {
|
func (c *Controller) Run(workers int, stopCh <-chan struct{}) {
|
||||||
logger := c.log
|
|
||||||
defer utilruntime.HandleCrash()
|
defer utilruntime.HandleCrash()
|
||||||
defer c.queue.ShutDown()
|
defer c.queue.ShutDown()
|
||||||
|
|
||||||
logger.Info("starting")
|
glog.Info("Starting generate-policy controller")
|
||||||
defer logger.Info("shutting down")
|
defer glog.Info("Shutting down generate-policy controller")
|
||||||
|
|
||||||
if !cache.WaitForCacheSync(stopCh, c.pSynced, c.grSynced) {
|
if !cache.WaitForCacheSync(stopCh, c.pSynced, c.grSynced) {
|
||||||
logger.Info("failed to sync informer cache")
|
glog.Error("generate-policy controller: failed to sync informer cache")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for i := 0; i < workers; i++ {
|
for i := 0; i < workers; i++ {
|
||||||
|
@ -244,29 +239,27 @@ func (c *Controller) processNextWorkItem() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) handleErr(err error, key interface{}) {
|
func (c *Controller) handleErr(err error, key interface{}) {
|
||||||
logger := c.log
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
c.queue.Forget(key)
|
c.queue.Forget(key)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.queue.NumRequeues(key) < maxRetries {
|
if c.queue.NumRequeues(key) < maxRetries {
|
||||||
logger.Error(err, "failed to sync generate request", "key", key)
|
glog.Errorf("Error syncing Generate Request %v: %v", key, err)
|
||||||
c.queue.AddRateLimited(key)
|
c.queue.AddRateLimited(key)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
utilruntime.HandleError(err)
|
utilruntime.HandleError(err)
|
||||||
logger.Error(err, "Dropping generate request from the queue", "key", key)
|
glog.Infof("Dropping generate request %q out of the queue: %v", key, err)
|
||||||
c.queue.Forget(key)
|
c.queue.Forget(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) syncGenerateRequest(key string) error {
|
func (c *Controller) syncGenerateRequest(key string) error {
|
||||||
logger := c.log
|
|
||||||
var err error
|
var err error
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
logger.Info("started sync", "key", key, "startTime", startTime)
|
glog.V(4).Infof("Started syncing GR %q (%v)", key, startTime)
|
||||||
defer func() {
|
defer func() {
|
||||||
logger.V(4).Info("finished sync", "key", key, "processingTime", time.Since(startTime))
|
glog.V(4).Infof("Finished syncing GR %q (%v)", key, time.Since(startTime))
|
||||||
}()
|
}()
|
||||||
_, grName, err := cache.SplitMetaNamespaceKey(key)
|
_, grName, err := cache.SplitMetaNamespaceKey(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -275,7 +268,7 @@ func (c *Controller) syncGenerateRequest(key string) error {
|
||||||
|
|
||||||
gr, err := c.grLister.Get(grName)
|
gr, err := c.grLister.Get(grName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "failed to list generate requests")
|
glog.V(4).Info(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return c.processGR(gr)
|
return c.processGR(gr)
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
"github.com/golang/glog"
|
||||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||||
dclient "github.com/nirmata/kyverno/pkg/dclient"
|
dclient "github.com/nirmata/kyverno/pkg/dclient"
|
||||||
"github.com/nirmata/kyverno/pkg/engine"
|
"github.com/nirmata/kyverno/pkg/engine"
|
||||||
|
@ -17,7 +17,6 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Controller) processGR(gr *kyverno.GenerateRequest) error {
|
func (c *Controller) processGR(gr *kyverno.GenerateRequest) error {
|
||||||
logger := c.log.WithValues("name", gr.Name, "policy", gr.Spec.Policy, "kind", gr.Spec.Resource.Kind, "namespace", gr.Spec.Resource.Namespace, "name", gr.Spec.Resource.Name)
|
|
||||||
var err error
|
var err error
|
||||||
var resource *unstructured.Unstructured
|
var resource *unstructured.Unstructured
|
||||||
var genResources []kyverno.ResourceSpec
|
var genResources []kyverno.ResourceSpec
|
||||||
|
@ -25,46 +24,45 @@ func (c *Controller) processGR(gr *kyverno.GenerateRequest) error {
|
||||||
resource, err = getResource(c.client, gr.Spec.Resource)
|
resource, err = getResource(c.client, gr.Spec.Resource)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Dont update status
|
// Dont update status
|
||||||
logger.Error(err, "resource does not exist or is yet to be created, requeueing")
|
glog.V(4).Infof("resource does not exist or is yet to be created, requeuing: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// 2 - Apply the generate policy on the resource
|
// 2 - Apply the generate policy on the resource
|
||||||
genResources, err = c.applyGenerate(*resource, *gr)
|
genResources, err = c.applyGenerate(*resource, *gr)
|
||||||
// 3 - Report Events
|
// 3 - Report Events
|
||||||
reportEvents(logger, err, c.eventGen, *gr, *resource)
|
reportEvents(err, c.eventGen, *gr, *resource)
|
||||||
// 4 - Update Status
|
// 4 - Update Status
|
||||||
return updateStatus(c.statusControl, *gr, err, genResources)
|
return updateStatus(c.statusControl, *gr, err, genResources)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) applyGenerate(resource unstructured.Unstructured, gr kyverno.GenerateRequest) ([]kyverno.ResourceSpec, error) {
|
func (c *Controller) applyGenerate(resource unstructured.Unstructured, gr kyverno.GenerateRequest) ([]kyverno.ResourceSpec, error) {
|
||||||
logger := c.log.WithValues("name", gr.Name, "policy", gr.Spec.Policy, "kind", gr.Spec.Resource.Kind, "namespace", gr.Spec.Resource.Namespace, "name", gr.Spec.Resource.Name)
|
|
||||||
// Get the list of rules to be applied
|
// Get the list of rules to be applied
|
||||||
// get policy
|
// get policy
|
||||||
policy, err := c.pLister.Get(gr.Spec.Policy)
|
policy, err := c.pLister.Get(gr.Spec.Policy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "policy not found")
|
glog.V(4).Infof("policy %s not found: %v", gr.Spec.Policy, err)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
// build context
|
// build context
|
||||||
ctx := context.NewContext()
|
ctx := context.NewContext()
|
||||||
resourceRaw, err := resource.MarshalJSON()
|
resourceRaw, err := resource.MarshalJSON()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "failed to marshal resource")
|
glog.V(4).Infof("failed to marshal resource: %v", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = ctx.AddResource(resourceRaw)
|
err = ctx.AddResource(resourceRaw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "failed to load resource in context")
|
glog.Infof("Failed to load resource in context: %v", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = ctx.AddUserInfo(gr.Spec.Context.UserRequestInfo)
|
err = ctx.AddUserInfo(gr.Spec.Context.UserRequestInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "failed to load SA in context")
|
glog.Infof("Failed to load userInfo in context: %v", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = ctx.AddSA(gr.Spec.Context.UserRequestInfo.AdmissionUserInfo.Username)
|
err = ctx.AddSA(gr.Spec.Context.UserRequestInfo.AdmissionUserInfo.Username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "failed to load UserInfo in context")
|
glog.Infof("Failed to load serviceAccount in context: %v", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,12 +76,12 @@ func (c *Controller) applyGenerate(resource unstructured.Unstructured, gr kyvern
|
||||||
// check if the policy still applies to the resource
|
// check if the policy still applies to the resource
|
||||||
engineResponse := engine.Generate(policyContext)
|
engineResponse := engine.Generate(policyContext)
|
||||||
if len(engineResponse.PolicyResponse.Rules) == 0 {
|
if len(engineResponse.PolicyResponse.Rules) == 0 {
|
||||||
logger.V(4).Info("policy does not apply to resource")
|
glog.V(4).Infof("policy %s, dont not apply to resource %v", gr.Spec.Policy, gr.Spec.Resource)
|
||||||
return nil, fmt.Errorf("policy %s, dont not apply to resource %v", gr.Spec.Policy, gr.Spec.Resource)
|
return nil, fmt.Errorf("policy %s, dont not apply to resource %v", gr.Spec.Policy, gr.Spec.Resource)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply the generate rule on resource
|
// Apply the generate rule on resource
|
||||||
return c.applyGeneratePolicy(logger, policyContext, gr)
|
return c.applyGeneratePolicy(policyContext, gr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateStatus(statusControl StatusControlInterface, gr kyverno.GenerateRequest, err error, genResources []kyverno.ResourceSpec) error {
|
func updateStatus(statusControl StatusControlInterface, gr kyverno.GenerateRequest, err error, genResources []kyverno.ResourceSpec) error {
|
||||||
|
@ -95,7 +93,7 @@ func updateStatus(statusControl StatusControlInterface, gr kyverno.GenerateReque
|
||||||
return statusControl.Success(gr, genResources)
|
return statusControl.Success(gr, genResources)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) applyGeneratePolicy(log logr.Logger, policyContext engine.PolicyContext, gr kyverno.GenerateRequest) ([]kyverno.ResourceSpec, error) {
|
func (c *Controller) applyGeneratePolicy(policyContext engine.PolicyContext, gr kyverno.GenerateRequest) ([]kyverno.ResourceSpec, error) {
|
||||||
// List of generatedResources
|
// List of generatedResources
|
||||||
var genResources []kyverno.ResourceSpec
|
var genResources []kyverno.ResourceSpec
|
||||||
// Get the response as the actions to be performed on the resource
|
// Get the response as the actions to be performed on the resource
|
||||||
|
@ -115,8 +113,9 @@ func (c *Controller) applyGeneratePolicy(log logr.Logger, policyContext engine.P
|
||||||
if !rule.HasGenerate() {
|
if !rule.HasGenerate() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
genResource, err := applyRule(log, c.client, rule, resource, ctx, processExisting)
|
genResource, err := applyRule(c.client, rule, resource, ctx, processExisting)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -173,7 +172,7 @@ func updateGenerateExecutionTime(newTime time.Duration, oldAverageTimeString str
|
||||||
return time.Duration(newAverageTimeInNanoSeconds) * time.Nanosecond
|
return time.Duration(newAverageTimeInNanoSeconds) * time.Nanosecond
|
||||||
}
|
}
|
||||||
|
|
||||||
func applyRule(log logr.Logger, client *dclient.Client, rule kyverno.Rule, resource unstructured.Unstructured, ctx context.EvalInterface, processExisting bool) (kyverno.ResourceSpec, error) {
|
func applyRule(client *dclient.Client, rule kyverno.Rule, resource unstructured.Unstructured, ctx context.EvalInterface, processExisting bool) (kyverno.ResourceSpec, error) {
|
||||||
var rdata map[string]interface{}
|
var rdata map[string]interface{}
|
||||||
var err error
|
var err error
|
||||||
var mode ResourceMode
|
var mode ResourceMode
|
||||||
|
@ -188,7 +187,7 @@ func applyRule(log logr.Logger, client *dclient.Client, rule kyverno.Rule, resou
|
||||||
// format : {{<variable_name}}
|
// format : {{<variable_name}}
|
||||||
// - if there is variables that are not defined the context -> results in error and rule is not applied
|
// - if there is variables that are not defined the context -> results in error and rule is not applied
|
||||||
// - valid variables are replaced with the values
|
// - valid variables are replaced with the values
|
||||||
if _, err := variables.SubstituteVars(log, ctx, genUnst.Object); err != nil {
|
if _, err := variables.SubstituteVars(ctx, genUnst.Object); err != nil {
|
||||||
return noGenResource, err
|
return noGenResource, err
|
||||||
}
|
}
|
||||||
genKind, _, err := unstructured.NestedString(genUnst.Object, "kind")
|
genKind, _, err := unstructured.NestedString(genUnst.Object, "kind")
|
||||||
|
@ -220,9 +219,9 @@ func applyRule(log logr.Logger, client *dclient.Client, rule kyverno.Rule, resou
|
||||||
}
|
}
|
||||||
|
|
||||||
if genData != nil {
|
if genData != nil {
|
||||||
rdata, mode, err = manageData(log, genKind, genNamespace, genName, genData, client, resource)
|
rdata, mode, err = manageData(genKind, genNamespace, genName, genData, client, resource)
|
||||||
} else {
|
} else {
|
||||||
rdata, mode, err = manageClone(log, genKind, genNamespace, genName, genCopy, client, resource)
|
rdata, mode, err = manageClone(genKind, genNamespace, genName, genCopy, client, resource)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return noGenResource, err
|
return noGenResource, err
|
||||||
|
@ -249,38 +248,38 @@ func applyRule(log logr.Logger, client *dclient.Client, rule kyverno.Rule, resou
|
||||||
// - app.kubernetes.io/managed-by: kyverno
|
// - app.kubernetes.io/managed-by: kyverno
|
||||||
// - kyverno.io/generated-by: kind/namespace/name (trigger resource)
|
// - kyverno.io/generated-by: kind/namespace/name (trigger resource)
|
||||||
manageLabels(newResource, resource)
|
manageLabels(newResource, resource)
|
||||||
logger := log.WithValues("genKind", genKind, "genNamespace", genNamespace, "genName", genName)
|
|
||||||
if mode == Create {
|
if mode == Create {
|
||||||
// Reset resource version
|
// Reset resource version
|
||||||
newResource.SetResourceVersion("")
|
newResource.SetResourceVersion("")
|
||||||
// Create the resource
|
// Create the resource
|
||||||
logger.V(4).Info("creating new resource")
|
glog.V(4).Infof("Creating new resource %s/%s/%s", genKind, genNamespace, genName)
|
||||||
_, err = client.CreateResource(genKind, genNamespace, newResource, false)
|
_, err = client.CreateResource(genKind, genNamespace, newResource, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Failed to create resource
|
// Failed to create resource
|
||||||
return noGenResource, err
|
return noGenResource, err
|
||||||
}
|
}
|
||||||
logger.V(4).Info("created new resource")
|
glog.V(4).Infof("Created new resource %s/%s/%s", genKind, genNamespace, genName)
|
||||||
|
|
||||||
} else if mode == Update {
|
} else if mode == Update {
|
||||||
logger.V(4).Info("updating existing resource")
|
glog.V(4).Infof("Updating existing resource %s/%s/%s", genKind, genNamespace, genName)
|
||||||
// Update the resource
|
// Update the resource
|
||||||
_, err := client.UpdateResource(genKind, genNamespace, newResource, false)
|
_, err := client.UpdateResource(genKind, genNamespace, newResource, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Failed to update resource
|
// Failed to update resource
|
||||||
return noGenResource, err
|
return noGenResource, err
|
||||||
}
|
}
|
||||||
logger.V(4).Info("updated new resource")
|
glog.V(4).Infof("Updated existing resource %s/%s/%s", genKind, genNamespace, genName)
|
||||||
}
|
}
|
||||||
|
|
||||||
return newGenResource, nil
|
return newGenResource, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func manageData(log logr.Logger, kind, namespace, name string, data map[string]interface{}, client *dclient.Client, resource unstructured.Unstructured) (map[string]interface{}, ResourceMode, error) {
|
func manageData(kind, namespace, name string, data map[string]interface{}, client *dclient.Client, resource unstructured.Unstructured) (map[string]interface{}, ResourceMode, error) {
|
||||||
// check if resource to be generated exists
|
// check if resource to be generated exists
|
||||||
obj, err := client.GetResource(kind, namespace, name)
|
obj, err := client.GetResource(kind, namespace, name)
|
||||||
if apierrors.IsNotFound(err) {
|
if apierrors.IsNotFound(err) {
|
||||||
log.Error(err, "resource does not exist, will try to create", "genKind", kind, "genNamespace", namespace, "genName", name)
|
glog.V(4).Infof("Resource %s/%s/%s does not exists, will try to create", kind, namespace, name)
|
||||||
return data, Create, nil
|
return data, Create, nil
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -289,17 +288,18 @@ func manageData(log logr.Logger, kind, namespace, name string, data map[string]i
|
||||||
return nil, Skip, err
|
return nil, Skip, err
|
||||||
}
|
}
|
||||||
// Resource exists; verfiy the content of the resource
|
// Resource exists; verfiy the content of the resource
|
||||||
err = checkResource(log, data, obj)
|
err = checkResource(data, obj)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
// Existing resource does contain the mentioned configuration in spec, skip processing the resource as it is already in expected state
|
// Existing resource does contain the mentioned configuration in spec, skip processing the resource as it is already in expected state
|
||||||
return nil, Skip, nil
|
return nil, Skip, nil
|
||||||
}
|
}
|
||||||
log.Info("to be generated resoruce already exists, but is missing the specifeid configurations, will try to update", "genKind", kind, "genNamespace", namespace, "genName", name)
|
|
||||||
|
glog.V(4).Infof("Resource %s/%s/%s exists but missing required configuration, will try to update", kind, namespace, name)
|
||||||
return data, Update, nil
|
return data, Update, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func manageClone(log logr.Logger, kind, namespace, name string, clone map[string]interface{}, client *dclient.Client, resource unstructured.Unstructured) (map[string]interface{}, ResourceMode, error) {
|
func manageClone(kind, namespace, name string, clone map[string]interface{}, client *dclient.Client, resource unstructured.Unstructured) (map[string]interface{}, ResourceMode, error) {
|
||||||
// check if resource to be generated exists
|
// check if resource to be generated exists
|
||||||
_, err := client.GetResource(kind, namespace, name)
|
_, err := client.GetResource(kind, namespace, name)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
@ -308,7 +308,6 @@ func manageClone(log logr.Logger, kind, namespace, name string, clone map[string
|
||||||
}
|
}
|
||||||
//TODO: check this
|
//TODO: check this
|
||||||
if !apierrors.IsNotFound(err) {
|
if !apierrors.IsNotFound(err) {
|
||||||
log.Error(err, "reference/clone resource is not found", "genKind", kind, "genNamespace", namespace, "genName", name)
|
|
||||||
//something wrong while fetching resource
|
//something wrong while fetching resource
|
||||||
return nil, Skip, err
|
return nil, Skip, err
|
||||||
}
|
}
|
||||||
|
@ -326,6 +325,8 @@ func manageClone(log logr.Logger, kind, namespace, name string, clone map[string
|
||||||
// attempting to clone it self, this will fail -> short-ciruit it
|
// attempting to clone it self, this will fail -> short-ciruit it
|
||||||
return nil, Skip, nil
|
return nil, Skip, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glog.V(4).Infof("check if resource %s/%s/%s exists", kind, newRNs, newRName)
|
||||||
// check if the resource as reference in clone exists?
|
// check if the resource as reference in clone exists?
|
||||||
obj, err := client.GetResource(kind, newRNs, newRName)
|
obj, err := client.GetResource(kind, newRNs, newRName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -348,10 +349,10 @@ const (
|
||||||
Update = "UPDATE"
|
Update = "UPDATE"
|
||||||
)
|
)
|
||||||
|
|
||||||
func checkResource(log logr.Logger, newResourceSpec interface{}, resource *unstructured.Unstructured) error {
|
func checkResource(newResourceSpec interface{}, resource *unstructured.Unstructured) error {
|
||||||
// check if the resource spec if a subset of the resource
|
// check if the resource spec if a subset of the resource
|
||||||
if path, err := validate.ValidateResourceWithPattern(log, resource.Object, newResourceSpec); err != nil {
|
if path, err := validate.ValidateResourceWithPattern(resource.Object, newResourceSpec); err != nil {
|
||||||
log.Error(err, "Failed to match the resource ", "path", path)
|
glog.V(4).Infof("Failed to match the resource at path %s: err %v", path, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -3,8 +3,8 @@ package generate
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/golang/glog"
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func manageLabels(unstr *unstructured.Unstructured, triggerResource unstructured.Unstructured) {
|
func manageLabels(unstr *unstructured.Unstructured, triggerResource unstructured.Unstructured) {
|
||||||
|
@ -30,7 +30,7 @@ func managedBy(labels map[string]string) {
|
||||||
val, ok := labels[key]
|
val, ok := labels[key]
|
||||||
if ok {
|
if ok {
|
||||||
if val != value {
|
if val != value {
|
||||||
log.Log.Info(fmt.Sprintf("resource managed by %s, kyverno wont over-ride the label", val))
|
glog.Infof("resource managed by %s, kyverno wont over-ride the label", val)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ func generatedBy(labels map[string]string, triggerResource unstructured.Unstruct
|
||||||
val, ok := labels[key]
|
val, ok := labels[key]
|
||||||
if ok {
|
if ok {
|
||||||
if val != value {
|
if val != value {
|
||||||
log.Log.Info(fmt.Sprintf("resource generated by %s, kyverno wont over-ride the label", val))
|
glog.Infof("resource generated by %s, kyverno wont over-ride the label", val)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,13 +3,13 @@ package generate
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
"github.com/golang/glog"
|
||||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||||
"github.com/nirmata/kyverno/pkg/event"
|
"github.com/nirmata/kyverno/pkg/event"
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
)
|
)
|
||||||
|
|
||||||
func reportEvents(log logr.Logger, err error, eventGen event.Interface, gr kyverno.GenerateRequest, resource unstructured.Unstructured) {
|
func reportEvents(err error, eventGen event.Interface, gr kyverno.GenerateRequest, resource unstructured.Unstructured) {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
// Success Events
|
// Success Events
|
||||||
// - resource -> policy rule applied successfully
|
// - resource -> policy rule applied successfully
|
||||||
|
@ -18,6 +18,7 @@ func reportEvents(log logr.Logger, err error, eventGen event.Interface, gr kyver
|
||||||
eventGen.Add(events...)
|
eventGen.Add(events...)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
glog.V(4).Infof("reporing events for %v", err)
|
||||||
events := failedEvents(err, gr, resource)
|
events := failedEvents(err, gr, resource)
|
||||||
eventGen.Add(events...)
|
eventGen.Add(events...)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
package generate
|
package generate
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/golang/glog"
|
||||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||||
kyvernoclient "github.com/nirmata/kyverno/pkg/client/clientset/versioned"
|
kyvernoclient "github.com/nirmata/kyverno/pkg/client/clientset/versioned"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
//StatusControlInterface provides interface to update status subresource
|
//StatusControlInterface provides interface to update status subresource
|
||||||
|
@ -25,10 +25,10 @@ func (sc StatusControl) Failed(gr kyverno.GenerateRequest, message string, genRe
|
||||||
gr.Status.GeneratedResources = genResources
|
gr.Status.GeneratedResources = genResources
|
||||||
_, err := sc.client.KyvernoV1().GenerateRequests("kyverno").UpdateStatus(&gr)
|
_, err := sc.client.KyvernoV1().GenerateRequests("kyverno").UpdateStatus(&gr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Log.Error(err, "failed to update generate request status", "name", gr.Name)
|
glog.V(4).Infof("FAILED: updated gr %s status to %s", gr.Name, string(kyverno.Failed))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
log.Log.Info("updated generate request status", "name", gr.Name, "status", string(kyverno.Failed))
|
glog.V(4).Infof("updated gr %s status to %s", gr.Name, string(kyverno.Failed))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,9 +41,9 @@ func (sc StatusControl) Success(gr kyverno.GenerateRequest, genResources []kyver
|
||||||
|
|
||||||
_, err := sc.client.KyvernoV1().GenerateRequests("kyverno").UpdateStatus(&gr)
|
_, err := sc.client.KyvernoV1().GenerateRequests("kyverno").UpdateStatus(&gr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Log.Error(err, "failed to update generate request status", "name", gr.Name)
|
glog.V(4).Infof("FAILED: updated gr %s status to %s", gr.Name, string(kyverno.Completed))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
log.Log.Info("updated generate request status", "name", gr.Name, "status", string(kyverno.Completed))
|
glog.V(4).Infof("updated gr %s status to %s", gr.Name, string(kyverno.Completed))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,8 @@ import (
|
||||||
|
|
||||||
policy2 "github.com/nirmata/kyverno/pkg/policy"
|
policy2 "github.com/nirmata/kyverno/pkg/policy"
|
||||||
|
|
||||||
|
"github.com/golang/glog"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
|
||||||
"k8s.io/client-go/discovery"
|
"k8s.io/client-go/discovery"
|
||||||
|
@ -32,7 +34,6 @@ import (
|
||||||
yamlv2 "gopkg.in/yaml.v2"
|
yamlv2 "gopkg.in/yaml.v2"
|
||||||
"k8s.io/cli-runtime/pkg/genericclioptions"
|
"k8s.io/cli-runtime/pkg/genericclioptions"
|
||||||
"k8s.io/client-go/kubernetes/scheme"
|
"k8s.io/client-go/kubernetes/scheme"
|
||||||
log "sigs.k8s.io/controller-runtime/pkg/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func Command() *cobra.Command {
|
func Command() *cobra.Command {
|
||||||
|
@ -50,7 +51,7 @@ func Command() *cobra.Command {
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !sanitizedError.IsErrorSanitized(err) {
|
if !sanitizedError.IsErrorSanitized(err) {
|
||||||
log.Log.Error(err, "failed to sanitize")
|
glog.V(4).Info(err)
|
||||||
err = fmt.Errorf("Internal error")
|
err = fmt.Errorf("Internal error")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,7 +71,7 @@ func Command() *cobra.Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, policy := range policies {
|
for _, policy := range policies {
|
||||||
err := policy2.Validate(utils.MarshalPolicy(*policy), nil, true)
|
err := policy2.Validate(utils.MarshalPolicy(*policy))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return sanitizedError.New(fmt.Sprintf("Policy %v is not valid", policy.Name))
|
return sanitizedError.New(fmt.Sprintf("Policy %v is not valid", policy.Name))
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,9 +9,6 @@ import (
|
||||||
"github.com/nirmata/kyverno/pkg/kyverno/apply"
|
"github.com/nirmata/kyverno/pkg/kyverno/apply"
|
||||||
|
|
||||||
"github.com/nirmata/kyverno/pkg/kyverno/version"
|
"github.com/nirmata/kyverno/pkg/kyverno/version"
|
||||||
"k8s.io/klog"
|
|
||||||
"k8s.io/klog/klogr"
|
|
||||||
log "sigs.k8s.io/controller-runtime/pkg/log"
|
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
@ -22,7 +19,7 @@ func CLI() {
|
||||||
Short: "kyverno manages native policies of Kubernetes",
|
Short: "kyverno manages native policies of Kubernetes",
|
||||||
}
|
}
|
||||||
|
|
||||||
configurelog(cli)
|
configureGlog(cli)
|
||||||
|
|
||||||
commands := []*cobra.Command{
|
commands := []*cobra.Command{
|
||||||
version.Command(),
|
version.Command(),
|
||||||
|
@ -39,9 +36,9 @@ func CLI() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func configurelog(cli *cobra.Command) {
|
func configureGlog(cli *cobra.Command) {
|
||||||
klog.InitFlags(nil)
|
flag.Parse()
|
||||||
log.SetLogger(klogr.New())
|
_ = flag.Set("logtostderr", "true")
|
||||||
|
|
||||||
cli.PersistentFlags().AddGoFlagSet(flag.CommandLine)
|
cli.PersistentFlags().AddGoFlagSet(flag.CommandLine)
|
||||||
_ = cli.PersistentFlags().MarkHidden("alsologtostderr")
|
_ = cli.PersistentFlags().MarkHidden("alsologtostderr")
|
||||||
|
|
|
@ -11,12 +11,13 @@ import (
|
||||||
|
|
||||||
"github.com/nirmata/kyverno/pkg/kyverno/sanitizedError"
|
"github.com/nirmata/kyverno/pkg/kyverno/sanitizedError"
|
||||||
|
|
||||||
|
"github.com/golang/glog"
|
||||||
|
|
||||||
policyvalidate "github.com/nirmata/kyverno/pkg/policy"
|
policyvalidate "github.com/nirmata/kyverno/pkg/policy"
|
||||||
|
|
||||||
v1 "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
v1 "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"k8s.io/apimachinery/pkg/util/yaml"
|
"k8s.io/apimachinery/pkg/util/yaml"
|
||||||
log "sigs.k8s.io/controller-runtime/pkg/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func Command() *cobra.Command {
|
func Command() *cobra.Command {
|
||||||
|
@ -28,7 +29,7 @@ func Command() *cobra.Command {
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !sanitizedError.IsErrorSanitized(err) {
|
if !sanitizedError.IsErrorSanitized(err) {
|
||||||
log.Log.Error(err, "failed to sanitize")
|
glog.V(4).Info(err)
|
||||||
err = fmt.Errorf("Internal error")
|
err = fmt.Errorf("Internal error")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,7 +45,7 @@ func Command() *cobra.Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, policy := range policies {
|
for _, policy := range policies {
|
||||||
err = policyvalidate.Validate(utils.MarshalPolicy(*policy), nil, true)
|
err = policyvalidate.Validate(utils.MarshalPolicy(*policy))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Policy " + policy.Name + " is invalid")
|
fmt.Println("Policy " + policy.Name + " is invalid")
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -6,12 +6,13 @@ import (
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
|
|
||||||
|
"github.com/golang/glog"
|
||||||
|
|
||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
|
|
||||||
"github.com/googleapis/gnostic/compiler"
|
"github.com/googleapis/gnostic/compiler"
|
||||||
|
|
||||||
openapi_v2 "github.com/googleapis/gnostic/OpenAPIv2"
|
openapi_v2 "github.com/googleapis/gnostic/OpenAPIv2"
|
||||||
log "sigs.k8s.io/controller-runtime/pkg/log"
|
|
||||||
|
|
||||||
client "github.com/nirmata/kyverno/pkg/dclient"
|
client "github.com/nirmata/kyverno/pkg/dclient"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
|
@ -43,12 +44,12 @@ func NewCRDSync(client *client.Client) *crdSync {
|
||||||
func (c *crdSync) Run(workers int, stopCh <-chan struct{}) {
|
func (c *crdSync) Run(workers int, stopCh <-chan struct{}) {
|
||||||
newDoc, err := c.client.DiscoveryClient.OpenAPISchema()
|
newDoc, err := c.client.DiscoveryClient.OpenAPISchema()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Log.Error(err, "cannot get openapi schema")
|
glog.V(4).Infof("cannot get openapi schema: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = useOpenApiDocument(newDoc)
|
err = useOpenApiDocument(newDoc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Log.Error(err, "Could not set custom OpenApi document")
|
glog.V(4).Infof("Could not set custom OpenApi document: %v\n", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sync CRD before kyverno starts
|
// Sync CRD before kyverno starts
|
||||||
|
@ -62,7 +63,7 @@ func (c *crdSync) Run(workers int, stopCh <-chan struct{}) {
|
||||||
func (c *crdSync) sync() {
|
func (c *crdSync) sync() {
|
||||||
crds, err := c.client.ListResource("CustomResourceDefinition", "", nil)
|
crds, err := c.client.ListResource("CustomResourceDefinition", "", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Log.Error(err, "could not fetch crd's from server")
|
glog.V(4).Infof("could not fetch crd's from server: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,7 +93,7 @@ func parseCRD(crd unstructured.Unstructured) {
|
||||||
|
|
||||||
crdName := crdDefinition.Spec.Names.Kind
|
crdName := crdDefinition.Spec.Names.Kind
|
||||||
if len(crdDefinition.Spec.Versions) < 1 {
|
if len(crdDefinition.Spec.Versions) < 1 {
|
||||||
log.Log.V(4).Info("could not parse crd schema, no versions present")
|
glog.V(4).Infof("could not parse crd schema, no versions present")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,7 +104,7 @@ func parseCRD(crd unstructured.Unstructured) {
|
||||||
|
|
||||||
parsedSchema, err := openapi_v2.NewSchema(schema, compiler.NewContext("schema", nil))
|
parsedSchema, err := openapi_v2.NewSchema(schema, compiler.NewContext("schema", nil))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Log.Error(err, "could not parse crd schema:")
|
glog.V(4).Infof("could not parse crd schema:%v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,9 +8,12 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
data "github.com/nirmata/kyverno/api"
|
|
||||||
"github.com/nirmata/kyverno/pkg/engine/utils"
|
"github.com/nirmata/kyverno/pkg/engine/utils"
|
||||||
|
|
||||||
|
"github.com/nirmata/kyverno/data"
|
||||||
|
|
||||||
|
"github.com/golang/glog"
|
||||||
|
|
||||||
"github.com/nirmata/kyverno/pkg/engine"
|
"github.com/nirmata/kyverno/pkg/engine"
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
|
|
||||||
|
@ -20,7 +23,6 @@ import (
|
||||||
"github.com/googleapis/gnostic/compiler"
|
"github.com/googleapis/gnostic/compiler"
|
||||||
"k8s.io/kube-openapi/pkg/util/proto"
|
"k8s.io/kube-openapi/pkg/util/proto"
|
||||||
"k8s.io/kube-openapi/pkg/util/proto/validation"
|
"k8s.io/kube-openapi/pkg/util/proto/validation"
|
||||||
log "sigs.k8s.io/controller-runtime/pkg/log"
|
|
||||||
|
|
||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
|
@ -118,7 +120,7 @@ func validatePolicyMutation(policy v1.ClusterPolicy) error {
|
||||||
newPolicy.Spec.Rules = rules
|
newPolicy.Spec.Rules = rules
|
||||||
resource, _ := generateEmptyResource(openApiGlobalState.definitions[openApiGlobalState.kindToDefinitionName[kind]]).(map[string]interface{})
|
resource, _ := generateEmptyResource(openApiGlobalState.definitions[openApiGlobalState.kindToDefinitionName[kind]]).(map[string]interface{})
|
||||||
if resource == nil {
|
if resource == nil {
|
||||||
log.Log.V(4).Info(fmt.Sprintf("Cannot Validate policy: openApi definition now found for %v", kind))
|
glog.V(4).Infof("Cannot Validate policy: openApi definition now found for %v", kind)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
newResource := unstructured.Unstructured{Object: resource}
|
newResource := unstructured.Unstructured{Object: resource}
|
||||||
|
|
|
@ -1,61 +0,0 @@
|
||||||
package policy
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
|
||||||
dclient "github.com/nirmata/kyverno/pkg/dclient"
|
|
||||||
"github.com/nirmata/kyverno/pkg/policy/generate"
|
|
||||||
"github.com/nirmata/kyverno/pkg/policy/mutate"
|
|
||||||
"github.com/nirmata/kyverno/pkg/policy/validate"
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
|
||||||
)
|
|
||||||
|
|
||||||
//Validation provides methods to validate a rule
|
|
||||||
type Validation interface {
|
|
||||||
Validate() (string, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
//validateAction performs validation on the rule actions
|
|
||||||
// - Mutate
|
|
||||||
// - Validation
|
|
||||||
// - Generate
|
|
||||||
func validateActions(idx int, rule kyverno.Rule, client *dclient.Client, mock bool) error {
|
|
||||||
var checker Validation
|
|
||||||
|
|
||||||
// Mutate
|
|
||||||
if rule.HasMutate() {
|
|
||||||
checker = mutate.NewMutateFactory(rule.Mutation)
|
|
||||||
if path, err := checker.Validate(); err != nil {
|
|
||||||
return fmt.Errorf("path: spec.rules[%d].mutate.%s.: %v", idx, path, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate
|
|
||||||
if rule.HasValidate() {
|
|
||||||
checker = validate.NewValidateFactory(rule.Validation)
|
|
||||||
if path, err := checker.Validate(); err != nil {
|
|
||||||
return fmt.Errorf("path: spec.rules[%d].validate.%s.: %v", idx, path, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate
|
|
||||||
if rule.HasGenerate() {
|
|
||||||
//TODO: this check is there to support offline validations
|
|
||||||
// generate uses selfSubjectReviews to verify actions
|
|
||||||
// this need to modified to use different implementation for online and offline mode
|
|
||||||
if mock {
|
|
||||||
checker = generate.NewFakeGenerate(rule.Generation)
|
|
||||||
if path, err := checker.Validate(); err != nil {
|
|
||||||
return fmt.Errorf("path: spec.rules[%d].generate.%s.: %v", idx, path, err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
checker = generate.NewGenerateFactory(client, rule.Generation, log.Log)
|
|
||||||
if path, err := checker.Validate(); err != nil {
|
|
||||||
return fmt.Errorf("path: spec.rules[%d].generate.%s.: %v", idx, path, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
jsonpatch "github.com/evanphx/json-patch"
|
jsonpatch "github.com/evanphx/json-patch"
|
||||||
"github.com/go-logr/logr"
|
"github.com/golang/glog"
|
||||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||||
"github.com/nirmata/kyverno/pkg/engine"
|
"github.com/nirmata/kyverno/pkg/engine"
|
||||||
"github.com/nirmata/kyverno/pkg/engine/context"
|
"github.com/nirmata/kyverno/pkg/engine/context"
|
||||||
|
@ -19,12 +19,12 @@ import (
|
||||||
|
|
||||||
// applyPolicy applies policy on a resource
|
// applyPolicy applies policy on a resource
|
||||||
//TODO: generation rules
|
//TODO: generation rules
|
||||||
func applyPolicy(policy kyverno.ClusterPolicy, resource unstructured.Unstructured, logger logr.Logger) (responses []response.EngineResponse) {
|
func applyPolicy(policy kyverno.ClusterPolicy, resource unstructured.Unstructured) (responses []response.EngineResponse) {
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
|
|
||||||
logger.Info("start applying policy", "startTime", startTime)
|
glog.V(4).Infof("Started apply policy %s on resource %s/%s/%s (%v)", policy.Name, resource.GetKind(), resource.GetNamespace(), resource.GetName(), startTime)
|
||||||
defer func() {
|
defer func() {
|
||||||
logger.Info("finisnhed applying policy", "processingTime", time.Since(startTime))
|
glog.V(4).Infof("Finished applying %s on resource %s/%s/%s (%v)", policy.Name, resource.GetKind(), resource.GetNamespace(), resource.GetName(), time.Since(startTime))
|
||||||
}()
|
}()
|
||||||
|
|
||||||
var engineResponses []response.EngineResponse
|
var engineResponses []response.EngineResponse
|
||||||
|
@ -32,15 +32,13 @@ func applyPolicy(policy kyverno.ClusterPolicy, resource unstructured.Unstructure
|
||||||
var err error
|
var err error
|
||||||
// build context
|
// build context
|
||||||
ctx := context.NewContext()
|
ctx := context.NewContext()
|
||||||
err = ctx.AddResource(transformResource(resource))
|
ctx.AddResource(transformResource(resource))
|
||||||
if err != nil {
|
|
||||||
logger.Error(err, "enable to add transform resource to ctx")
|
|
||||||
}
|
|
||||||
//MUTATION
|
//MUTATION
|
||||||
engineResponse, err = mutation(policy, resource, ctx, logger)
|
engineResponse, err = mutation(policy, resource, ctx)
|
||||||
engineResponses = append(engineResponses, engineResponse)
|
engineResponses = append(engineResponses, engineResponse)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "failed to process mutation rule")
|
glog.Errorf("unable to process mutation rules: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
//VALIDATION
|
//VALIDATION
|
||||||
|
@ -50,52 +48,52 @@ func applyPolicy(policy kyverno.ClusterPolicy, resource unstructured.Unstructure
|
||||||
//TODO: GENERATION
|
//TODO: GENERATION
|
||||||
return engineResponses
|
return engineResponses
|
||||||
}
|
}
|
||||||
func mutation(policy kyverno.ClusterPolicy, resource unstructured.Unstructured, ctx context.EvalInterface, log logr.Logger) (response.EngineResponse, error) {
|
func mutation(policy kyverno.ClusterPolicy, resource unstructured.Unstructured, ctx context.EvalInterface) (response.EngineResponse, error) {
|
||||||
|
|
||||||
engineResponse := engine.Mutate(engine.PolicyContext{Policy: policy, NewResource: resource, Context: ctx})
|
engineResponse := engine.Mutate(engine.PolicyContext{Policy: policy, NewResource: resource, Context: ctx})
|
||||||
if !engineResponse.IsSuccesful() {
|
if !engineResponse.IsSuccesful() {
|
||||||
log.V(4).Info("failed to apply mutation rules; reporting them")
|
glog.V(4).Infof("mutation had errors reporting them")
|
||||||
return engineResponse, nil
|
return engineResponse, nil
|
||||||
}
|
}
|
||||||
// Verify if the JSON pathes returned by the Mutate are already applied to the resource
|
// Verify if the JSON pathes returned by the Mutate are already applied to the resource
|
||||||
if reflect.DeepEqual(resource, engineResponse.PatchedResource) {
|
if reflect.DeepEqual(resource, engineResponse.PatchedResource) {
|
||||||
// resources matches
|
// resources matches
|
||||||
log.V(4).Info("resource already satisfys the policy")
|
glog.V(4).Infof("resource %s/%s/%s satisfies policy %s", engineResponse.PolicyResponse.Resource.Kind, engineResponse.PolicyResponse.Resource.Namespace, engineResponse.PolicyResponse.Resource.Name, engineResponse.PolicyResponse.Policy)
|
||||||
return engineResponse, nil
|
return engineResponse, nil
|
||||||
}
|
}
|
||||||
return getFailedOverallRuleInfo(resource, engineResponse, log)
|
return getFailedOverallRuleInfo(resource, engineResponse)
|
||||||
}
|
}
|
||||||
|
|
||||||
// getFailedOverallRuleInfo gets detailed info for over-all mutation failure
|
// getFailedOverallRuleInfo gets detailed info for over-all mutation failure
|
||||||
func getFailedOverallRuleInfo(resource unstructured.Unstructured, engineResponse response.EngineResponse, log logr.Logger) (response.EngineResponse, error) {
|
func getFailedOverallRuleInfo(resource unstructured.Unstructured, engineResponse response.EngineResponse) (response.EngineResponse, error) {
|
||||||
rawResource, err := resource.MarshalJSON()
|
rawResource, err := resource.MarshalJSON()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err, "faield to marshall resource")
|
glog.V(4).Infof("unable to marshal resource: %v\n", err)
|
||||||
return response.EngineResponse{}, err
|
return response.EngineResponse{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// resource does not match so there was a mutation rule violated
|
// resource does not match so there was a mutation rule violated
|
||||||
for index, rule := range engineResponse.PolicyResponse.Rules {
|
for index, rule := range engineResponse.PolicyResponse.Rules {
|
||||||
log.V(4).Info("veriying if policy rule was applied before", "rule", rule.Name)
|
glog.V(4).Infof("veriying if policy %s rule %s was applied before to resource %s/%s/%s", engineResponse.PolicyResponse.Policy, rule.Name, engineResponse.PolicyResponse.Resource.Kind, engineResponse.PolicyResponse.Resource.Namespace, engineResponse.PolicyResponse.Resource.Name)
|
||||||
if len(rule.Patches) == 0 {
|
if len(rule.Patches) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
patch, err := jsonpatch.DecodePatch(utils.JoinPatches(rule.Patches))
|
patch, err := jsonpatch.DecodePatch(utils.JoinPatches(rule.Patches))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err, "failed to decode JSON patch", "patches", rule.Patches)
|
glog.V(4).Infof("unable to decode patch %s: %v", rule.Patches, err)
|
||||||
return response.EngineResponse{}, err
|
return response.EngineResponse{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// apply the patches returned by mutate to the original resource
|
// apply the patches returned by mutate to the original resource
|
||||||
patchedResource, err := patch.Apply(rawResource)
|
patchedResource, err := patch.Apply(rawResource)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err, "failed to apply JSON patch", "patches", rule.Patches)
|
glog.V(4).Infof("unable to apply patch %s: %v", rule.Patches, err)
|
||||||
return response.EngineResponse{}, err
|
return response.EngineResponse{}, err
|
||||||
}
|
}
|
||||||
if !jsonpatch.Equal(patchedResource, rawResource) {
|
if !jsonpatch.Equal(patchedResource, rawResource) {
|
||||||
log.V(4).Info("policy rule conditions not satisfied by resource", "rule", rule.Name)
|
glog.V(4).Infof("policy %s rule %s condition not satisfied by existing resource", engineResponse.PolicyResponse.Policy, rule.Name)
|
||||||
engineResponse.PolicyResponse.Rules[index].Success = false
|
engineResponse.PolicyResponse.Rules[index].Success = false
|
||||||
engineResponse.PolicyResponse.Rules[index].Message = fmt.Sprintf("mutation json patches not found at resource path %s", extractPatchPath(rule.Patches, log))
|
engineResponse.PolicyResponse.Rules[index].Message = fmt.Sprintf("mutation json patches not found at resource path %s", extractPatchPath(rule.Patches))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return engineResponse, nil
|
return engineResponse, nil
|
||||||
|
@ -107,14 +105,14 @@ type jsonPatch struct {
|
||||||
Value interface{} `json:"value"`
|
Value interface{} `json:"value"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func extractPatchPath(patches [][]byte, log logr.Logger) string {
|
func extractPatchPath(patches [][]byte) string {
|
||||||
var resultPath []string
|
var resultPath []string
|
||||||
// extract the patch path and value
|
// extract the patch path and value
|
||||||
for _, patch := range patches {
|
for _, patch := range patches {
|
||||||
log.V(4).Info("expected json patch not found in resource", "patch", string(patch))
|
glog.V(4).Infof("expected json patch not found in resource: %s", string(patch))
|
||||||
var data jsonPatch
|
var data jsonPatch
|
||||||
if err := json.Unmarshal(patch, &data); err != nil {
|
if err := json.Unmarshal(patch, &data); err != nil {
|
||||||
log.Error(err, "failed to decode the generate patch", "patch", string(patch))
|
glog.V(4).Infof("Failed to decode the generated patch %v: Error %v", string(patch), err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
resultPath = append(resultPath, data.Path)
|
resultPath = append(resultPath, data.Path)
|
||||||
|
|
|
@ -6,7 +6,6 @@ import (
|
||||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||||
"github.com/nirmata/kyverno/pkg/engine/context"
|
"github.com/nirmata/kyverno/pkg/engine/context"
|
||||||
"github.com/nirmata/kyverno/pkg/engine/variables"
|
"github.com/nirmata/kyverno/pkg/engine/variables"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
//ContainsUserInfo returns error is userInfo is defined
|
//ContainsUserInfo returns error is userInfo is defined
|
||||||
|
@ -36,23 +35,23 @@ func ContainsUserInfo(policy kyverno.ClusterPolicy) error {
|
||||||
filterVars := []string{"request.userInfo*", "serviceAccountName", "serviceAccountNamespace"}
|
filterVars := []string{"request.userInfo*", "serviceAccountName", "serviceAccountNamespace"}
|
||||||
ctx := context.NewContext(filterVars...)
|
ctx := context.NewContext(filterVars...)
|
||||||
for condIdx, condition := range rule.Conditions {
|
for condIdx, condition := range rule.Conditions {
|
||||||
if condition.Key, err = variables.SubstituteVars(log.Log, ctx, condition.Key); err != nil {
|
if condition.Key, err = variables.SubstituteVars(ctx, condition.Key); err != nil {
|
||||||
return fmt.Errorf("userInfo variable used at spec/rules[%d]/condition[%d]/key", idx, condIdx)
|
return fmt.Errorf("userInfo variable used at spec/rules[%d]/condition[%d]/key", idx, condIdx)
|
||||||
}
|
}
|
||||||
|
|
||||||
if condition.Value, err = variables.SubstituteVars(log.Log, ctx, condition.Value); err != nil {
|
if condition.Value, err = variables.SubstituteVars(ctx, condition.Value); err != nil {
|
||||||
return fmt.Errorf("userInfo variable used at spec/rules[%d]/condition[%d]/value", idx, condIdx)
|
return fmt.Errorf("userInfo variable used at spec/rules[%d]/condition[%d]/value", idx, condIdx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if rule.Mutation.Overlay, err = variables.SubstituteVars(log.Log, ctx, rule.Mutation.Overlay); err != nil {
|
if rule.Mutation.Overlay, err = variables.SubstituteVars(ctx, rule.Mutation.Overlay); err != nil {
|
||||||
return fmt.Errorf("userInfo variable used at spec/rules[%d]/mutate/overlay", idx)
|
return fmt.Errorf("userInfo variable used at spec/rules[%d]/mutate/overlay", idx)
|
||||||
}
|
}
|
||||||
if rule.Validation.Pattern, err = variables.SubstituteVars(log.Log, ctx, rule.Validation.Pattern); err != nil {
|
if rule.Validation.Pattern, err = variables.SubstituteVars(ctx, rule.Validation.Pattern); err != nil {
|
||||||
return fmt.Errorf("userInfo variable used at spec/rules[%d]/validate/pattern", idx)
|
return fmt.Errorf("userInfo variable used at spec/rules[%d]/validate/pattern", idx)
|
||||||
}
|
}
|
||||||
for idx2, pattern := range rule.Validation.AnyPattern {
|
for idx2, pattern := range rule.Validation.AnyPattern {
|
||||||
if rule.Validation.AnyPattern[idx2], err = variables.SubstituteVars(log.Log, ctx, pattern); err != nil {
|
if rule.Validation.AnyPattern[idx2], err = variables.SubstituteVars(ctx, pattern); err != nil {
|
||||||
return fmt.Errorf("userInfo variable used at spec/rules[%d]/validate/anyPattern[%d]", idx, idx2)
|
return fmt.Errorf("userInfo variable used at spec/rules[%d]/validate/anyPattern[%d]", idx, idx2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,71 +4,57 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
"github.com/golang/glog"
|
||||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||||
kyvernolister "github.com/nirmata/kyverno/pkg/client/listers/kyverno/v1"
|
kyvernolister "github.com/nirmata/kyverno/pkg/client/listers/kyverno/v1"
|
||||||
"github.com/nirmata/kyverno/pkg/engine/response"
|
"github.com/nirmata/kyverno/pkg/engine/response"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (pc *PolicyController) cleanUp(ers []response.EngineResponse) {
|
|
||||||
for _, er := range ers {
|
|
||||||
if !er.IsSuccesful() {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if len(er.PolicyResponse.Rules) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// clean up after the policy has been corrected
|
|
||||||
pc.cleanUpPolicyViolation(er.PolicyResponse)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pc *PolicyController) cleanUpPolicyViolation(pResponse response.PolicyResponse) {
|
func (pc *PolicyController) cleanUpPolicyViolation(pResponse response.PolicyResponse) {
|
||||||
logger := pc.log
|
|
||||||
// - check if there is violation on resource (label:Selector)
|
// - check if there is violation on resource (label:Selector)
|
||||||
if pResponse.Resource.Namespace == "" {
|
if pResponse.Resource.Namespace == "" {
|
||||||
pv, err := getClusterPV(pc.cpvLister, pResponse.Policy, pResponse.Resource.Kind, pResponse.Resource.Name, logger)
|
pv, err := getClusterPV(pc.cpvLister, pResponse.Policy, pResponse.Resource.Kind, pResponse.Resource.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "failed to get cluster policy violation on policy and resource", "policy", pResponse.Policy, "kind", pResponse.Resource.Kind, "name", pResponse.Resource.Name)
|
glog.Errorf("failed to cleanUp violations: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if reflect.DeepEqual(pv, kyverno.ClusterPolicyViolation{}) {
|
if reflect.DeepEqual(pv, kyverno.ClusterPolicyViolation{}) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glog.V(4).Infof("cleanup cluster violation %s on %s", pv.Name, pv.Spec.ResourceSpec.ToKey())
|
||||||
if err := pc.pvControl.DeleteClusterPolicyViolation(pv.Name); err != nil {
|
if err := pc.pvControl.DeleteClusterPolicyViolation(pv.Name); err != nil {
|
||||||
logger.Error(err, "failed to delete cluster policy violation", "name", pv.Name)
|
glog.Errorf("failed to delete cluster policy violation %s on %s: %v", pv.Name, pv.Spec.ResourceSpec.ToKey(), err)
|
||||||
} else {
|
|
||||||
logger.Info("deleted cluster policy violation", "name", pv.Name)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// namespace policy violation
|
// namespace policy violation
|
||||||
nspv, err := getNamespacedPV(pc.nspvLister, pResponse.Policy, pResponse.Resource.Kind, pResponse.Resource.Namespace, pResponse.Resource.Name, logger)
|
nspv, err := getNamespacedPV(pc.nspvLister, pResponse.Policy, pResponse.Resource.Kind, pResponse.Resource.Namespace, pResponse.Resource.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "failed to get namespaced policy violation on policy and resource", "policy", pResponse.Policy, "kind", pResponse.Resource.Kind, "namespace", pResponse.Resource.Namespace, "name", pResponse.Resource.Name)
|
glog.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if reflect.DeepEqual(nspv, kyverno.PolicyViolation{}) {
|
if reflect.DeepEqual(nspv, kyverno.PolicyViolation{}) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
glog.V(4).Infof("cleanup namespaced violation %s on %s.%s", nspv.Name, pResponse.Resource.Namespace, nspv.Spec.ResourceSpec.ToKey())
|
||||||
if err := pc.pvControl.DeleteNamespacedPolicyViolation(nspv.Namespace, nspv.Name); err != nil {
|
if err := pc.pvControl.DeleteNamespacedPolicyViolation(nspv.Namespace, nspv.Name); err != nil {
|
||||||
logger.Error(err, "failed to delete cluster policy violation", "name", nspv.Name, "namespace", nspv.Namespace)
|
glog.Errorf("failed to delete namespaced policy violation %s on %s: %v", nspv.Name, nspv.Spec.ResourceSpec.ToKey(), err)
|
||||||
} else {
|
|
||||||
logger.Info("deleted namespaced policy violation", "name", nspv.Name, "namespace", nspv.Namespace)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wont do the claiming of objects, just lookup based on selectors
|
// Wont do the claiming of objects, just lookup based on selectors
|
||||||
func getClusterPV(pvLister kyvernolister.ClusterPolicyViolationLister, policyName, rkind, rname string, log logr.Logger) (kyverno.ClusterPolicyViolation, error) {
|
func getClusterPV(pvLister kyvernolister.ClusterPolicyViolationLister, policyName, rkind, rname string) (kyverno.ClusterPolicyViolation, error) {
|
||||||
var err error
|
var err error
|
||||||
// Check Violation on resource
|
// Check Violation on resource
|
||||||
pvs, err := pvLister.List(labels.Everything())
|
pvs, err := pvLister.List(labels.Everything())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err, "failed to list cluster policy violations")
|
glog.V(2).Infof("unable to list policy violations : %v", err)
|
||||||
return kyverno.ClusterPolicyViolation{}, fmt.Errorf("failed to list cluster pv: %v", err)
|
return kyverno.ClusterPolicyViolation{}, fmt.Errorf("failed to list cluster pv: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,10 +69,10 @@ func getClusterPV(pvLister kyvernolister.ClusterPolicyViolationLister, policyNam
|
||||||
return kyverno.ClusterPolicyViolation{}, nil
|
return kyverno.ClusterPolicyViolation{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getNamespacedPV(nspvLister kyvernolister.PolicyViolationLister, policyName, rkind, rnamespace, rname string, log logr.Logger) (kyverno.PolicyViolation, error) {
|
func getNamespacedPV(nspvLister kyvernolister.PolicyViolationLister, policyName, rkind, rnamespace, rname string) (kyverno.PolicyViolation, error) {
|
||||||
nspvs, err := nspvLister.PolicyViolations(rnamespace).List(labels.Everything())
|
nspvs, err := nspvLister.PolicyViolations(rnamespace).List(labels.Everything())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err, "failed to list namespaced policy violation")
|
glog.V(2).Infof("failed to list namespaced pv: %v", err)
|
||||||
return kyverno.PolicyViolation{}, fmt.Errorf("failed to list namespaced pv: %v", err)
|
return kyverno.PolicyViolation{}, fmt.Errorf("failed to list namespaced pv: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,15 @@
|
||||||
package policy
|
package policy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/golang/glog"
|
||||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||||
"k8s.io/client-go/tools/cache"
|
"k8s.io/client-go/tools/cache"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (pc *PolicyController) addClusterPolicyViolation(obj interface{}) {
|
func (pc *PolicyController) addClusterPolicyViolation(obj interface{}) {
|
||||||
pv := obj.(*kyverno.ClusterPolicyViolation)
|
pv := obj.(*kyverno.ClusterPolicyViolation)
|
||||||
logger := pc.log.WithValues("kind", pv.Kind, "namespace", pv.Namespace, "name", pv.Name)
|
|
||||||
|
|
||||||
if pv.DeletionTimestamp != nil {
|
if pv.DeletionTimestamp != nil {
|
||||||
// On a restart of the controller manager, it's possible for an object to
|
// On a restart of the controller manager, it's possible for an object to
|
||||||
|
@ -20,15 +22,15 @@ func (pc *PolicyController) addClusterPolicyViolation(obj interface{}) {
|
||||||
ps := pc.getPolicyForClusterPolicyViolation(pv)
|
ps := pc.getPolicyForClusterPolicyViolation(pv)
|
||||||
if len(ps) == 0 {
|
if len(ps) == 0 {
|
||||||
// there is no cluster policy for this violation, so we can delete this cluster policy violation
|
// there is no cluster policy for this violation, so we can delete this cluster policy violation
|
||||||
logger.V(4).Info("Cluster Policy Violation does not belong to an active policy, will be cleanedup")
|
glog.V(4).Infof("Cluster Policy Violation %s does not belong to an active policy, will be cleanedup", pv.Name)
|
||||||
if err := pc.pvControl.DeleteClusterPolicyViolation(pv.Name); err != nil {
|
if err := pc.pvControl.DeleteClusterPolicyViolation(pv.Name); err != nil {
|
||||||
logger.Error(err, "failed to delete resource")
|
glog.Errorf("Failed to deleted cluster policy violation %s: %v", pv.Name, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
logger.V(4).Info("resource deleted")
|
glog.V(4).Infof("Cluster Policy Violation %s deleted", pv.Name)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
logger.V(4).Info("resource added")
|
glog.V(4).Infof("Cluster Policy Violation %s added.", pv.Name)
|
||||||
for _, p := range ps {
|
for _, p := range ps {
|
||||||
pc.enqueuePolicy(p)
|
pc.enqueuePolicy(p)
|
||||||
}
|
}
|
||||||
|
@ -42,20 +44,19 @@ func (pc *PolicyController) updateClusterPolicyViolation(old, cur interface{}) {
|
||||||
// Two different versions of the same replica set will always have different RVs.
|
// Two different versions of the same replica set will always have different RVs.
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
logger := pc.log.WithValues("kind", curPV.Kind, "namespace", curPV.Namespace, "name", curPV.Name)
|
|
||||||
|
|
||||||
ps := pc.getPolicyForClusterPolicyViolation(curPV)
|
ps := pc.getPolicyForClusterPolicyViolation(curPV)
|
||||||
if len(ps) == 0 {
|
if len(ps) == 0 {
|
||||||
// there is no cluster policy for this violation, so we can delete this cluster policy violation
|
// there is no cluster policy for this violation, so we can delete this cluster policy violation
|
||||||
logger.V(4).Info("Cluster Policy Violation does not belong to an active policy, will be cleanedup")
|
glog.V(4).Infof("Cluster Policy Violation %s does not belong to an active policy, will be cleanedup", curPV.Name)
|
||||||
if err := pc.pvControl.DeleteClusterPolicyViolation(curPV.Name); err != nil {
|
if err := pc.pvControl.DeleteClusterPolicyViolation(curPV.Name); err != nil {
|
||||||
logger.Error(err, "failed to delete resource")
|
glog.Errorf("Failed to deleted cluster policy violation %s: %v", curPV.Name, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
logger.V(4).Info("resource deleted")
|
glog.V(4).Infof("PolicyViolation %s deleted", curPV.Name)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
logger.V(4).Info("resource updated")
|
glog.V(4).Infof("Cluster PolicyViolation %s updated", curPV.Name)
|
||||||
for _, p := range ps {
|
for _, p := range ps {
|
||||||
pc.enqueuePolicy(p)
|
pc.enqueuePolicy(p)
|
||||||
}
|
}
|
||||||
|
@ -66,7 +67,6 @@ func (pc *PolicyController) updateClusterPolicyViolation(old, cur interface{}) {
|
||||||
// a DeletionFinalStateUnknown marker item.
|
// a DeletionFinalStateUnknown marker item.
|
||||||
|
|
||||||
func (pc *PolicyController) deleteClusterPolicyViolation(obj interface{}) {
|
func (pc *PolicyController) deleteClusterPolicyViolation(obj interface{}) {
|
||||||
logger := pc.log
|
|
||||||
pv, ok := obj.(*kyverno.ClusterPolicyViolation)
|
pv, ok := obj.(*kyverno.ClusterPolicyViolation)
|
||||||
// When a delete is dropped, the relist will notice a PolicyViolation in the store not
|
// When a delete is dropped, the relist will notice a PolicyViolation in the store not
|
||||||
// in the list, leading to the insertion of a tombstone object which contains
|
// in the list, leading to the insertion of a tombstone object which contains
|
||||||
|
@ -75,35 +75,33 @@ func (pc *PolicyController) deleteClusterPolicyViolation(obj interface{}) {
|
||||||
if !ok {
|
if !ok {
|
||||||
tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
|
tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
|
||||||
if !ok {
|
if !ok {
|
||||||
logger.Info("Couldn't get object from tombstone", "obj", obj)
|
glog.Info(fmt.Errorf("Couldn't get object from tombstone %#v", obj))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
pv, ok = tombstone.Obj.(*kyverno.ClusterPolicyViolation)
|
pv, ok = tombstone.Obj.(*kyverno.ClusterPolicyViolation)
|
||||||
if !ok {
|
if !ok {
|
||||||
logger.Info("Couldn't get object from tombstone", "obj", obj)
|
glog.Info(fmt.Errorf("Couldn't get object from tombstone %#v", obj))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger = logger.WithValues("kind", pv.Kind, "namespace", pv.Namespace, "name", pv.Name)
|
|
||||||
ps := pc.getPolicyForClusterPolicyViolation(pv)
|
ps := pc.getPolicyForClusterPolicyViolation(pv)
|
||||||
if len(ps) == 0 {
|
if len(ps) == 0 {
|
||||||
// there is no cluster policy for this violation, so we can delete this cluster policy violation
|
// there is no cluster policy for this violation, so we can delete this cluster policy violation
|
||||||
logger.V(4).Info("Cluster Policy Violation does not belong to an active policy, will be cleanedup")
|
glog.V(4).Infof("Cluster Policy Violation %s does not belong to an active policy, will be cleanedup", pv.Name)
|
||||||
if err := pc.pvControl.DeleteClusterPolicyViolation(pv.Name); err != nil {
|
if err := pc.pvControl.DeleteClusterPolicyViolation(pv.Name); err != nil {
|
||||||
logger.Error(err, "failed to delete resource")
|
glog.Errorf("Failed to deleted cluster policy violation %s: %v", pv.Name, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
logger.V(4).Info("resource deleted")
|
glog.V(4).Infof("Cluster Policy Violation %s deleted", pv.Name)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
logger.V(4).Info("resource updated")
|
glog.V(4).Infof("Cluster PolicyViolation %s updated", pv.Name)
|
||||||
for _, p := range ps {
|
for _, p := range ps {
|
||||||
pc.enqueuePolicy(p)
|
pc.enqueuePolicy(p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pc *PolicyController) getPolicyForClusterPolicyViolation(pv *kyverno.ClusterPolicyViolation) []*kyverno.ClusterPolicy {
|
func (pc *PolicyController) getPolicyForClusterPolicyViolation(pv *kyverno.ClusterPolicyViolation) []*kyverno.ClusterPolicy {
|
||||||
logger := pc.log.WithValues("kind", pv.Kind, "namespace", pv.Namespace, "name", pv.Name)
|
|
||||||
policies, err := pc.pLister.GetPolicyForPolicyViolation(pv)
|
policies, err := pc.pLister.GetPolicyForPolicyViolation(pv)
|
||||||
if err != nil || len(policies) == 0 {
|
if err != nil || len(policies) == 0 {
|
||||||
return nil
|
return nil
|
||||||
|
@ -115,7 +113,8 @@ func (pc *PolicyController) getPolicyForClusterPolicyViolation(pv *kyverno.Clust
|
||||||
if len(policies) > 1 {
|
if len(policies) > 1 {
|
||||||
// ControllerRef will ensure we don't do anything crazy, but more than one
|
// ControllerRef will ensure we don't do anything crazy, but more than one
|
||||||
// item in this list nevertheless constitutes user error.
|
// item in this list nevertheless constitutes user error.
|
||||||
logger.V(4).Info("user error! more than one policy is selecting policy violation", "labels", pv.Labels, "policy", policies[0].Name)
|
glog.V(4).Infof("user error! more than one policy is selecting policy violation %s with labels: %#v, returning %s",
|
||||||
|
pv.Name, pv.Labels, policies[0].Name)
|
||||||
}
|
}
|
||||||
return policies
|
return policies
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,10 +3,10 @@ package policy
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/golang/glog"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func buildPolicyLabel(policyName string) (labels.Selector, error) {
|
func buildPolicyLabel(policyName string) (labels.Selector, error) {
|
||||||
|
@ -27,7 +27,7 @@ func buildPolicyLabel(policyName string) (labels.Selector, error) {
|
||||||
func transformResource(resource unstructured.Unstructured) []byte {
|
func transformResource(resource unstructured.Unstructured) []byte {
|
||||||
data, err := resource.MarshalJSON()
|
data, err := resource.MarshalJSON()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Log.Error(err, "failed to marshal resource")
|
glog.Errorf("failed to marshall resource %v: %v", resource, err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return data
|
return data
|
||||||
|
|
|
@ -1,85 +0,0 @@
|
||||||
package common
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"regexp"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/nirmata/kyverno/pkg/engine/anchor"
|
|
||||||
)
|
|
||||||
|
|
||||||
//ValidatePattern validates the pattern
|
|
||||||
func ValidatePattern(patternElement interface{}, path string, supportedAnchors []anchor.IsAnchor) (string, error) {
|
|
||||||
switch typedPatternElement := patternElement.(type) {
|
|
||||||
case map[string]interface{}:
|
|
||||||
return validateMap(typedPatternElement, path, supportedAnchors)
|
|
||||||
case []interface{}:
|
|
||||||
return validateArray(typedPatternElement, path, supportedAnchors)
|
|
||||||
case string, float64, int, int64, bool, nil:
|
|
||||||
//TODO? check operator
|
|
||||||
return "", nil
|
|
||||||
default:
|
|
||||||
return path, fmt.Errorf("Validation rule failed at '%s', pattern contains unknown type", path)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func validateMap(patternMap map[string]interface{}, path string, supportedAnchors []anchor.IsAnchor) (string, error) {
|
|
||||||
// check if anchors are defined
|
|
||||||
for key, value := range patternMap {
|
|
||||||
// if key is anchor
|
|
||||||
// check regex () -> this is anchor
|
|
||||||
// ()
|
|
||||||
// single char ()
|
|
||||||
re, err := regexp.Compile(`^.?\(.+\)$`)
|
|
||||||
if err != nil {
|
|
||||||
return path + "/" + key, fmt.Errorf("Unable to parse the field %s: %v", key, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
matched := re.MatchString(key)
|
|
||||||
// check the type of anchor
|
|
||||||
if matched {
|
|
||||||
// some type of anchor
|
|
||||||
// check if valid anchor
|
|
||||||
if !checkAnchors(key, supportedAnchors) {
|
|
||||||
return path + "/" + key, fmt.Errorf("Unsupported anchor %s", key)
|
|
||||||
}
|
|
||||||
|
|
||||||
// addition check for existence anchor
|
|
||||||
// value must be of type list
|
|
||||||
if anchor.IsExistenceAnchor(key) {
|
|
||||||
typedValue, ok := value.([]interface{})
|
|
||||||
if !ok {
|
|
||||||
return path + "/" + key, fmt.Errorf("Existence anchor should have value of type list")
|
|
||||||
}
|
|
||||||
// validate there is only one entry in the list
|
|
||||||
if len(typedValue) == 0 || len(typedValue) > 1 {
|
|
||||||
return path + "/" + key, fmt.Errorf("Existence anchor: single value expected, multiple specified")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// lets validate the values now :)
|
|
||||||
if errPath, err := ValidatePattern(value, path+"/"+key, supportedAnchors); err != nil {
|
|
||||||
return errPath, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func validateArray(patternArray []interface{}, path string, supportedAnchors []anchor.IsAnchor) (string, error) {
|
|
||||||
for i, patternElement := range patternArray {
|
|
||||||
currentPath := path + strconv.Itoa(i) + "/"
|
|
||||||
// lets validate the values now :)
|
|
||||||
if errPath, err := ValidatePattern(patternElement, currentPath, supportedAnchors); err != nil {
|
|
||||||
return errPath, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkAnchors(key string, supportedAnchors []anchor.IsAnchor) bool {
|
|
||||||
for _, f := range supportedAnchors {
|
|
||||||
if f(key) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
|
@ -1,9 +1,10 @@
|
||||||
package policy
|
package policy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
"github.com/golang/glog"
|
||||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||||
kyvernoclient "github.com/nirmata/kyverno/pkg/client/clientset/versioned"
|
kyvernoclient "github.com/nirmata/kyverno/pkg/client/clientset/versioned"
|
||||||
"github.com/nirmata/kyverno/pkg/client/clientset/versioned/scheme"
|
"github.com/nirmata/kyverno/pkg/client/clientset/versioned/scheme"
|
||||||
|
@ -71,7 +72,6 @@ type PolicyController struct {
|
||||||
pvGenerator policyviolation.GeneratorInterface
|
pvGenerator policyviolation.GeneratorInterface
|
||||||
// resourceWebhookWatcher queues the webhook creation request, creates the webhook
|
// resourceWebhookWatcher queues the webhook creation request, creates the webhook
|
||||||
resourceWebhookWatcher *webhookconfig.ResourceWebhookRegister
|
resourceWebhookWatcher *webhookconfig.ResourceWebhookRegister
|
||||||
log logr.Logger
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPolicyController create a new PolicyController
|
// NewPolicyController create a new PolicyController
|
||||||
|
@ -84,11 +84,10 @@ func NewPolicyController(kyvernoClient *kyvernoclient.Clientset,
|
||||||
eventGen event.Interface,
|
eventGen event.Interface,
|
||||||
pvGenerator policyviolation.GeneratorInterface,
|
pvGenerator policyviolation.GeneratorInterface,
|
||||||
pMetaStore policystore.UpdateInterface,
|
pMetaStore policystore.UpdateInterface,
|
||||||
resourceWebhookWatcher *webhookconfig.ResourceWebhookRegister,
|
resourceWebhookWatcher *webhookconfig.ResourceWebhookRegister) (*PolicyController, error) {
|
||||||
log logr.Logger) (*PolicyController, error) {
|
|
||||||
// Event broad caster
|
// Event broad caster
|
||||||
eventBroadcaster := record.NewBroadcaster()
|
eventBroadcaster := record.NewBroadcaster()
|
||||||
eventBroadcaster.StartLogging(log.Info)
|
eventBroadcaster.StartLogging(glog.Infof)
|
||||||
eventInterface, err := client.GetEventsInterface()
|
eventInterface, err := client.GetEventsInterface()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -105,7 +104,6 @@ func NewPolicyController(kyvernoClient *kyvernoclient.Clientset,
|
||||||
pMetaStore: pMetaStore,
|
pMetaStore: pMetaStore,
|
||||||
pvGenerator: pvGenerator,
|
pvGenerator: pvGenerator,
|
||||||
resourceWebhookWatcher: resourceWebhookWatcher,
|
resourceWebhookWatcher: resourceWebhookWatcher,
|
||||||
log: log,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pc.pvControl = RealPVControl{Client: kyvernoClient, Recorder: pc.eventRecorder}
|
pc.pvControl = RealPVControl{Client: kyvernoClient, Recorder: pc.eventRecorder}
|
||||||
|
@ -147,7 +145,6 @@ func NewPolicyController(kyvernoClient *kyvernoclient.Clientset,
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pc *PolicyController) addPolicy(obj interface{}) {
|
func (pc *PolicyController) addPolicy(obj interface{}) {
|
||||||
logger := pc.log
|
|
||||||
p := obj.(*kyverno.ClusterPolicy)
|
p := obj.(*kyverno.ClusterPolicy)
|
||||||
// Only process policies that are enabled for "background" execution
|
// Only process policies that are enabled for "background" execution
|
||||||
// policy.spec.background -> "True"
|
// policy.spec.background -> "True"
|
||||||
|
@ -171,19 +168,19 @@ func (pc *PolicyController) addPolicy(obj interface{}) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.V(4).Info("adding policy", "name", p.Name)
|
|
||||||
|
glog.V(4).Infof("Adding Policy %s", p.Name)
|
||||||
pc.enqueuePolicy(p)
|
pc.enqueuePolicy(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pc *PolicyController) updatePolicy(old, cur interface{}) {
|
func (pc *PolicyController) updatePolicy(old, cur interface{}) {
|
||||||
logger := pc.log
|
|
||||||
oldP := old.(*kyverno.ClusterPolicy)
|
oldP := old.(*kyverno.ClusterPolicy)
|
||||||
curP := cur.(*kyverno.ClusterPolicy)
|
curP := cur.(*kyverno.ClusterPolicy)
|
||||||
// TODO: optimize this : policy meta-store
|
// TODO: optimize this : policy meta-store
|
||||||
// Update policy-> (remove,add)
|
// Update policy-> (remove,add)
|
||||||
err := pc.pMetaStore.UnRegister(*oldP)
|
err := pc.pMetaStore.UnRegister(*oldP)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "failed to unregister policy", "name", oldP.Name)
|
glog.Infof("Failed to unregister policy %s", oldP.Name)
|
||||||
}
|
}
|
||||||
pc.pMetaStore.Register(*curP)
|
pc.pMetaStore.Register(*curP)
|
||||||
|
|
||||||
|
@ -206,29 +203,28 @@ func (pc *PolicyController) updatePolicy(old, cur interface{}) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.V(4).Info("updating policy", "name", oldP.Name)
|
glog.V(4).Infof("Updating Policy %s", oldP.Name)
|
||||||
pc.enqueuePolicy(curP)
|
pc.enqueuePolicy(curP)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pc *PolicyController) deletePolicy(obj interface{}) {
|
func (pc *PolicyController) deletePolicy(obj interface{}) {
|
||||||
logger := pc.log
|
|
||||||
p, ok := obj.(*kyverno.ClusterPolicy)
|
p, ok := obj.(*kyverno.ClusterPolicy)
|
||||||
if !ok {
|
if !ok {
|
||||||
tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
|
tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
|
||||||
if !ok {
|
if !ok {
|
||||||
logger.Info("couldnt get object from tomstone", "obj", obj)
|
glog.Info(fmt.Errorf("Couldn't get object from tombstone %#v", obj))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
p, ok = tombstone.Obj.(*kyverno.ClusterPolicy)
|
p, ok = tombstone.Obj.(*kyverno.ClusterPolicy)
|
||||||
if !ok {
|
if !ok {
|
||||||
logger.Info("tombstone container object that is not a policy", "obj", obj)
|
glog.Info(fmt.Errorf("Tombstone contained object that is not a Policy %#v", obj))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.V(4).Info("deleting policy", "name", p.Name)
|
glog.V(4).Infof("Deleting Policy %s", p.Name)
|
||||||
// Unregister from policy meta-store
|
// Unregister from policy meta-store
|
||||||
if err := pc.pMetaStore.UnRegister(*p); err != nil {
|
if err := pc.pMetaStore.UnRegister(*p); err != nil {
|
||||||
logger.Error(err, "failed to unregister policy", "name", p.Name)
|
glog.Infof("failed to unregister policy %s", p.Name)
|
||||||
}
|
}
|
||||||
// we process policies that are not set of background processing as we need to perform policy violation
|
// we process policies that are not set of background processing as we need to perform policy violation
|
||||||
// cleanup when a policy is deleted.
|
// cleanup when a policy is deleted.
|
||||||
|
@ -236,10 +232,9 @@ func (pc *PolicyController) deletePolicy(obj interface{}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pc *PolicyController) enqueue(policy *kyverno.ClusterPolicy) {
|
func (pc *PolicyController) enqueue(policy *kyverno.ClusterPolicy) {
|
||||||
logger := pc.log
|
|
||||||
key, err := cache.MetaNamespaceKeyFunc(policy)
|
key, err := cache.MetaNamespaceKeyFunc(policy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "failed to enqueu policy")
|
glog.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
pc.queue.Add(key)
|
pc.queue.Add(key)
|
||||||
|
@ -247,16 +242,15 @@ func (pc *PolicyController) enqueue(policy *kyverno.ClusterPolicy) {
|
||||||
|
|
||||||
// Run begins watching and syncing.
|
// Run begins watching and syncing.
|
||||||
func (pc *PolicyController) Run(workers int, stopCh <-chan struct{}) {
|
func (pc *PolicyController) Run(workers int, stopCh <-chan struct{}) {
|
||||||
logger := pc.log
|
|
||||||
|
|
||||||
defer utilruntime.HandleCrash()
|
defer utilruntime.HandleCrash()
|
||||||
defer pc.queue.ShutDown()
|
defer pc.queue.ShutDown()
|
||||||
|
|
||||||
logger.Info("starting")
|
glog.Info("Starting policy controller")
|
||||||
defer logger.Info("shutting down")
|
defer glog.Info("Shutting down policy controller")
|
||||||
|
|
||||||
if !cache.WaitForCacheSync(stopCh, pc.pListerSynced, pc.cpvListerSynced, pc.nspvListerSynced) {
|
if !cache.WaitForCacheSync(stopCh, pc.pListerSynced, pc.cpvListerSynced, pc.nspvListerSynced) {
|
||||||
logger.Info("failed to sync informer cache")
|
glog.Error("failed to sync informer cache")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -291,33 +285,31 @@ func (pc *PolicyController) processNextWorkItem() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pc *PolicyController) handleErr(err error, key interface{}) {
|
func (pc *PolicyController) handleErr(err error, key interface{}) {
|
||||||
logger := pc.log
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
pc.queue.Forget(key)
|
pc.queue.Forget(key)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if pc.queue.NumRequeues(key) < maxRetries {
|
if pc.queue.NumRequeues(key) < maxRetries {
|
||||||
logger.Error(err, "failed to sync policy", "key", key)
|
glog.V(2).Infof("Error syncing Policy %v: %v", key, err)
|
||||||
pc.queue.AddRateLimited(key)
|
pc.queue.AddRateLimited(key)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
utilruntime.HandleError(err)
|
utilruntime.HandleError(err)
|
||||||
logger.V(2).Info("dropping policy out of queue", "key", key)
|
glog.V(2).Infof("Dropping policy %q out of the queue: %v", key, err)
|
||||||
pc.queue.Forget(key)
|
pc.queue.Forget(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pc *PolicyController) syncPolicy(key string) error {
|
func (pc *PolicyController) syncPolicy(key string) error {
|
||||||
logger := pc.log
|
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
logger.V(4).Info("started syncing policy", "key", key, "startTime", startTime)
|
glog.V(4).Infof("Started syncing policy %q (%v)", key, startTime)
|
||||||
defer func() {
|
defer func() {
|
||||||
logger.V(4).Info("finished syncing policy", "key", key, "processingTime", time.Since(startTime))
|
glog.V(4).Infof("Finished syncing policy %q (%v)", key, time.Since(startTime))
|
||||||
}()
|
}()
|
||||||
policy, err := pc.pLister.Get(key)
|
policy, err := pc.pLister.Get(key)
|
||||||
if errors.IsNotFound(err) {
|
if errors.IsNotFound(err) {
|
||||||
logger.V(2).Info("policy deleted", "key", key)
|
glog.V(2).Infof("Policy %v has been deleted", key)
|
||||||
// delete cluster policy violation
|
// delete cluster policy violation
|
||||||
if err := pc.deleteClusterPolicyViolations(key); err != nil {
|
if err := pc.deleteClusterPolicyViolations(key); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -330,7 +322,8 @@ func (pc *PolicyController) syncPolicy(key string) error {
|
||||||
// remove webhook configurations if there are no policies
|
// remove webhook configurations if there are no policies
|
||||||
if err := pc.removeResourceWebhookConfiguration(); err != nil {
|
if err := pc.removeResourceWebhookConfiguration(); err != nil {
|
||||||
// do not fail, if unable to delete resource webhook config
|
// do not fail, if unable to delete resource webhook config
|
||||||
logger.Error(err, "failed to remove resource webhook configurations")
|
glog.V(4).Infof("failed to remove resource webhook configuration: %v", err)
|
||||||
|
glog.Errorln(err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
"github.com/golang/glog"
|
||||||
"github.com/minio/minio/pkg/wildcard"
|
"github.com/minio/minio/pkg/wildcard"
|
||||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||||
"github.com/nirmata/kyverno/pkg/config"
|
"github.com/nirmata/kyverno/pkg/config"
|
||||||
|
@ -19,27 +19,27 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func (pc *PolicyController) processExistingResources(policy kyverno.ClusterPolicy) []response.EngineResponse {
|
func (pc *PolicyController) processExistingResources(policy kyverno.ClusterPolicy) []response.EngineResponse {
|
||||||
logger := pc.log.WithValues("policy", policy.Name)
|
|
||||||
// Parse through all the resources
|
// Parse through all the resources
|
||||||
// drops the cache after configured rebuild time
|
// drops the cache after configured rebuild time
|
||||||
pc.rm.Drop()
|
pc.rm.Drop()
|
||||||
var engineResponses []response.EngineResponse
|
var engineResponses []response.EngineResponse
|
||||||
// get resource that are satisfy the resource description defined in the rules
|
// get resource that are satisfy the resource description defined in the rules
|
||||||
resourceMap := listResources(pc.client, policy, pc.configHandler, logger)
|
resourceMap := listResources(pc.client, policy, pc.configHandler)
|
||||||
for _, resource := range resourceMap {
|
for _, resource := range resourceMap {
|
||||||
// pre-processing, check if the policy and resource version has been processed before
|
// pre-processing, check if the policy and resource version has been processed before
|
||||||
if !pc.rm.ProcessResource(policy.Name, policy.ResourceVersion, resource.GetKind(), resource.GetNamespace(), resource.GetName(), resource.GetResourceVersion()) {
|
if !pc.rm.ProcessResource(policy.Name, policy.ResourceVersion, resource.GetKind(), resource.GetNamespace(), resource.GetName(), resource.GetResourceVersion()) {
|
||||||
logger.V(4).Info("policy and resource already processed", "policyResourceVersion", policy.ResourceVersion, "resourceResourceVersion", resource.GetResourceVersion(), "kind", resource.GetKind(), "namespace", resource.GetNamespace(), "name", resource.GetName())
|
glog.V(4).Infof("policy %s with resource version %s already processed on resource %s/%s/%s with resource version %s", policy.Name, policy.ResourceVersion, resource.GetKind(), resource.GetNamespace(), resource.GetName(), resource.GetResourceVersion())
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// skip reporting violation on pod which has annotation pod-policies.kyverno.io/autogen-applied
|
// skip reporting violation on pod which has annotation pod-policies.kyverno.io/autogen-applied
|
||||||
if skipPodApplication(resource, logger) {
|
if skipPodApplication(resource) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// apply the policy on each
|
// apply the policy on each
|
||||||
engineResponse := applyPolicy(policy, resource, logger)
|
glog.V(4).Infof("apply policy %s with resource version %s on resource %s/%s/%s with resource version %s", policy.Name, policy.ResourceVersion, resource.GetKind(), resource.GetNamespace(), resource.GetName(), resource.GetResourceVersion())
|
||||||
|
engineResponse := applyPolicy(policy, resource)
|
||||||
// get engine response for mutation & validation independently
|
// get engine response for mutation & validation independently
|
||||||
engineResponses = append(engineResponses, engineResponse...)
|
engineResponses = append(engineResponses, engineResponse...)
|
||||||
// post-processing, register the resource as processed
|
// post-processing, register the resource as processed
|
||||||
|
@ -48,26 +48,36 @@ func (pc *PolicyController) processExistingResources(policy kyverno.ClusterPolic
|
||||||
return engineResponses
|
return engineResponses
|
||||||
}
|
}
|
||||||
|
|
||||||
func listResources(client *client.Client, policy kyverno.ClusterPolicy, configHandler config.Interface, log logr.Logger) map[string]unstructured.Unstructured {
|
func listResources(client *client.Client, policy kyverno.ClusterPolicy, configHandler config.Interface) map[string]unstructured.Unstructured {
|
||||||
// key uid
|
// key uid
|
||||||
resourceMap := map[string]unstructured.Unstructured{}
|
resourceMap := map[string]unstructured.Unstructured{}
|
||||||
|
|
||||||
for _, rule := range policy.Spec.Rules {
|
for _, rule := range policy.Spec.Rules {
|
||||||
// resources that match
|
// resources that match
|
||||||
for _, k := range rule.MatchResources.Kinds {
|
for _, k := range rule.MatchResources.Kinds {
|
||||||
|
// if kindIsExcluded(k, rule.ExcludeResources.Kinds) {
|
||||||
|
// glog.V(4).Infof("processing policy %s rule %s: kind %s is exluded", policy.Name, rule.Name, k)
|
||||||
|
// continue
|
||||||
|
// }
|
||||||
var namespaces []string
|
var namespaces []string
|
||||||
|
if k == "Namespace" {
|
||||||
|
// TODO
|
||||||
|
// this is handled by generator controller
|
||||||
|
glog.V(4).Infof("skipping processing policy %s rule %s for kind Namespace", policy.Name, rule.Name)
|
||||||
|
continue
|
||||||
|
}
|
||||||
if len(rule.MatchResources.Namespaces) > 0 {
|
if len(rule.MatchResources.Namespaces) > 0 {
|
||||||
namespaces = append(namespaces, rule.MatchResources.Namespaces...)
|
namespaces = append(namespaces, rule.MatchResources.Namespaces...)
|
||||||
log.V(4).Info("namespaces included", "namespaces", rule.MatchResources.Namespaces)
|
glog.V(4).Infof("namespaces specified for inclusion: %v", rule.MatchResources.Namespaces)
|
||||||
} else {
|
} else {
|
||||||
log.V(4).Info("processing all namespaces", "rule", rule.Name)
|
glog.V(4).Infof("processing policy %s rule %s, namespace not defined, getting all namespaces ", policy.Name, rule.Name)
|
||||||
// get all namespaces
|
// get all namespaces
|
||||||
namespaces = getAllNamespaces(client, log)
|
namespaces = getAllNamespaces(client)
|
||||||
}
|
}
|
||||||
|
|
||||||
// get resources in the namespaces
|
// get resources in the namespaces
|
||||||
for _, ns := range namespaces {
|
for _, ns := range namespaces {
|
||||||
rMap := getResourcesPerNamespace(k, client, ns, rule, configHandler, log)
|
rMap := getResourcesPerNamespace(k, client, ns, rule, configHandler)
|
||||||
mergeresources(resourceMap, rMap)
|
mergeresources(resourceMap, rMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,16 +86,16 @@ func listResources(client *client.Client, policy kyverno.ClusterPolicy, configHa
|
||||||
return resourceMap
|
return resourceMap
|
||||||
}
|
}
|
||||||
|
|
||||||
func getResourcesPerNamespace(kind string, client *client.Client, namespace string, rule kyverno.Rule, configHandler config.Interface, log logr.Logger) map[string]unstructured.Unstructured {
|
func getResourcesPerNamespace(kind string, client *client.Client, namespace string, rule kyverno.Rule, configHandler config.Interface) map[string]unstructured.Unstructured {
|
||||||
resourceMap := map[string]unstructured.Unstructured{}
|
resourceMap := map[string]unstructured.Unstructured{}
|
||||||
// merge include and exclude label selector values
|
// merge include and exclude label selector values
|
||||||
ls := rule.MatchResources.Selector
|
ls := rule.MatchResources.Selector
|
||||||
// ls := mergeLabelSectors(rule.MatchResources.Selector, rule.ExcludeResources.Selector)
|
// ls := mergeLabelSectors(rule.MatchResources.Selector, rule.ExcludeResources.Selector)
|
||||||
// list resources
|
// list resources
|
||||||
log.V(4).Info("list resources to be processed")
|
glog.V(4).Infof("get resources for kind %s, namespace %s, selector %v", kind, namespace, rule.MatchResources.Selector)
|
||||||
list, err := client.ListResource(kind, namespace, ls)
|
list, err := client.ListResource(kind, namespace, ls)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err, "failed to list resources", "kind", kind)
|
glog.Infof("unable to get resources: err %v", err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// filter based on name
|
// filter based on name
|
||||||
|
@ -93,6 +103,7 @@ func getResourcesPerNamespace(kind string, client *client.Client, namespace stri
|
||||||
// match name
|
// match name
|
||||||
if rule.MatchResources.Name != "" {
|
if rule.MatchResources.Name != "" {
|
||||||
if !wildcard.Match(rule.MatchResources.Name, r.GetName()) {
|
if !wildcard.Match(rule.MatchResources.Name, r.GetName()) {
|
||||||
|
glog.V(4).Infof("skipping resource %s/%s due to include condition name=%s mistatch", r.GetNamespace(), r.GetName(), rule.MatchResources.Name)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -107,11 +118,12 @@ func getResourcesPerNamespace(kind string, client *client.Client, namespace stri
|
||||||
|
|
||||||
// exclude the resources
|
// exclude the resources
|
||||||
// skip resources to be filtered
|
// skip resources to be filtered
|
||||||
excludeResources(resourceMap, rule.ExcludeResources.ResourceDescription, configHandler, log)
|
excludeResources(resourceMap, rule.ExcludeResources.ResourceDescription, configHandler)
|
||||||
|
// glog.V(4).Infof("resource map: %v", resourceMap)
|
||||||
return resourceMap
|
return resourceMap
|
||||||
}
|
}
|
||||||
|
|
||||||
func excludeResources(included map[string]unstructured.Unstructured, exclude kyverno.ResourceDescription, configHandler config.Interface, log logr.Logger) {
|
func excludeResources(included map[string]unstructured.Unstructured, exclude kyverno.ResourceDescription, configHandler config.Interface) {
|
||||||
if reflect.DeepEqual(exclude, (kyverno.ResourceDescription{})) {
|
if reflect.DeepEqual(exclude, (kyverno.ResourceDescription{})) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -142,7 +154,7 @@ func excludeResources(included map[string]unstructured.Unstructured, exclude kyv
|
||||||
selector, err := metav1.LabelSelectorAsSelector(exclude.Selector)
|
selector, err := metav1.LabelSelectorAsSelector(exclude.Selector)
|
||||||
// if the label selector is incorrect, should be fail or
|
// if the label selector is incorrect, should be fail or
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err, "failed to build label selector")
|
glog.Error(err)
|
||||||
return Skip
|
return Skip
|
||||||
}
|
}
|
||||||
if selector.Matches(labels.Set(labelsMap)) {
|
if selector.Matches(labels.Set(labelsMap)) {
|
||||||
|
@ -193,6 +205,8 @@ func excludeResources(included map[string]unstructured.Unstructured, exclude kyv
|
||||||
}
|
}
|
||||||
// exclude the filtered resources
|
// exclude the filtered resources
|
||||||
if configHandler.ToFilter(resource.GetKind(), resource.GetNamespace(), resource.GetName()) {
|
if configHandler.ToFilter(resource.GetKind(), resource.GetNamespace(), resource.GetName()) {
|
||||||
|
//TODO: improve the text
|
||||||
|
glog.V(4).Infof("excluding resource %s/%s/%s as its satisfies the filtered resources", resource.GetKind(), resource.GetNamespace(), resource.GetName())
|
||||||
delete(included, uid)
|
delete(included, uid)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -230,13 +244,12 @@ func mergeresources(a, b map[string]unstructured.Unstructured) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getAllNamespaces(client *client.Client, log logr.Logger) []string {
|
func getAllNamespaces(client *client.Client) []string {
|
||||||
|
|
||||||
var namespaces []string
|
var namespaces []string
|
||||||
// get all namespaces
|
// get all namespaces
|
||||||
nsList, err := client.ListResource("Namespace", "", nil)
|
nsList, err := client.ListResource("Namespace", "", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err, "failed to list namespaces")
|
glog.Error(err)
|
||||||
return namespaces
|
return namespaces
|
||||||
}
|
}
|
||||||
for _, ns := range nsList.Items {
|
for _, ns := range nsList.Items {
|
||||||
|
@ -278,11 +291,14 @@ type resourceManager interface {
|
||||||
//TODO: or drop based on the size
|
//TODO: or drop based on the size
|
||||||
func (rm *ResourceManager) Drop() {
|
func (rm *ResourceManager) Drop() {
|
||||||
timeSince := time.Since(rm.time)
|
timeSince := time.Since(rm.time)
|
||||||
|
glog.V(4).Infof("time since last cache reset time %v is %v", rm.time, timeSince)
|
||||||
|
glog.V(4).Infof("cache rebuild time %v", time.Duration(rm.rebuildTime)*time.Second)
|
||||||
if timeSince > time.Duration(rm.rebuildTime)*time.Second {
|
if timeSince > time.Duration(rm.rebuildTime)*time.Second {
|
||||||
rm.mux.Lock()
|
rm.mux.Lock()
|
||||||
defer rm.mux.Unlock()
|
defer rm.mux.Unlock()
|
||||||
rm.data = map[string]interface{}{}
|
rm.data = map[string]interface{}{}
|
||||||
rm.time = time.Now()
|
rm.time = time.Now()
|
||||||
|
glog.V(4).Infof("dropping cache at time %v", rm.time)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -311,14 +327,14 @@ func buildKey(policy, pv, kind, ns, name, rv string) string {
|
||||||
return policy + "/" + pv + "/" + kind + "/" + ns + "/" + name + "/" + rv
|
return policy + "/" + pv + "/" + kind + "/" + ns + "/" + name + "/" + rv
|
||||||
}
|
}
|
||||||
|
|
||||||
func skipPodApplication(resource unstructured.Unstructured, log logr.Logger) bool {
|
func skipPodApplication(resource unstructured.Unstructured) bool {
|
||||||
if resource.GetKind() != "Pod" {
|
if resource.GetKind() != "Pod" {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
annotation := resource.GetAnnotations()
|
annotation := resource.GetAnnotations()
|
||||||
if _, ok := annotation[engine.PodTemplateAnnotation]; ok {
|
if _, ok := annotation[engine.PodTemplateAnnotation]; ok {
|
||||||
log.V(4).Info("Policies already processed on pod controllers, skip processing policy on Pod", "kind", resource.GetKind(), "namespace", resource.GetNamespace(), "name", resource.GetName())
|
glog.V(4).Infof("Policies already processed on pod controllers, skip processing policy on Pod/%s/%s", resource.GetNamespace(), resource.GetName())
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,74 +0,0 @@
|
||||||
package generate
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/go-logr/logr"
|
|
||||||
"github.com/nirmata/kyverno/pkg/auth"
|
|
||||||
dclient "github.com/nirmata/kyverno/pkg/dclient"
|
|
||||||
)
|
|
||||||
|
|
||||||
//Operations provides methods to performing operations on resource
|
|
||||||
type Operations interface {
|
|
||||||
// CanICreate returns 'true' if self can 'create' resource
|
|
||||||
CanICreate(kind, namespace string) (bool, error)
|
|
||||||
// CanIUpdate returns 'true' if self can 'update' resource
|
|
||||||
CanIUpdate(kind, namespace string) (bool, error)
|
|
||||||
// CanIDelete returns 'true' if self can 'delete' resource
|
|
||||||
CanIDelete(kind, namespace string) (bool, error)
|
|
||||||
// CanIGet returns 'true' if self can 'get' resource
|
|
||||||
CanIGet(kind, namespace string) (bool, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
//Auth provides implementation to check if caller/self/kyverno has access to perofrm operations
|
|
||||||
type Auth struct {
|
|
||||||
client *dclient.Client
|
|
||||||
log logr.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
//NewAuth returns a new instance of Auth for operations
|
|
||||||
func NewAuth(client *dclient.Client, log logr.Logger) *Auth {
|
|
||||||
a := Auth{
|
|
||||||
client: client,
|
|
||||||
log: log,
|
|
||||||
}
|
|
||||||
return &a
|
|
||||||
}
|
|
||||||
|
|
||||||
// CanICreate returns 'true' if self can 'create' resource
|
|
||||||
func (a *Auth) CanICreate(kind, namespace string) (bool, error) {
|
|
||||||
canI := auth.NewCanI(a.client, kind, namespace, "create", a.log)
|
|
||||||
ok, err := canI.RunAccessCheck()
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
return ok, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CanIUpdate returns 'true' if self can 'update' resource
|
|
||||||
func (a *Auth) CanIUpdate(kind, namespace string) (bool, error) {
|
|
||||||
canI := auth.NewCanI(a.client, kind, namespace, "update", a.log)
|
|
||||||
ok, err := canI.RunAccessCheck()
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
return ok, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CanIDelete returns 'true' if self can 'delete' resource
|
|
||||||
func (a *Auth) CanIDelete(kind, namespace string) (bool, error) {
|
|
||||||
canI := auth.NewCanI(a.client, kind, namespace, "delete", a.log)
|
|
||||||
ok, err := canI.RunAccessCheck()
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
return ok, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CanIGet returns 'true' if self can 'get' resource
|
|
||||||
func (a *Auth) CanIGet(kind, namespace string) (bool, error) {
|
|
||||||
canI := auth.NewCanI(a.client, kind, namespace, "get", a.log)
|
|
||||||
ok, err := canI.RunAccessCheck()
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
return ok, nil
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
package generate
|
|
||||||
|
|
||||||
import (
|
|
||||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
|
||||||
"github.com/nirmata/kyverno/pkg/policy/generate/fake"
|
|
||||||
)
|
|
||||||
|
|
||||||
//FakeGenerate provides implementation for generate rule processing
|
|
||||||
// with mocks/fakes for cluster interactions
|
|
||||||
type FakeGenerate struct {
|
|
||||||
Generate
|
|
||||||
}
|
|
||||||
|
|
||||||
//NewFakeGenerate returns a new instance of generatecheck that uses
|
|
||||||
// fake/mock implementation for operation access(always returns true)
|
|
||||||
func NewFakeGenerate(rule kyverno.Generation) *FakeGenerate {
|
|
||||||
g := FakeGenerate{}
|
|
||||||
g.rule = rule
|
|
||||||
g.authCheck = fake.NewFakeAuth()
|
|
||||||
return &g
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
package fake
|
|
||||||
|
|
||||||
//FakeAuth providers implementation for testing, retuning true for all operations
|
|
||||||
type FakeAuth struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
//NewFakeAuth returns a new instance of Fake Auth that returns true for each operation
|
|
||||||
func NewFakeAuth() *FakeAuth {
|
|
||||||
a := FakeAuth{}
|
|
||||||
return &a
|
|
||||||
}
|
|
||||||
|
|
||||||
// CanICreate returns 'true'
|
|
||||||
func (a *FakeAuth) CanICreate(kind, namespace string) (bool, error) {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CanIUpdate returns 'true'
|
|
||||||
func (a *FakeAuth) CanIUpdate(kind, namespace string) (bool, error) {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CanIDelete returns 'true'
|
|
||||||
func (a *FakeAuth) CanIDelete(kind, namespace string) (bool, error) {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CanIGet returns 'true'
|
|
||||||
func (a *FakeAuth) CanIGet(kind, namespace string) (bool, error) {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
|
@ -1,151 +0,0 @@
|
||||||
package generate
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
|
||||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
|
||||||
dclient "github.com/nirmata/kyverno/pkg/dclient"
|
|
||||||
"github.com/nirmata/kyverno/pkg/engine/anchor"
|
|
||||||
"github.com/nirmata/kyverno/pkg/engine/variables"
|
|
||||||
"github.com/nirmata/kyverno/pkg/policy/common"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Generate provides implementation to validate 'generate' rule
|
|
||||||
type Generate struct {
|
|
||||||
// rule to hold 'generate' rule specifications
|
|
||||||
rule kyverno.Generation
|
|
||||||
// authCheck to check access for operations
|
|
||||||
authCheck Operations
|
|
||||||
//logger
|
|
||||||
log logr.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
//NewGenerateFactory returns a new instance of Generate validation checker
|
|
||||||
func NewGenerateFactory(client *dclient.Client, rule kyverno.Generation, log logr.Logger) *Generate {
|
|
||||||
g := Generate{
|
|
||||||
rule: rule,
|
|
||||||
authCheck: NewAuth(client, log),
|
|
||||||
log: log,
|
|
||||||
}
|
|
||||||
|
|
||||||
return &g
|
|
||||||
}
|
|
||||||
|
|
||||||
//Validate validates the 'generate' rule
|
|
||||||
func (g *Generate) Validate() (string, error) {
|
|
||||||
rule := g.rule
|
|
||||||
if rule.Data == nil && rule.Clone == (kyverno.CloneFrom{}) {
|
|
||||||
return "", fmt.Errorf("clone or data are required")
|
|
||||||
}
|
|
||||||
if rule.Data != nil && rule.Clone != (kyverno.CloneFrom{}) {
|
|
||||||
return "", fmt.Errorf("only one operation allowed per generate rule(data or clone)")
|
|
||||||
}
|
|
||||||
kind, name, namespace := rule.Kind, rule.Name, rule.Namespace
|
|
||||||
|
|
||||||
if name == "" {
|
|
||||||
return "name", fmt.Errorf("name cannot be empty")
|
|
||||||
}
|
|
||||||
if kind == "" {
|
|
||||||
return "kind", fmt.Errorf("kind cannot be empty")
|
|
||||||
}
|
|
||||||
// Can I generate resource
|
|
||||||
|
|
||||||
if !reflect.DeepEqual(rule.Clone, kyverno.CloneFrom{}) {
|
|
||||||
if path, err := g.validateClone(rule.Clone, kind); err != nil {
|
|
||||||
return fmt.Sprintf("clone.%s", path), err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if rule.Data != nil {
|
|
||||||
//TODO: is this required ?? as anchors can only be on pattern and not resource
|
|
||||||
// we can add this check by not sure if its needed here
|
|
||||||
if path, err := common.ValidatePattern(rule.Data, "/", []anchor.IsAnchor{}); err != nil {
|
|
||||||
return fmt.Sprintf("data.%s", path), fmt.Errorf("anchors not supported on generate resources: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Kyverno generate-controller create/update/deletes the resources specified in generate rule of policy
|
|
||||||
// kyverno uses SA 'kyverno-service-account' and has default ClusterRoles and ClusterRoleBindings
|
|
||||||
// instuctions to modify the RBAC for kyverno are mentioned at https://github.com/nirmata/kyverno/blob/master/documentation/installation.md
|
|
||||||
// - operations required: create/update/delete/get
|
|
||||||
// If kind and namespace contain variables, then we cannot resolve then so we skip the processing
|
|
||||||
if err := g.canIGenerate(kind, namespace); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *Generate) validateClone(c kyverno.CloneFrom, kind string) (string, error) {
|
|
||||||
if c.Name == "" {
|
|
||||||
return "name", fmt.Errorf("name cannot be empty")
|
|
||||||
}
|
|
||||||
if c.Namespace == "" {
|
|
||||||
return "namespace", fmt.Errorf("namespace cannot be empty")
|
|
||||||
}
|
|
||||||
namespace := c.Namespace
|
|
||||||
// Skip if there is variable defined
|
|
||||||
if !variables.IsVariable(kind) && !variables.IsVariable(namespace) {
|
|
||||||
// GET
|
|
||||||
ok, err := g.authCheck.CanIGet(kind, namespace)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
if !ok {
|
|
||||||
return "", fmt.Errorf("kyverno does not have permissions to 'get' resource %s/%s. Update permissions in ClusterRole 'kyverno:generatecontroller'", kind, namespace)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
g.log.V(4).Info("name & namespace uses variables, so cannot be resolved. Skipping Auth Checks.")
|
|
||||||
}
|
|
||||||
return "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
//canIGenerate returns a error if kyverno cannot perform oprations
|
|
||||||
func (g *Generate) canIGenerate(kind, namespace string) error {
|
|
||||||
// Skip if there is variable defined
|
|
||||||
authCheck := g.authCheck
|
|
||||||
if !variables.IsVariable(kind) && !variables.IsVariable(namespace) {
|
|
||||||
// CREATE
|
|
||||||
ok, err := authCheck.CanICreate(kind, namespace)
|
|
||||||
if err != nil {
|
|
||||||
// machinery error
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("kyverno does not have permissions to 'create' resource %s/%s. Update permissions in ClusterRole 'kyverno:generatecontroller'", kind, namespace)
|
|
||||||
}
|
|
||||||
// UPDATE
|
|
||||||
ok, err = authCheck.CanIUpdate(kind, namespace)
|
|
||||||
if err != nil {
|
|
||||||
// machinery error
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("kyverno does not have permissions to 'update' resource %s/%s. Update permissions in ClusterRole 'kyverno:generatecontroller'", kind, namespace)
|
|
||||||
}
|
|
||||||
// GET
|
|
||||||
ok, err = authCheck.CanIGet(kind, namespace)
|
|
||||||
if err != nil {
|
|
||||||
// machinery error
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("kyverno does not have permissions to 'get' resource %s/%s. Update permissions in ClusterRole 'kyverno:generatecontroller'", kind, namespace)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DELETE
|
|
||||||
ok, err = authCheck.CanIDelete(kind, namespace)
|
|
||||||
if err != nil {
|
|
||||||
// machinery error
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("kyverno does not have permissions to 'delete' resource %s/%s. Update permissions in ClusterRole 'kyverno:generatecontroller'", kind, namespace)
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
g.log.V(4).Info("name & namespace uses variables, so cannot be resolved. Skipping Auth Checks.")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,89 +0,0 @@
|
||||||
package generate
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
|
||||||
"gotest.tools/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Test_Validate_Generate(t *testing.T) {
|
|
||||||
rawGenerate := []byte(`
|
|
||||||
{
|
|
||||||
"kind": "NetworkPolicy",
|
|
||||||
"name": "defaultnetworkpolicy",
|
|
||||||
"data": {
|
|
||||||
"spec": {
|
|
||||||
"podSelector": {},
|
|
||||||
"policyTypes": [
|
|
||||||
"Ingress",
|
|
||||||
"Egress"
|
|
||||||
],
|
|
||||||
"ingress": [
|
|
||||||
{}
|
|
||||||
],
|
|
||||||
"egress": [
|
|
||||||
{}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}`)
|
|
||||||
|
|
||||||
var genRule kyverno.Generation
|
|
||||||
err := json.Unmarshal(rawGenerate, &genRule)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
checker := NewFakeGenerate(genRule)
|
|
||||||
if _, err := checker.Validate(); err != nil {
|
|
||||||
assert.Assert(t, err != nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_Validate_Generate_HasAnchors(t *testing.T) {
|
|
||||||
var err error
|
|
||||||
rawGenerate := []byte(`
|
|
||||||
{
|
|
||||||
"kind": "NetworkPolicy",
|
|
||||||
"name": "defaultnetworkpolicy",
|
|
||||||
"data": {
|
|
||||||
"spec": {
|
|
||||||
"(podSelector)": {},
|
|
||||||
"policyTypes": [
|
|
||||||
"Ingress",
|
|
||||||
"Egress"
|
|
||||||
],
|
|
||||||
"ingress": [
|
|
||||||
{}
|
|
||||||
],
|
|
||||||
"egress": [
|
|
||||||
{}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}`)
|
|
||||||
|
|
||||||
var genRule kyverno.Generation
|
|
||||||
err = json.Unmarshal(rawGenerate, &genRule)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
checker := NewFakeGenerate(genRule)
|
|
||||||
if _, err := checker.Validate(); err != nil {
|
|
||||||
assert.Assert(t, err != nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
rawGenerate = []byte(`
|
|
||||||
{
|
|
||||||
"kind": "ConfigMap",
|
|
||||||
"name": "copied-cm",
|
|
||||||
"clone": {
|
|
||||||
"^(namespace)": "default",
|
|
||||||
"name": "game"
|
|
||||||
}
|
|
||||||
}`)
|
|
||||||
|
|
||||||
err = json.Unmarshal(rawGenerate, &genRule)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
checker = NewFakeGenerate(genRule)
|
|
||||||
if _, err := checker.Validate(); err != nil {
|
|
||||||
assert.Assert(t, err != nil)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,63 +0,0 @@
|
||||||
package mutate
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
|
||||||
"github.com/nirmata/kyverno/pkg/engine/anchor"
|
|
||||||
"github.com/nirmata/kyverno/pkg/policy/common"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Mutate provides implementation to validate 'mutate' rule
|
|
||||||
type Mutate struct {
|
|
||||||
// rule to hold 'mutate' rule specifications
|
|
||||||
rule kyverno.Mutation
|
|
||||||
}
|
|
||||||
|
|
||||||
//NewMutateFactory returns a new instance of Mutate validation checker
|
|
||||||
func NewMutateFactory(rule kyverno.Mutation) *Mutate {
|
|
||||||
m := Mutate{
|
|
||||||
rule: rule,
|
|
||||||
}
|
|
||||||
return &m
|
|
||||||
}
|
|
||||||
|
|
||||||
//Validate validates the 'mutate' rule
|
|
||||||
func (m *Mutate) Validate() (string, error) {
|
|
||||||
rule := m.rule
|
|
||||||
// JSON Patches
|
|
||||||
if len(rule.Patches) != 0 {
|
|
||||||
for i, patch := range rule.Patches {
|
|
||||||
if err := validatePatch(patch); err != nil {
|
|
||||||
return fmt.Sprintf("patch[%d]", i), err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Overlay
|
|
||||||
if rule.Overlay != nil {
|
|
||||||
path, err := common.ValidatePattern(rule.Overlay, "/", []anchor.IsAnchor{anchor.IsConditionAnchor, anchor.IsAddingAnchor})
|
|
||||||
if err != nil {
|
|
||||||
return path, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate if all mandatory PolicyPatch fields are set
|
|
||||||
func validatePatch(pp kyverno.Patch) error {
|
|
||||||
if pp.Path == "" {
|
|
||||||
return errors.New("JSONPatch field 'path' is mandatory")
|
|
||||||
}
|
|
||||||
if pp.Operation == "add" || pp.Operation == "replace" {
|
|
||||||
if pp.Value == nil {
|
|
||||||
return fmt.Errorf("JSONPatch field 'value' is mandatory for operation '%s'", pp.Operation)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
} else if pp.Operation == "remove" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Errorf("Unsupported JSONPatch operation '%s'", pp.Operation)
|
|
||||||
}
|
|
|
@ -1,151 +0,0 @@
|
||||||
package mutate
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
|
||||||
"gotest.tools/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Test_Validate_Mutate_ConditionAnchor(t *testing.T) {
|
|
||||||
rawMutate := []byte(`
|
|
||||||
{
|
|
||||||
"overlay": {
|
|
||||||
"spec": {
|
|
||||||
"(serviceAccountName)": "*",
|
|
||||||
"automountServiceAccountToken": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}`)
|
|
||||||
|
|
||||||
var mutate kyverno.Mutation
|
|
||||||
err := json.Unmarshal(rawMutate, &mutate)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
checker := NewMutateFactory(mutate)
|
|
||||||
if _, err := checker.Validate(); err != nil {
|
|
||||||
assert.NilError(t, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_Validate_Mutate_PlusAnchor(t *testing.T) {
|
|
||||||
rawMutate := []byte(`
|
|
||||||
{
|
|
||||||
"overlay": {
|
|
||||||
"spec": {
|
|
||||||
"+(serviceAccountName)": "*",
|
|
||||||
"automountServiceAccountToken": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}`)
|
|
||||||
|
|
||||||
var mutate kyverno.Mutation
|
|
||||||
err := json.Unmarshal(rawMutate, &mutate)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
checker := NewMutateFactory(mutate)
|
|
||||||
if _, err := checker.Validate(); err != nil {
|
|
||||||
assert.NilError(t, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_Validate_Mutate_Mismatched(t *testing.T) {
|
|
||||||
rawMutate := []byte(`
|
|
||||||
{
|
|
||||||
"overlay": {
|
|
||||||
"spec": {
|
|
||||||
"^(serviceAccountName)": "*",
|
|
||||||
"automountServiceAccountToken": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}`)
|
|
||||||
|
|
||||||
var mutateExistence kyverno.Mutation
|
|
||||||
err := json.Unmarshal(rawMutate, &mutateExistence)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
checker := NewMutateFactory(mutateExistence)
|
|
||||||
if _, err := checker.Validate(); err != nil {
|
|
||||||
assert.Assert(t, err != nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
var mutateEqual kyverno.Mutation
|
|
||||||
rawMutate = []byte(`
|
|
||||||
{
|
|
||||||
"overlay": {
|
|
||||||
"spec": {
|
|
||||||
"=(serviceAccountName)": "*",
|
|
||||||
"automountServiceAccountToken": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}`)
|
|
||||||
|
|
||||||
err = json.Unmarshal(rawMutate, &mutateEqual)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
checker = NewMutateFactory(mutateEqual)
|
|
||||||
if _, err := checker.Validate(); err != nil {
|
|
||||||
assert.Assert(t, err != nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
var mutateNegation kyverno.Mutation
|
|
||||||
rawMutate = []byte(`
|
|
||||||
{
|
|
||||||
"overlay": {
|
|
||||||
"spec": {
|
|
||||||
"X(serviceAccountName)": "*",
|
|
||||||
"automountServiceAccountToken": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}`)
|
|
||||||
|
|
||||||
err = json.Unmarshal(rawMutate, &mutateNegation)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
checker = NewMutateFactory(mutateEqual)
|
|
||||||
if _, err := checker.Validate(); err != nil {
|
|
||||||
assert.Assert(t, err != nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_Validate_Mutate_Unsupported(t *testing.T) {
|
|
||||||
var err error
|
|
||||||
var mutate kyverno.Mutation
|
|
||||||
// case 1
|
|
||||||
rawMutate := []byte(`
|
|
||||||
{
|
|
||||||
"overlay": {
|
|
||||||
"spec": {
|
|
||||||
"!(serviceAccountName)": "*",
|
|
||||||
"automountServiceAccountToken": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}`)
|
|
||||||
|
|
||||||
err = json.Unmarshal(rawMutate, &mutate)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
checker := NewMutateFactory(mutate)
|
|
||||||
if _, err := checker.Validate(); err != nil {
|
|
||||||
assert.Assert(t, err != nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// case 2
|
|
||||||
rawMutate = []byte(`
|
|
||||||
{
|
|
||||||
"overlay": {
|
|
||||||
"spec": {
|
|
||||||
"~(serviceAccountName)": "*",
|
|
||||||
"automountServiceAccountToken": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}`)
|
|
||||||
|
|
||||||
err = json.Unmarshal(rawMutate, &mutate)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
checker = NewMutateFactory(mutate)
|
|
||||||
if _, err := checker.Validate(); err != nil {
|
|
||||||
assert.Assert(t, err != nil)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,13 +1,13 @@
|
||||||
package policy
|
package policy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/golang/glog"
|
||||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||||
cache "k8s.io/client-go/tools/cache"
|
cache "k8s.io/client-go/tools/cache"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (pc *PolicyController) addNamespacedPolicyViolation(obj interface{}) {
|
func (pc *PolicyController) addNamespacedPolicyViolation(obj interface{}) {
|
||||||
pv := obj.(*kyverno.PolicyViolation)
|
pv := obj.(*kyverno.PolicyViolation)
|
||||||
logger := pc.log.WithValues("kind", pv.Kind, "namespace", pv.Namespace, "name", pv.Name)
|
|
||||||
|
|
||||||
if pv.DeletionTimestamp != nil {
|
if pv.DeletionTimestamp != nil {
|
||||||
// On a restart of the controller manager, it's possible for an object to
|
// On a restart of the controller manager, it's possible for an object to
|
||||||
|
@ -20,16 +20,15 @@ func (pc *PolicyController) addNamespacedPolicyViolation(obj interface{}) {
|
||||||
ps := pc.getPolicyForNamespacedPolicyViolation(pv)
|
ps := pc.getPolicyForNamespacedPolicyViolation(pv)
|
||||||
if len(ps) == 0 {
|
if len(ps) == 0 {
|
||||||
// there is no cluster policy for this violation, so we can delete this cluster policy violation
|
// there is no cluster policy for this violation, so we can delete this cluster policy violation
|
||||||
logger.V(4).Info("namepaced policy violation does not belong to an active policy, will be cleanedup")
|
glog.V(4).Infof("PolicyViolation %s does not belong to an active policy, will be cleanedup", pv.Name)
|
||||||
if err := pc.pvControl.DeleteNamespacedPolicyViolation(pv.Namespace, pv.Name); err != nil {
|
if err := pc.pvControl.DeleteNamespacedPolicyViolation(pv.Namespace, pv.Name); err != nil {
|
||||||
logger.Error(err, "failed to delete resource")
|
glog.Errorf("Failed to deleted policy violation %s: %v", pv.Name, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
logger.V(4).Info("resource deleted")
|
glog.V(4).Infof("PolicyViolation %s deleted", pv.Name)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
glog.V(4).Infof("Orphan Policy Violation %s added.", pv.Name)
|
||||||
logger.V(4).Info("resource added")
|
|
||||||
for _, p := range ps {
|
for _, p := range ps {
|
||||||
pc.enqueuePolicy(p)
|
pc.enqueuePolicy(p)
|
||||||
}
|
}
|
||||||
|
@ -43,20 +42,19 @@ func (pc *PolicyController) updateNamespacedPolicyViolation(old, cur interface{}
|
||||||
// Two different versions of the same replica set will always have different RVs.
|
// Two different versions of the same replica set will always have different RVs.
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
logger := pc.log.WithValues("kind", curPV.Kind, "namespace", curPV.Namespace, "name", curPV.Name)
|
|
||||||
|
|
||||||
ps := pc.getPolicyForNamespacedPolicyViolation(curPV)
|
ps := pc.getPolicyForNamespacedPolicyViolation(curPV)
|
||||||
if len(ps) == 0 {
|
if len(ps) == 0 {
|
||||||
// there is no namespaced policy for this violation, so we can delete this cluster policy violation
|
// there is no namespaced policy for this violation, so we can delete this cluster policy violation
|
||||||
logger.V(4).Info("nameapced policy violation does not belong to an active policy, will be cleanedup")
|
glog.V(4).Infof("Namespaced Policy Violation %s does not belong to an active policy, will be cleanedup", curPV.Name)
|
||||||
if err := pc.pvControl.DeleteNamespacedPolicyViolation(curPV.Namespace, curPV.Name); err != nil {
|
if err := pc.pvControl.DeleteNamespacedPolicyViolation(curPV.Namespace, curPV.Name); err != nil {
|
||||||
logger.Error(err, "failed to delete resource")
|
glog.Errorf("Failed to deleted namespaced policy violation %s: %v", curPV.Name, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
logger.V(4).Info("resource deleted")
|
glog.V(4).Infof("Namespaced Policy Violation %s deleted", curPV.Name)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
logger.V(4).Info("resource updated")
|
glog.V(4).Infof("Namespaced Policy sViolation %s updated", curPV.Name)
|
||||||
for _, p := range ps {
|
for _, p := range ps {
|
||||||
pc.enqueuePolicy(p)
|
pc.enqueuePolicy(p)
|
||||||
}
|
}
|
||||||
|
@ -64,7 +62,6 @@ func (pc *PolicyController) updateNamespacedPolicyViolation(old, cur interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pc *PolicyController) deleteNamespacedPolicyViolation(obj interface{}) {
|
func (pc *PolicyController) deleteNamespacedPolicyViolation(obj interface{}) {
|
||||||
logger := pc.log
|
|
||||||
pv, ok := obj.(*kyverno.PolicyViolation)
|
pv, ok := obj.(*kyverno.PolicyViolation)
|
||||||
// When a delete is dropped, the relist will notice a PolicyViolation in the store not
|
// When a delete is dropped, the relist will notice a PolicyViolation in the store not
|
||||||
// in the list, leading to the insertion of a tombstone object which contains
|
// in the list, leading to the insertion of a tombstone object which contains
|
||||||
|
@ -73,36 +70,34 @@ func (pc *PolicyController) deleteNamespacedPolicyViolation(obj interface{}) {
|
||||||
if !ok {
|
if !ok {
|
||||||
tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
|
tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
|
||||||
if !ok {
|
if !ok {
|
||||||
logger.Info("Couldn't get object from tombstone", "obj", obj)
|
glog.Infof("Couldn't get object from tombstone %#v", obj)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
pv, ok = tombstone.Obj.(*kyverno.PolicyViolation)
|
pv, ok = tombstone.Obj.(*kyverno.PolicyViolation)
|
||||||
if !ok {
|
if !ok {
|
||||||
logger.Info("Couldn't get object from tombstone", "obj", obj)
|
glog.Infof("Couldn't get object from tombstone %#v", obj)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
logger = logger.WithValues("kind", pv.Kind, "namespace", pv.Namespace, "name", pv.Name)
|
|
||||||
ps := pc.getPolicyForNamespacedPolicyViolation(pv)
|
ps := pc.getPolicyForNamespacedPolicyViolation(pv)
|
||||||
if len(ps) == 0 {
|
if len(ps) == 0 {
|
||||||
// there is no cluster policy for this violation, so we can delete this cluster policy violation
|
// there is no cluster policy for this violation, so we can delete this cluster policy violation
|
||||||
logger.V(4).Info("nameapced policy violation does not belong to an active policy, will be cleanedup")
|
glog.V(4).Infof("Namespaced Policy Violation %s does not belong to an active policy, will be cleanedup", pv.Name)
|
||||||
if err := pc.pvControl.DeleteNamespacedPolicyViolation(pv.Namespace, pv.Name); err != nil {
|
if err := pc.pvControl.DeleteNamespacedPolicyViolation(pv.Namespace, pv.Name); err != nil {
|
||||||
logger.Error(err, "failed to delete resource")
|
glog.Errorf("Failed to deleted namespaced policy violation %s: %v", pv.Name, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
logger.V(4).Info("resource deleted")
|
glog.V(4).Infof("Namespaced Policy Violation %s deleted", pv.Name)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
logger.V(4).Info("resource updated")
|
glog.V(4).Infof("Namespaced PolicyViolation %s updated", pv.Name)
|
||||||
for _, p := range ps {
|
for _, p := range ps {
|
||||||
pc.enqueuePolicy(p)
|
pc.enqueuePolicy(p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pc *PolicyController) getPolicyForNamespacedPolicyViolation(pv *kyverno.PolicyViolation) []*kyverno.ClusterPolicy {
|
func (pc *PolicyController) getPolicyForNamespacedPolicyViolation(pv *kyverno.PolicyViolation) []*kyverno.ClusterPolicy {
|
||||||
logger := pc.log.WithValues("kind", pv.Kind, "namespace", pv.Namespace, "name", pv.Name)
|
|
||||||
policies, err := pc.pLister.GetPolicyForNamespacedPolicyViolation(pv)
|
policies, err := pc.pLister.GetPolicyForNamespacedPolicyViolation(pv)
|
||||||
if err != nil || len(policies) == 0 {
|
if err != nil || len(policies) == 0 {
|
||||||
return nil
|
return nil
|
||||||
|
@ -114,7 +109,8 @@ func (pc *PolicyController) getPolicyForNamespacedPolicyViolation(pv *kyverno.Po
|
||||||
if len(policies) > 1 {
|
if len(policies) > 1 {
|
||||||
// ControllerRef will ensure we don't do anything crazy, but more than one
|
// ControllerRef will ensure we don't do anything crazy, but more than one
|
||||||
// item in this list nevertheless constitutes user error.
|
// item in this list nevertheless constitutes user error.
|
||||||
logger.V(4).Info("user error! more than one policy is selecting policy violation", "labels", pv.Labels, "policy", policies[0].Name)
|
glog.V(4).Infof("user error! more than one policy is selecting policy violation %s with labels: %#v, returning %s",
|
||||||
|
pv.Name, pv.Labels, policies[0].Name)
|
||||||
}
|
}
|
||||||
return policies
|
return policies
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ package policy
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
"github.com/golang/glog"
|
||||||
"github.com/nirmata/kyverno/pkg/engine/response"
|
"github.com/nirmata/kyverno/pkg/engine/response"
|
||||||
"github.com/nirmata/kyverno/pkg/event"
|
"github.com/nirmata/kyverno/pkg/event"
|
||||||
"github.com/nirmata/kyverno/pkg/policyviolation"
|
"github.com/nirmata/kyverno/pkg/policyviolation"
|
||||||
|
@ -13,12 +13,11 @@ import (
|
||||||
// - has violation -> report
|
// - has violation -> report
|
||||||
// - no violation -> cleanup policy violations
|
// - no violation -> cleanup policy violations
|
||||||
func (pc *PolicyController) cleanupAndReport(engineResponses []response.EngineResponse) {
|
func (pc *PolicyController) cleanupAndReport(engineResponses []response.EngineResponse) {
|
||||||
logger := pc.log
|
|
||||||
// generate Events
|
// generate Events
|
||||||
eventInfos := generateEvents(pc.log, engineResponses)
|
eventInfos := generateEvents(engineResponses)
|
||||||
pc.eventGen.Add(eventInfos...)
|
pc.eventGen.Add(eventInfos...)
|
||||||
// create policy violation
|
// create policy violation
|
||||||
pvInfos := policyviolation.GeneratePVsFromEngineResponse(engineResponses, logger)
|
pvInfos := policyviolation.GeneratePVsFromEngineResponse(engineResponses)
|
||||||
for i := range pvInfos {
|
for i := range pvInfos {
|
||||||
pvInfos[i].FromSync = true
|
pvInfos[i].FromSync = true
|
||||||
}
|
}
|
||||||
|
@ -30,27 +29,39 @@ func (pc *PolicyController) cleanupAndReport(engineResponses []response.EngineRe
|
||||||
pc.cleanUp(engineResponses)
|
pc.cleanUp(engineResponses)
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateEvents(log logr.Logger, ers []response.EngineResponse) []event.Info {
|
func (pc *PolicyController) cleanUp(ers []response.EngineResponse) {
|
||||||
|
for _, er := range ers {
|
||||||
|
if !er.IsSuccesful() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if len(er.PolicyResponse.Rules) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// clean up after the policy has been corrected
|
||||||
|
pc.cleanUpPolicyViolation(er.PolicyResponse)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateEvents(ers []response.EngineResponse) []event.Info {
|
||||||
var eventInfos []event.Info
|
var eventInfos []event.Info
|
||||||
for _, er := range ers {
|
for _, er := range ers {
|
||||||
if er.IsSuccesful() {
|
if er.IsSuccesful() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
eventInfos = append(eventInfos, generateEventsPerEr(log, er)...)
|
eventInfos = append(eventInfos, generateEventsPerEr(er)...)
|
||||||
}
|
}
|
||||||
return eventInfos
|
return eventInfos
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateEventsPerEr(log logr.Logger, er response.EngineResponse) []event.Info {
|
func generateEventsPerEr(er response.EngineResponse) []event.Info {
|
||||||
logger := log.WithValues("policy", er.PolicyResponse.Policy, "kind", er.PolicyResponse.Resource.Kind, "namespace", er.PolicyResponse.Resource.Namespace, "name", er.PolicyResponse.Resource.Name)
|
|
||||||
var eventInfos []event.Info
|
var eventInfos []event.Info
|
||||||
logger.V(4).Info("reporting results for policy")
|
glog.V(4).Infof("reporting results for policy '%s' application on resource '%s/%s/%s'", er.PolicyResponse.Policy, er.PolicyResponse.Resource.Kind, er.PolicyResponse.Resource.Namespace, er.PolicyResponse.Resource.Name)
|
||||||
for _, rule := range er.PolicyResponse.Rules {
|
for _, rule := range er.PolicyResponse.Rules {
|
||||||
if rule.Success {
|
if rule.Success {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// generate event on resource for each failed rule
|
// generate event on resource for each failed rule
|
||||||
logger.V(4).Info("generating event on resource")
|
glog.V(4).Infof("generation event on resource '%s/%s/%s' for policy '%s'", er.PolicyResponse.Resource.Kind, er.PolicyResponse.Resource.Namespace, er.PolicyResponse.Resource.Name, er.PolicyResponse.Policy)
|
||||||
e := event.Info{}
|
e := event.Info{}
|
||||||
e.Kind = er.PolicyResponse.Resource.Kind
|
e.Kind = er.PolicyResponse.Resource.Kind
|
||||||
e.Namespace = er.PolicyResponse.Resource.Namespace
|
e.Namespace = er.PolicyResponse.Resource.Namespace
|
||||||
|
@ -65,7 +76,7 @@ func generateEventsPerEr(log logr.Logger, er response.EngineResponse) []event.In
|
||||||
}
|
}
|
||||||
|
|
||||||
// generate a event on policy for all failed rules
|
// generate a event on policy for all failed rules
|
||||||
logger.V(4).Info("generating event on policy")
|
glog.V(4).Infof("generation event on policy '%s'", er.PolicyResponse.Policy)
|
||||||
e := event.Info{}
|
e := event.Info{}
|
||||||
e.Kind = "ClusterPolicy"
|
e.Kind = "ClusterPolicy"
|
||||||
e.Namespace = ""
|
e.Namespace = ""
|
||||||
|
|
|
@ -5,12 +5,16 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/golang/glog"
|
||||||
|
|
||||||
"github.com/nirmata/kyverno/pkg/openapi"
|
"github.com/nirmata/kyverno/pkg/openapi"
|
||||||
|
|
||||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||||
dclient "github.com/nirmata/kyverno/pkg/dclient"
|
"github.com/nirmata/kyverno/pkg/engine/anchor"
|
||||||
rbacv1 "k8s.io/api/rbac/v1"
|
rbacv1 "k8s.io/api/rbac/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
|
@ -18,10 +22,11 @@ import (
|
||||||
// Validate does some initial check to verify some conditions
|
// Validate does some initial check to verify some conditions
|
||||||
// - One operation per rule
|
// - One operation per rule
|
||||||
// - ResourceDescription mandatory checks
|
// - ResourceDescription mandatory checks
|
||||||
func Validate(policyRaw []byte, client *dclient.Client, mock bool) error {
|
func Validate(policyRaw []byte) error {
|
||||||
var p kyverno.ClusterPolicy
|
var p kyverno.ClusterPolicy
|
||||||
err := json.Unmarshal(policyRaw, &p)
|
err := json.Unmarshal(policyRaw, &p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
glog.Errorf("Failed to unmarshal policy admission request, err %v\n", err)
|
||||||
return fmt.Errorf("failed to unmarshal policy admission request err %v", err)
|
return fmt.Errorf("failed to unmarshal policy admission request err %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,12 +62,24 @@ func Validate(policyRaw []byte, client *dclient.Client, mock bool) error {
|
||||||
// as there are more than 1 operation in rule, not need to evaluate it further
|
// as there are more than 1 operation in rule, not need to evaluate it further
|
||||||
return fmt.Errorf("path: spec.rules[%d]: %v", i, err)
|
return fmt.Errorf("path: spec.rules[%d]: %v", i, err)
|
||||||
}
|
}
|
||||||
// validate rule actions
|
// Operation Validation
|
||||||
// - Mutate
|
// Mutation
|
||||||
// - Validate
|
if rule.HasMutate() {
|
||||||
// - Generate
|
if path, err := validateMutation(rule.Mutation); err != nil {
|
||||||
if err := validateActions(i, rule, client, mock); err != nil {
|
return fmt.Errorf("path: spec.rules[%d].mutate.%s.: %v", i, path, err)
|
||||||
return err
|
}
|
||||||
|
}
|
||||||
|
// Validation
|
||||||
|
if rule.HasValidate() {
|
||||||
|
if path, err := validateValidation(rule.Validation); err != nil {
|
||||||
|
return fmt.Errorf("path: spec.rules[%d].validate.%s.: %v", i, path, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Generation
|
||||||
|
if rule.HasGenerate() {
|
||||||
|
if path, err := validateGeneration(rule.Generation); err != nil {
|
||||||
|
return fmt.Errorf("path: spec.rules[%d].generate.%s.: %v", i, path, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If a rules match block does not match any kind,
|
// If a rules match block does not match any kind,
|
||||||
|
@ -261,3 +278,193 @@ func validateResourceDescription(rd kyverno.ResourceDescription) error {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func validateMutation(m kyverno.Mutation) (string, error) {
|
||||||
|
// JSON Patches
|
||||||
|
if len(m.Patches) != 0 {
|
||||||
|
for i, patch := range m.Patches {
|
||||||
|
if err := validatePatch(patch); err != nil {
|
||||||
|
return fmt.Sprintf("patch[%d]", i), err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Overlay
|
||||||
|
if m.Overlay != nil {
|
||||||
|
path, err := validatePattern(m.Overlay, "/", []anchor.IsAnchor{anchor.IsConditionAnchor, anchor.IsAddingAnchor})
|
||||||
|
if err != nil {
|
||||||
|
return path, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate if all mandatory PolicyPatch fields are set
|
||||||
|
func validatePatch(pp kyverno.Patch) error {
|
||||||
|
if pp.Path == "" {
|
||||||
|
return errors.New("JSONPatch field 'path' is mandatory")
|
||||||
|
}
|
||||||
|
if pp.Operation == "add" || pp.Operation == "replace" {
|
||||||
|
if pp.Value == nil {
|
||||||
|
return fmt.Errorf("JSONPatch field 'value' is mandatory for operation '%s'", pp.Operation)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
} else if pp.Operation == "remove" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("Unsupported JSONPatch operation '%s'", pp.Operation)
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateValidation(v kyverno.Validation) (string, error) {
|
||||||
|
if err := validateOverlayPattern(v); err != nil {
|
||||||
|
// no need to proceed ahead
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Pattern != nil {
|
||||||
|
if path, err := validatePattern(v.Pattern, "/", []anchor.IsAnchor{anchor.IsConditionAnchor, anchor.IsExistenceAnchor, anchor.IsEqualityAnchor, anchor.IsNegationAnchor}); err != nil {
|
||||||
|
return fmt.Sprintf("pattern.%s", path), err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(v.AnyPattern) != 0 {
|
||||||
|
for i, pattern := range v.AnyPattern {
|
||||||
|
if path, err := validatePattern(pattern, "/", []anchor.IsAnchor{anchor.IsConditionAnchor, anchor.IsExistenceAnchor, anchor.IsEqualityAnchor, anchor.IsNegationAnchor}); err != nil {
|
||||||
|
return fmt.Sprintf("anyPattern[%d].%s", i, path), err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// validateOverlayPattern checks one of pattern/anyPattern must exist
|
||||||
|
func validateOverlayPattern(v kyverno.Validation) error {
|
||||||
|
if v.Pattern == nil && len(v.AnyPattern) == 0 {
|
||||||
|
return fmt.Errorf("a pattern or anyPattern must be specified")
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Pattern != nil && len(v.AnyPattern) != 0 {
|
||||||
|
return fmt.Errorf("only one operation allowed per validation rule(pattern or anyPattern)")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate returns error if generator is configured incompletely
|
||||||
|
func validateGeneration(gen kyverno.Generation) (string, error) {
|
||||||
|
|
||||||
|
if gen.Data == nil && gen.Clone == (kyverno.CloneFrom{}) {
|
||||||
|
return "", fmt.Errorf("clone or data are required")
|
||||||
|
}
|
||||||
|
if gen.Data != nil && gen.Clone != (kyverno.CloneFrom{}) {
|
||||||
|
return "", fmt.Errorf("only one operation allowed per generate rule(data or clone)")
|
||||||
|
}
|
||||||
|
// check kind is non empty
|
||||||
|
// check name is non empty
|
||||||
|
if gen.Name == "" {
|
||||||
|
return "name", fmt.Errorf("name cannot be empty")
|
||||||
|
}
|
||||||
|
if gen.Kind == "" {
|
||||||
|
return "kind", fmt.Errorf("kind cannot be empty")
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(gen.Clone, kyverno.CloneFrom{}) {
|
||||||
|
if path, err := validateClone(gen.Clone); err != nil {
|
||||||
|
return fmt.Sprintf("clone.%s", path), err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if gen.Data != nil {
|
||||||
|
//TODO: is this required ?? as anchors can only be on pattern and not resource
|
||||||
|
// we can add this check by not sure if its needed here
|
||||||
|
if path, err := validatePattern(gen.Data, "/", []anchor.IsAnchor{}); err != nil {
|
||||||
|
return fmt.Sprintf("data.%s", path), fmt.Errorf("anchors not supported on generate resources: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateClone(c kyverno.CloneFrom) (string, error) {
|
||||||
|
if c.Name == "" {
|
||||||
|
return "name", fmt.Errorf("name cannot be empty")
|
||||||
|
}
|
||||||
|
if c.Namespace == "" {
|
||||||
|
return "namespace", fmt.Errorf("namespace cannot be empty")
|
||||||
|
}
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func validatePattern(patternElement interface{}, path string, supportedAnchors []anchor.IsAnchor) (string, error) {
|
||||||
|
switch typedPatternElement := patternElement.(type) {
|
||||||
|
case map[string]interface{}:
|
||||||
|
return validateMap(typedPatternElement, path, supportedAnchors)
|
||||||
|
case []interface{}:
|
||||||
|
return validateArray(typedPatternElement, path, supportedAnchors)
|
||||||
|
case string, float64, int, int64, bool, nil:
|
||||||
|
//TODO? check operator
|
||||||
|
return "", nil
|
||||||
|
default:
|
||||||
|
return path, fmt.Errorf("Validation rule failed at '%s', pattern contains unknown type", path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateMap(patternMap map[string]interface{}, path string, supportedAnchors []anchor.IsAnchor) (string, error) {
|
||||||
|
// check if anchors are defined
|
||||||
|
for key, value := range patternMap {
|
||||||
|
// if key is anchor
|
||||||
|
// check regex () -> this is anchor
|
||||||
|
// ()
|
||||||
|
// single char ()
|
||||||
|
re, err := regexp.Compile(`^.?\(.+\)$`)
|
||||||
|
if err != nil {
|
||||||
|
return path + "/" + key, fmt.Errorf("Unable to parse the field %s: %v", key, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
matched := re.MatchString(key)
|
||||||
|
// check the type of anchor
|
||||||
|
if matched {
|
||||||
|
// some type of anchor
|
||||||
|
// check if valid anchor
|
||||||
|
if !checkAnchors(key, supportedAnchors) {
|
||||||
|
return path + "/" + key, fmt.Errorf("Unsupported anchor %s", key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// addition check for existence anchor
|
||||||
|
// value must be of type list
|
||||||
|
if anchor.IsExistenceAnchor(key) {
|
||||||
|
typedValue, ok := value.([]interface{})
|
||||||
|
if !ok {
|
||||||
|
return path + "/" + key, fmt.Errorf("Existence anchor should have value of type list")
|
||||||
|
}
|
||||||
|
// validate there is only one entry in the list
|
||||||
|
if len(typedValue) == 0 || len(typedValue) > 1 {
|
||||||
|
return path + "/" + key, fmt.Errorf("Existence anchor: single value expected, multiple specified")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// lets validate the values now :)
|
||||||
|
if errPath, err := validatePattern(value, path+"/"+key, supportedAnchors); err != nil {
|
||||||
|
return errPath, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateArray(patternArray []interface{}, path string, supportedAnchors []anchor.IsAnchor) (string, error) {
|
||||||
|
for i, patternElement := range patternArray {
|
||||||
|
currentPath := path + strconv.Itoa(i) + "/"
|
||||||
|
// lets validate the values now :)
|
||||||
|
if errPath, err := validatePattern(patternElement, currentPath, supportedAnchors); err != nil {
|
||||||
|
return errPath, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkAnchors(key string, supportedAnchors []anchor.IsAnchor) bool {
|
||||||
|
for _, f := range supportedAnchors {
|
||||||
|
if f(key) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
|
@ -1,61 +0,0 @@
|
||||||
package validate
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
|
||||||
"github.com/nirmata/kyverno/pkg/engine/anchor"
|
|
||||||
"github.com/nirmata/kyverno/pkg/policy/common"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Validate provides implementation to validate 'validate' rule
|
|
||||||
type Validate struct {
|
|
||||||
// rule to hold 'validate' rule specifications
|
|
||||||
rule kyverno.Validation
|
|
||||||
}
|
|
||||||
|
|
||||||
//NewValidateFactory returns a new instance of Mutate validation checker
|
|
||||||
func NewValidateFactory(rule kyverno.Validation) *Validate {
|
|
||||||
m := Validate{
|
|
||||||
rule: rule,
|
|
||||||
}
|
|
||||||
return &m
|
|
||||||
}
|
|
||||||
|
|
||||||
//Validate validates the 'validate' rule
|
|
||||||
func (v *Validate) Validate() (string, error) {
|
|
||||||
rule := v.rule
|
|
||||||
if err := v.validateOverlayPattern(); err != nil {
|
|
||||||
// no need to proceed ahead
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
if rule.Pattern != nil {
|
|
||||||
if path, err := common.ValidatePattern(rule.Pattern, "/", []anchor.IsAnchor{anchor.IsConditionAnchor, anchor.IsExistenceAnchor, anchor.IsEqualityAnchor, anchor.IsNegationAnchor}); err != nil {
|
|
||||||
return fmt.Sprintf("pattern.%s", path), err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(rule.AnyPattern) != 0 {
|
|
||||||
for i, pattern := range rule.AnyPattern {
|
|
||||||
if path, err := common.ValidatePattern(pattern, "/", []anchor.IsAnchor{anchor.IsConditionAnchor, anchor.IsExistenceAnchor, anchor.IsEqualityAnchor, anchor.IsNegationAnchor}); err != nil {
|
|
||||||
return fmt.Sprintf("anyPattern[%d].%s", i, path), err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// validateOverlayPattern checks one of pattern/anyPattern must exist
|
|
||||||
func (v *Validate) validateOverlayPattern() error {
|
|
||||||
rule := v.rule
|
|
||||||
if rule.Pattern == nil && len(rule.AnyPattern) == 0 {
|
|
||||||
return fmt.Errorf("a pattern or anyPattern must be specified")
|
|
||||||
}
|
|
||||||
|
|
||||||
if rule.Pattern != nil && len(rule.AnyPattern) != 0 {
|
|
||||||
return fmt.Errorf("only one operation allowed per validation rule(pattern or anyPattern)")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,381 +0,0 @@
|
||||||
package validate
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
|
||||||
"gotest.tools/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Test_Validate_OverlayPattern_Empty(t *testing.T) {
|
|
||||||
rawValidation := []byte(`
|
|
||||||
{}`)
|
|
||||||
|
|
||||||
var validation kyverno.Validation
|
|
||||||
err := json.Unmarshal(rawValidation, &validation)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
checker := NewValidateFactory(validation)
|
|
||||||
if _, err := checker.Validate(); err != nil {
|
|
||||||
assert.Assert(t, err != nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func Test_Validate_OverlayPattern_Nil_PatternAnypattern(t *testing.T) {
|
|
||||||
rawValidation := []byte(`
|
|
||||||
{ "message": "Privileged mode is not allowed. Set allowPrivilegeEscalation and privileged to false"
|
|
||||||
}
|
|
||||||
`)
|
|
||||||
|
|
||||||
var validation kyverno.Validation
|
|
||||||
err := json.Unmarshal(rawValidation, &validation)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
checker := NewValidateFactory(validation)
|
|
||||||
if _, err := checker.Validate(); err != nil {
|
|
||||||
assert.Assert(t, err != nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_Validate_OverlayPattern_Exist_PatternAnypattern(t *testing.T) {
|
|
||||||
rawValidation := []byte(`
|
|
||||||
{
|
|
||||||
"message": "Privileged mode is not allowed. Set allowPrivilegeEscalation and privileged to false",
|
|
||||||
"anyPattern": [
|
|
||||||
{
|
|
||||||
"spec": {
|
|
||||||
"securityContext": {
|
|
||||||
"allowPrivilegeEscalation": false,
|
|
||||||
"privileged": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"pattern": {
|
|
||||||
"spec": {
|
|
||||||
"containers": [
|
|
||||||
{
|
|
||||||
"name": "*",
|
|
||||||
"securityContext": {
|
|
||||||
"allowPrivilegeEscalation": false,
|
|
||||||
"privileged": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}`)
|
|
||||||
|
|
||||||
var validation kyverno.Validation
|
|
||||||
err := json.Unmarshal(rawValidation, &validation)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
checker := NewValidateFactory(validation)
|
|
||||||
if _, err := checker.Validate(); err != nil {
|
|
||||||
assert.Assert(t, err != nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func Test_Validate_OverlayPattern_Valid(t *testing.T) {
|
|
||||||
rawValidation := []byte(`
|
|
||||||
{
|
|
||||||
"message": "Privileged mode is not allowed. Set allowPrivilegeEscalation and privileged to false",
|
|
||||||
"anyPattern": [
|
|
||||||
{
|
|
||||||
"spec": {
|
|
||||||
"securityContext": {
|
|
||||||
"allowPrivilegeEscalation": false,
|
|
||||||
"privileged": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"spec": {
|
|
||||||
"containers": [
|
|
||||||
{
|
|
||||||
"name": "*",
|
|
||||||
"securityContext": {
|
|
||||||
"allowPrivilegeEscalation": false,
|
|
||||||
"privileged": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
`)
|
|
||||||
|
|
||||||
var validation kyverno.Validation
|
|
||||||
err := json.Unmarshal(rawValidation, &validation)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
checker := NewValidateFactory(validation)
|
|
||||||
if _, err := checker.Validate(); err != nil {
|
|
||||||
assert.NilError(t, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_Validate_ExistingAnchor_AnchorOnMap(t *testing.T) {
|
|
||||||
rawValidation := []byte(`
|
|
||||||
{
|
|
||||||
"message": "validate container security contexts",
|
|
||||||
"anyPattern": [
|
|
||||||
{
|
|
||||||
"spec": {
|
|
||||||
"template": {
|
|
||||||
"spec": {
|
|
||||||
"containers": [
|
|
||||||
{
|
|
||||||
"^(securityContext)": {
|
|
||||||
"runAsNonRoot": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
`)
|
|
||||||
|
|
||||||
var validation kyverno.Validation
|
|
||||||
err := json.Unmarshal(rawValidation, &validation)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
checker := NewValidateFactory(validation)
|
|
||||||
if _, err := checker.Validate(); err != nil {
|
|
||||||
assert.Assert(t, err != nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_Validate_ExistingAnchor_AnchorOnString(t *testing.T) {
|
|
||||||
rawValidation := []byte(`{
|
|
||||||
"message": "validate container security contexts",
|
|
||||||
"pattern": {
|
|
||||||
"spec": {
|
|
||||||
"template": {
|
|
||||||
"spec": {
|
|
||||||
"containers": [
|
|
||||||
{
|
|
||||||
"securityContext": {
|
|
||||||
"allowPrivilegeEscalation": "^(false)"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`)
|
|
||||||
|
|
||||||
var validation kyverno.Validation
|
|
||||||
err := json.Unmarshal(rawValidation, &validation)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
checker := NewValidateFactory(validation)
|
|
||||||
if _, err := checker.Validate(); err != nil {
|
|
||||||
assert.Assert(t, err != nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_Validate_ExistingAnchor_Valid(t *testing.T) {
|
|
||||||
var err error
|
|
||||||
var validation kyverno.Validation
|
|
||||||
rawValidation := []byte(`
|
|
||||||
{
|
|
||||||
"message": "validate container security contexts",
|
|
||||||
"anyPattern": [
|
|
||||||
{
|
|
||||||
"spec": {
|
|
||||||
"template": {
|
|
||||||
"spec": {
|
|
||||||
"^(containers)": [
|
|
||||||
{
|
|
||||||
"securityContext": {
|
|
||||||
"runAsNonRoot": "true"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}`)
|
|
||||||
|
|
||||||
err = json.Unmarshal(rawValidation, &validation)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
checker := NewValidateFactory(validation)
|
|
||||||
if _, err := checker.Validate(); err != nil {
|
|
||||||
assert.Assert(t, err != nil)
|
|
||||||
}
|
|
||||||
rawValidation = []byte(`
|
|
||||||
{
|
|
||||||
"message": "validate container security contexts",
|
|
||||||
"pattern": {
|
|
||||||
"spec": {
|
|
||||||
"template": {
|
|
||||||
"spec": {
|
|
||||||
"^(containers)": [
|
|
||||||
{
|
|
||||||
"securityContext": {
|
|
||||||
"allowPrivilegeEscalation": "false"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} `)
|
|
||||||
err = json.Unmarshal(rawValidation, &validation)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
checker = NewValidateFactory(validation)
|
|
||||||
if _, err := checker.Validate(); err != nil {
|
|
||||||
assert.Assert(t, err != nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_Validate_Validate_ValidAnchor(t *testing.T) {
|
|
||||||
var err error
|
|
||||||
var validate kyverno.Validation
|
|
||||||
var rawValidate []byte
|
|
||||||
// case 1
|
|
||||||
rawValidate = []byte(`
|
|
||||||
{
|
|
||||||
"message": "Root user is not allowed. Set runAsNonRoot to true.",
|
|
||||||
"anyPattern": [
|
|
||||||
{
|
|
||||||
"spec": {
|
|
||||||
"securityContext": {
|
|
||||||
"(runAsNonRoot)": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"spec": {
|
|
||||||
"^(containers)": [
|
|
||||||
{
|
|
||||||
"name": "*",
|
|
||||||
"securityContext": {
|
|
||||||
"runAsNonRoot": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}`)
|
|
||||||
|
|
||||||
err = json.Unmarshal(rawValidate, &validate)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
checker := NewValidateFactory(validate)
|
|
||||||
if _, err := checker.Validate(); err != nil {
|
|
||||||
assert.NilError(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// case 2
|
|
||||||
validate = kyverno.Validation{}
|
|
||||||
rawValidate = []byte(`
|
|
||||||
{
|
|
||||||
"message": "Root user is not allowed. Set runAsNonRoot to true.",
|
|
||||||
"pattern": {
|
|
||||||
"spec": {
|
|
||||||
"=(securityContext)": {
|
|
||||||
"runAsNonRoot": "true"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}`)
|
|
||||||
|
|
||||||
err = json.Unmarshal(rawValidate, &validate)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
checker = NewValidateFactory(validate)
|
|
||||||
if _, err := checker.Validate(); err != nil {
|
|
||||||
assert.NilError(t, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_Validate_Validate_Mismatched(t *testing.T) {
|
|
||||||
rawValidate := []byte(`
|
|
||||||
{
|
|
||||||
"message": "Root user is not allowed. Set runAsNonRoot to true.",
|
|
||||||
"pattern": {
|
|
||||||
"spec": {
|
|
||||||
"containers": [
|
|
||||||
{
|
|
||||||
"name": "*",
|
|
||||||
"securityContext": {
|
|
||||||
"+(runAsNonRoot)": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}`)
|
|
||||||
|
|
||||||
var validate kyverno.Validation
|
|
||||||
err := json.Unmarshal(rawValidate, &validate)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
checker := NewValidateFactory(validate)
|
|
||||||
if _, err := checker.Validate(); err != nil {
|
|
||||||
assert.Assert(t, err != nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_Validate_Validate_Unsupported(t *testing.T) {
|
|
||||||
var err error
|
|
||||||
var validate kyverno.Validation
|
|
||||||
|
|
||||||
// case 1
|
|
||||||
rawValidate := []byte(`
|
|
||||||
{
|
|
||||||
"message": "Root user is not allowed. Set runAsNonRoot to true.",
|
|
||||||
"pattern": {
|
|
||||||
"spec": {
|
|
||||||
"containers": [
|
|
||||||
{
|
|
||||||
"name": "*",
|
|
||||||
"securityContext": {
|
|
||||||
"!(runAsNonRoot)": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}`)
|
|
||||||
|
|
||||||
err = json.Unmarshal(rawValidate, &validate)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
checker := NewValidateFactory(validate)
|
|
||||||
if _, err := checker.Validate(); err != nil {
|
|
||||||
assert.Assert(t, err != nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// case 2
|
|
||||||
rawValidate = []byte(`
|
|
||||||
{
|
|
||||||
"message": "Root user is not allowed. Set runAsNonRoot to true.",
|
|
||||||
"pattern": {
|
|
||||||
"spec": {
|
|
||||||
"containers": [
|
|
||||||
{
|
|
||||||
"name": "*",
|
|
||||||
"securityContext": {
|
|
||||||
"~(runAsNonRoot)": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}`)
|
|
||||||
|
|
||||||
err = json.Unmarshal(rawValidate, &validate)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
checker = NewValidateFactory(validate)
|
|
||||||
if _, err := checker.Validate(); err != nil {
|
|
||||||
assert.Assert(t, err != nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -287,6 +287,369 @@ func Test_Validate_ResourceDescription_InvalidSelector(t *testing.T) {
|
||||||
assert.Assert(t, err != nil)
|
assert.Assert(t, err != nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_Validate_OverlayPattern_Empty(t *testing.T) {
|
||||||
|
rawValidation := []byte(`
|
||||||
|
{}`)
|
||||||
|
|
||||||
|
var validation kyverno.Validation
|
||||||
|
err := json.Unmarshal(rawValidation, &validation)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
if _, err := validateValidation(validation); err != nil {
|
||||||
|
assert.Assert(t, err != nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Validate_OverlayPattern_Nil_PatternAnypattern(t *testing.T) {
|
||||||
|
rawValidation := []byte(`
|
||||||
|
{ "message": "Privileged mode is not allowed. Set allowPrivilegeEscalation and privileged to false"
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
|
||||||
|
var validation kyverno.Validation
|
||||||
|
err := json.Unmarshal(rawValidation, &validation)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
if _, err := validateValidation(validation); err != nil {
|
||||||
|
assert.Assert(t, err != nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Validate_OverlayPattern_Exist_PatternAnypattern(t *testing.T) {
|
||||||
|
rawValidation := []byte(`
|
||||||
|
{
|
||||||
|
"message": "Privileged mode is not allowed. Set allowPrivilegeEscalation and privileged to false",
|
||||||
|
"anyPattern": [
|
||||||
|
{
|
||||||
|
"spec": {
|
||||||
|
"securityContext": {
|
||||||
|
"allowPrivilegeEscalation": false,
|
||||||
|
"privileged": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"pattern": {
|
||||||
|
"spec": {
|
||||||
|
"containers": [
|
||||||
|
{
|
||||||
|
"name": "*",
|
||||||
|
"securityContext": {
|
||||||
|
"allowPrivilegeEscalation": false,
|
||||||
|
"privileged": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`)
|
||||||
|
|
||||||
|
var validation kyverno.Validation
|
||||||
|
err := json.Unmarshal(rawValidation, &validation)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
if _, err := validateValidation(validation); err != nil {
|
||||||
|
assert.Assert(t, err != nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Validate_OverlayPattern_Valid(t *testing.T) {
|
||||||
|
rawValidation := []byte(`
|
||||||
|
{
|
||||||
|
"message": "Privileged mode is not allowed. Set allowPrivilegeEscalation and privileged to false",
|
||||||
|
"anyPattern": [
|
||||||
|
{
|
||||||
|
"spec": {
|
||||||
|
"securityContext": {
|
||||||
|
"allowPrivilegeEscalation": false,
|
||||||
|
"privileged": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"spec": {
|
||||||
|
"containers": [
|
||||||
|
{
|
||||||
|
"name": "*",
|
||||||
|
"securityContext": {
|
||||||
|
"allowPrivilegeEscalation": false,
|
||||||
|
"privileged": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
|
||||||
|
var validation kyverno.Validation
|
||||||
|
err := json.Unmarshal(rawValidation, &validation)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
if _, err := validateValidation(validation); err != nil {
|
||||||
|
assert.NilError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Validate_ExistingAnchor_AnchorOnMap(t *testing.T) {
|
||||||
|
rawValidation := []byte(`
|
||||||
|
{
|
||||||
|
"message": "validate container security contexts",
|
||||||
|
"anyPattern": [
|
||||||
|
{
|
||||||
|
"spec": {
|
||||||
|
"template": {
|
||||||
|
"spec": {
|
||||||
|
"containers": [
|
||||||
|
{
|
||||||
|
"^(securityContext)": {
|
||||||
|
"runAsNonRoot": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
|
||||||
|
var validation kyverno.Validation
|
||||||
|
err := json.Unmarshal(rawValidation, &validation)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
if _, err := validateValidation(validation); err != nil {
|
||||||
|
assert.Assert(t, err != nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Validate_ExistingAnchor_AnchorOnString(t *testing.T) {
|
||||||
|
rawValidation := []byte(`{
|
||||||
|
"message": "validate container security contexts",
|
||||||
|
"pattern": {
|
||||||
|
"spec": {
|
||||||
|
"template": {
|
||||||
|
"spec": {
|
||||||
|
"containers": [
|
||||||
|
{
|
||||||
|
"securityContext": {
|
||||||
|
"allowPrivilegeEscalation": "^(false)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
|
||||||
|
var validation kyverno.Validation
|
||||||
|
err := json.Unmarshal(rawValidation, &validation)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
if _, err := validateValidation(validation); err != nil {
|
||||||
|
assert.Assert(t, err != nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Validate_ExistingAnchor_Valid(t *testing.T) {
|
||||||
|
var err error
|
||||||
|
var validation kyverno.Validation
|
||||||
|
rawValidation := []byte(`
|
||||||
|
{
|
||||||
|
"message": "validate container security contexts",
|
||||||
|
"anyPattern": [
|
||||||
|
{
|
||||||
|
"spec": {
|
||||||
|
"template": {
|
||||||
|
"spec": {
|
||||||
|
"^(containers)": [
|
||||||
|
{
|
||||||
|
"securityContext": {
|
||||||
|
"runAsNonRoot": "true"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}`)
|
||||||
|
|
||||||
|
err = json.Unmarshal(rawValidation, &validation)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
if _, err := validateValidation(validation); err != nil {
|
||||||
|
assert.Assert(t, err != nil)
|
||||||
|
}
|
||||||
|
rawValidation = []byte(`
|
||||||
|
{
|
||||||
|
"message": "validate container security contexts",
|
||||||
|
"pattern": {
|
||||||
|
"spec": {
|
||||||
|
"template": {
|
||||||
|
"spec": {
|
||||||
|
"^(containers)": [
|
||||||
|
{
|
||||||
|
"securityContext": {
|
||||||
|
"allowPrivilegeEscalation": "false"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} `)
|
||||||
|
err = json.Unmarshal(rawValidation, &validation)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
if _, err := validateValidation(validation); err != nil {
|
||||||
|
assert.Assert(t, err != nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Validate_Validate_ValidAnchor(t *testing.T) {
|
||||||
|
var err error
|
||||||
|
var validate kyverno.Validation
|
||||||
|
var rawValidate []byte
|
||||||
|
// case 1
|
||||||
|
rawValidate = []byte(`
|
||||||
|
{
|
||||||
|
"message": "Root user is not allowed. Set runAsNonRoot to true.",
|
||||||
|
"anyPattern": [
|
||||||
|
{
|
||||||
|
"spec": {
|
||||||
|
"securityContext": {
|
||||||
|
"(runAsNonRoot)": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"spec": {
|
||||||
|
"^(containers)": [
|
||||||
|
{
|
||||||
|
"name": "*",
|
||||||
|
"securityContext": {
|
||||||
|
"runAsNonRoot": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}`)
|
||||||
|
|
||||||
|
err = json.Unmarshal(rawValidate, &validate)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
if _, err := validateValidation(validate); err != nil {
|
||||||
|
assert.NilError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// case 2
|
||||||
|
validate = kyverno.Validation{}
|
||||||
|
rawValidate = []byte(`
|
||||||
|
{
|
||||||
|
"message": "Root user is not allowed. Set runAsNonRoot to true.",
|
||||||
|
"pattern": {
|
||||||
|
"spec": {
|
||||||
|
"=(securityContext)": {
|
||||||
|
"runAsNonRoot": "true"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`)
|
||||||
|
|
||||||
|
err = json.Unmarshal(rawValidate, &validate)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
if _, err := validateValidation(validate); err != nil {
|
||||||
|
assert.NilError(t, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Validate_Validate_Mismatched(t *testing.T) {
|
||||||
|
rawValidate := []byte(`
|
||||||
|
{
|
||||||
|
"message": "Root user is not allowed. Set runAsNonRoot to true.",
|
||||||
|
"pattern": {
|
||||||
|
"spec": {
|
||||||
|
"containers": [
|
||||||
|
{
|
||||||
|
"name": "*",
|
||||||
|
"securityContext": {
|
||||||
|
"+(runAsNonRoot)": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`)
|
||||||
|
|
||||||
|
var validate kyverno.Validation
|
||||||
|
err := json.Unmarshal(rawValidate, &validate)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
if _, err := validateValidation(validate); err != nil {
|
||||||
|
assert.Assert(t, err != nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Validate_Validate_Unsupported(t *testing.T) {
|
||||||
|
var err error
|
||||||
|
var validate kyverno.Validation
|
||||||
|
|
||||||
|
// case 1
|
||||||
|
rawValidate := []byte(`
|
||||||
|
{
|
||||||
|
"message": "Root user is not allowed. Set runAsNonRoot to true.",
|
||||||
|
"pattern": {
|
||||||
|
"spec": {
|
||||||
|
"containers": [
|
||||||
|
{
|
||||||
|
"name": "*",
|
||||||
|
"securityContext": {
|
||||||
|
"!(runAsNonRoot)": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`)
|
||||||
|
|
||||||
|
err = json.Unmarshal(rawValidate, &validate)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
if _, err := validateValidation(validate); err != nil {
|
||||||
|
assert.Assert(t, err != nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// case 2
|
||||||
|
rawValidate = []byte(`
|
||||||
|
{
|
||||||
|
"message": "Root user is not allowed. Set runAsNonRoot to true.",
|
||||||
|
"pattern": {
|
||||||
|
"spec": {
|
||||||
|
"containers": [
|
||||||
|
{
|
||||||
|
"name": "*",
|
||||||
|
"securityContext": {
|
||||||
|
"~(runAsNonRoot)": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`)
|
||||||
|
|
||||||
|
err = json.Unmarshal(rawValidate, &validate)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
if _, err := validateValidation(validate); err != nil {
|
||||||
|
assert.Assert(t, err != nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func Test_Validate_Policy(t *testing.T) {
|
func Test_Validate_Policy(t *testing.T) {
|
||||||
rawPolicy := []byte(`
|
rawPolicy := []byte(`
|
||||||
{
|
{
|
||||||
|
@ -369,10 +732,225 @@ func Test_Validate_Policy(t *testing.T) {
|
||||||
}
|
}
|
||||||
}`)
|
}`)
|
||||||
|
|
||||||
err := Validate(rawPolicy, nil, true)
|
err := Validate(rawPolicy)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_Validate_Mutate_ConditionAnchor(t *testing.T) {
|
||||||
|
rawMutate := []byte(`
|
||||||
|
{
|
||||||
|
"overlay": {
|
||||||
|
"spec": {
|
||||||
|
"(serviceAccountName)": "*",
|
||||||
|
"automountServiceAccountToken": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`)
|
||||||
|
|
||||||
|
var mutate kyverno.Mutation
|
||||||
|
err := json.Unmarshal(rawMutate, &mutate)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
if _, err := validateMutation(mutate); err != nil {
|
||||||
|
assert.NilError(t, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Validate_Mutate_PlusAnchor(t *testing.T) {
|
||||||
|
rawMutate := []byte(`
|
||||||
|
{
|
||||||
|
"overlay": {
|
||||||
|
"spec": {
|
||||||
|
"+(serviceAccountName)": "*",
|
||||||
|
"automountServiceAccountToken": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`)
|
||||||
|
|
||||||
|
var mutate kyverno.Mutation
|
||||||
|
err := json.Unmarshal(rawMutate, &mutate)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
if _, err := validateMutation(mutate); err != nil {
|
||||||
|
assert.NilError(t, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Validate_Mutate_Mismatched(t *testing.T) {
|
||||||
|
rawMutate := []byte(`
|
||||||
|
{
|
||||||
|
"overlay": {
|
||||||
|
"spec": {
|
||||||
|
"^(serviceAccountName)": "*",
|
||||||
|
"automountServiceAccountToken": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`)
|
||||||
|
|
||||||
|
var mutateExistence kyverno.Mutation
|
||||||
|
err := json.Unmarshal(rawMutate, &mutateExistence)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
if _, err := validateMutation(mutateExistence); err != nil {
|
||||||
|
assert.Assert(t, err != nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
var mutateEqual kyverno.Mutation
|
||||||
|
rawMutate = []byte(`
|
||||||
|
{
|
||||||
|
"overlay": {
|
||||||
|
"spec": {
|
||||||
|
"=(serviceAccountName)": "*",
|
||||||
|
"automountServiceAccountToken": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`)
|
||||||
|
|
||||||
|
err = json.Unmarshal(rawMutate, &mutateEqual)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
if _, err := validateMutation(mutateEqual); err != nil {
|
||||||
|
assert.Assert(t, err != nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
var mutateNegation kyverno.Mutation
|
||||||
|
rawMutate = []byte(`
|
||||||
|
{
|
||||||
|
"overlay": {
|
||||||
|
"spec": {
|
||||||
|
"X(serviceAccountName)": "*",
|
||||||
|
"automountServiceAccountToken": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`)
|
||||||
|
|
||||||
|
err = json.Unmarshal(rawMutate, &mutateNegation)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
if _, err := validateMutation(mutateEqual); err != nil {
|
||||||
|
assert.Assert(t, err != nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Validate_Mutate_Unsupported(t *testing.T) {
|
||||||
|
var err error
|
||||||
|
var mutate kyverno.Mutation
|
||||||
|
// case 1
|
||||||
|
rawMutate := []byte(`
|
||||||
|
{
|
||||||
|
"overlay": {
|
||||||
|
"spec": {
|
||||||
|
"!(serviceAccountName)": "*",
|
||||||
|
"automountServiceAccountToken": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`)
|
||||||
|
|
||||||
|
err = json.Unmarshal(rawMutate, &mutate)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
if _, err := validateMutation(mutate); err != nil {
|
||||||
|
assert.Assert(t, err != nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// case 2
|
||||||
|
rawMutate = []byte(`
|
||||||
|
{
|
||||||
|
"overlay": {
|
||||||
|
"spec": {
|
||||||
|
"~(serviceAccountName)": "*",
|
||||||
|
"automountServiceAccountToken": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`)
|
||||||
|
|
||||||
|
err = json.Unmarshal(rawMutate, &mutate)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
if _, err := validateMutation(mutate); err != nil {
|
||||||
|
assert.Assert(t, err != nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Validate_Generate(t *testing.T) {
|
||||||
|
rawGenerate := []byte(`
|
||||||
|
{
|
||||||
|
"kind": "NetworkPolicy",
|
||||||
|
"name": "defaultnetworkpolicy",
|
||||||
|
"data": {
|
||||||
|
"spec": {
|
||||||
|
"podSelector": {},
|
||||||
|
"policyTypes": [
|
||||||
|
"Ingress",
|
||||||
|
"Egress"
|
||||||
|
],
|
||||||
|
"ingress": [
|
||||||
|
{}
|
||||||
|
],
|
||||||
|
"egress": [
|
||||||
|
{}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`)
|
||||||
|
|
||||||
|
var generate kyverno.Generation
|
||||||
|
err := json.Unmarshal(rawGenerate, &generate)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
if _, err := validateGeneration(generate); err != nil {
|
||||||
|
assert.Assert(t, err != nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Validate_Generate_HasAnchors(t *testing.T) {
|
||||||
|
var err error
|
||||||
|
var generate kyverno.Generation
|
||||||
|
rawGenerate := []byte(`
|
||||||
|
{
|
||||||
|
"kind": "NetworkPolicy",
|
||||||
|
"name": "defaultnetworkpolicy",
|
||||||
|
"data": {
|
||||||
|
"spec": {
|
||||||
|
"(podSelector)": {},
|
||||||
|
"policyTypes": [
|
||||||
|
"Ingress",
|
||||||
|
"Egress"
|
||||||
|
],
|
||||||
|
"ingress": [
|
||||||
|
{}
|
||||||
|
],
|
||||||
|
"egress": [
|
||||||
|
{}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`)
|
||||||
|
|
||||||
|
err = json.Unmarshal(rawGenerate, &generate)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
if _, err := validateGeneration(generate); err != nil {
|
||||||
|
assert.Assert(t, err != nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
rawGenerate = []byte(`
|
||||||
|
{
|
||||||
|
"kind": "ConfigMap",
|
||||||
|
"name": "copied-cm",
|
||||||
|
"clone": {
|
||||||
|
"^(namespace)": "default",
|
||||||
|
"name": "game"
|
||||||
|
}
|
||||||
|
}`)
|
||||||
|
|
||||||
|
errNew := json.Unmarshal(rawGenerate, &generate)
|
||||||
|
assert.NilError(t, errNew)
|
||||||
|
err = json.Unmarshal(rawGenerate, &generate)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
if _, err := validateGeneration(generate); err != nil {
|
||||||
|
assert.Assert(t, err != nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func Test_Validate_ErrorFormat(t *testing.T) {
|
func Test_Validate_ErrorFormat(t *testing.T) {
|
||||||
rawPolicy := []byte(`
|
rawPolicy := []byte(`
|
||||||
{
|
{
|
||||||
|
@ -511,7 +1089,7 @@ func Test_Validate_ErrorFormat(t *testing.T) {
|
||||||
}
|
}
|
||||||
`)
|
`)
|
||||||
|
|
||||||
err := Validate(rawPolicy, nil, true)
|
err := Validate(rawPolicy)
|
||||||
assert.Assert(t, err != nil)
|
assert.Assert(t, err != nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,25 +1,25 @@
|
||||||
package policy
|
package policy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/golang/glog"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (pc *PolicyController) removeResourceWebhookConfiguration() error {
|
func (pc *PolicyController) removeResourceWebhookConfiguration() error {
|
||||||
logger := pc.log
|
|
||||||
var err error
|
var err error
|
||||||
// get all existing policies
|
// get all existing policies
|
||||||
policies, err := pc.pLister.List(labels.NewSelector())
|
policies, err := pc.pLister.List(labels.NewSelector())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "failed to list policies")
|
glog.V(4).Infof("failed to list policies: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(policies) == 0 {
|
if len(policies) == 0 {
|
||||||
logger.V(4).Info("no policies loaded, removing resource webhook configuration if one exists")
|
glog.V(4).Info("no policies loaded, removing resource webhook configuration if one exists")
|
||||||
return pc.resourceWebhookWatcher.RemoveResourceWebhookConfiguration()
|
return pc.resourceWebhookWatcher.RemoveResourceWebhookConfiguration()
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.V(4).Info("no policies with mutating or validating webhook configurations, remove resource webhook configuration if one exists")
|
glog.V(4).Info("no policies with mutating or validating webhook configurations, remove resource webhook configuration if one exists")
|
||||||
|
|
||||||
return pc.resourceWebhookWatcher.RemoveResourceWebhookConfiguration()
|
return pc.resourceWebhookWatcher.RemoveResourceWebhookConfiguration()
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,16 +2,16 @@ package policystatus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/golang/glog"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
|
|
||||||
"github.com/nirmata/kyverno/pkg/client/clientset/versioned"
|
"github.com/nirmata/kyverno/pkg/client/clientset/versioned"
|
||||||
|
|
||||||
v1 "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
v1 "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||||
log "sigs.k8s.io/controller-runtime/pkg/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Policy status implementation works in the following way,
|
// Policy status implementation works in the following way,
|
||||||
|
@ -111,7 +111,8 @@ func (s *Sync) updateStatusCache(stopCh <-chan struct{}) {
|
||||||
s.cache.keyToMutex.Get(statusUpdater.PolicyName()).Unlock()
|
s.cache.keyToMutex.Get(statusUpdater.PolicyName()).Unlock()
|
||||||
oldStatus, _ := json.Marshal(status)
|
oldStatus, _ := json.Marshal(status)
|
||||||
newStatus, _ := json.Marshal(updatedStatus)
|
newStatus, _ := json.Marshal(updatedStatus)
|
||||||
log.Log.V(4).Info(fmt.Sprintf("\nupdated status of policy - %v\noldStatus:\n%v\nnewStatus:\n%v\n", statusUpdater.PolicyName(), string(oldStatus), string(newStatus)))
|
|
||||||
|
glog.V(4).Infof("\nupdated status of policy - %v\noldStatus:\n%v\nnewStatus:\n%v\n", statusUpdater.PolicyName(), string(oldStatus), string(newStatus))
|
||||||
case <-stopCh:
|
case <-stopCh:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -139,7 +140,7 @@ func (s *Sync) updatePolicyStatus() {
|
||||||
s.cache.dataMu.Lock()
|
s.cache.dataMu.Lock()
|
||||||
delete(s.cache.data, policyName)
|
delete(s.cache.data, policyName)
|
||||||
s.cache.dataMu.Unlock()
|
s.cache.dataMu.Unlock()
|
||||||
log.Log.Error(err, "failed to update policy status")
|
glog.V(4).Info(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,11 +3,12 @@ package policystore
|
||||||
import (
|
import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
|
|
||||||
|
"github.com/golang/glog"
|
||||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||||
kyvernoinformer "github.com/nirmata/kyverno/pkg/client/informers/externalversions/kyverno/v1"
|
kyvernoinformer "github.com/nirmata/kyverno/pkg/client/informers/externalversions/kyverno/v1"
|
||||||
kyvernolister "github.com/nirmata/kyverno/pkg/client/listers/kyverno/v1"
|
kyvernolister "github.com/nirmata/kyverno/pkg/client/listers/kyverno/v1"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
|
||||||
"k8s.io/client-go/tools/cache"
|
"k8s.io/client-go/tools/cache"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -23,7 +24,6 @@ type PolicyStore struct {
|
||||||
pLister kyvernolister.ClusterPolicyLister
|
pLister kyvernolister.ClusterPolicyLister
|
||||||
// returns true if the cluster policy store has been synced at least once
|
// returns true if the cluster policy store has been synced at least once
|
||||||
pSynched cache.InformerSynced
|
pSynched cache.InformerSynced
|
||||||
log logr.Logger
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//UpdateInterface provides api to update policies
|
//UpdateInterface provides api to update policies
|
||||||
|
@ -40,29 +40,25 @@ type LookupInterface interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPolicyStore returns a new policy store
|
// NewPolicyStore returns a new policy store
|
||||||
func NewPolicyStore(pInformer kyvernoinformer.ClusterPolicyInformer,
|
func NewPolicyStore(pInformer kyvernoinformer.ClusterPolicyInformer) *PolicyStore {
|
||||||
log logr.Logger) *PolicyStore {
|
|
||||||
ps := PolicyStore{
|
ps := PolicyStore{
|
||||||
data: make(kindMap),
|
data: make(kindMap),
|
||||||
pLister: pInformer.Lister(),
|
pLister: pInformer.Lister(),
|
||||||
pSynched: pInformer.Informer().HasSynced,
|
pSynched: pInformer.Informer().HasSynced,
|
||||||
log: log,
|
|
||||||
}
|
}
|
||||||
return &ps
|
return &ps
|
||||||
}
|
}
|
||||||
|
|
||||||
//Run checks syncing
|
//Run checks syncing
|
||||||
func (ps *PolicyStore) Run(stopCh <-chan struct{}) {
|
func (ps *PolicyStore) Run(stopCh <-chan struct{}) {
|
||||||
logger := ps.log
|
|
||||||
if !cache.WaitForCacheSync(stopCh, ps.pSynched) {
|
if !cache.WaitForCacheSync(stopCh, ps.pSynched) {
|
||||||
logger.Info("failed to sync informer cache")
|
glog.Error("policy meta store: failed to sync informer cache")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Register a new policy
|
//Register a new policy
|
||||||
func (ps *PolicyStore) Register(policy kyverno.ClusterPolicy) {
|
func (ps *PolicyStore) Register(policy kyverno.ClusterPolicy) {
|
||||||
logger := ps.log
|
glog.V(4).Infof("adding resources %s", policy.Name)
|
||||||
logger.V(4).Info("adding policy", "name", policy.Name)
|
|
||||||
ps.mu.Lock()
|
ps.mu.Lock()
|
||||||
defer ps.mu.Unlock()
|
defer ps.mu.Unlock()
|
||||||
var pmap policyMap
|
var pmap policyMap
|
||||||
|
|
|
@ -3,23 +3,24 @@ package policyviolation
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
"github.com/golang/glog"
|
||||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||||
"github.com/nirmata/kyverno/pkg/engine/response"
|
"github.com/nirmata/kyverno/pkg/engine/response"
|
||||||
)
|
)
|
||||||
|
|
||||||
//GeneratePVsFromEngineResponse generate Violations from engine responses
|
//GeneratePVsFromEngineResponse generate Violations from engine responses
|
||||||
func GeneratePVsFromEngineResponse(ers []response.EngineResponse, log logr.Logger) (pvInfos []Info) {
|
func GeneratePVsFromEngineResponse(ers []response.EngineResponse) (pvInfos []Info) {
|
||||||
for _, er := range ers {
|
for _, er := range ers {
|
||||||
// ignore creation of PV for resources that are yet to be assigned a name
|
// ignore creation of PV for resources that are yet to be assigned a name
|
||||||
if er.PolicyResponse.Resource.Name == "" {
|
if er.PolicyResponse.Resource.Name == "" {
|
||||||
log.V(4).Info("resource does no have a name assigned yet, not creating a policy violation", "resource", er.PolicyResponse.Resource)
|
glog.V(4).Infof("resource %v, has not been assigned a name, not creating a policy violation for it", er.PolicyResponse.Resource)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// skip when response succeed
|
// skip when response succeed
|
||||||
if er.IsSuccesful() {
|
if er.IsSuccesful() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
glog.V(4).Infof("Building policy violation for engine response %v", er)
|
||||||
// build policy violation info
|
// build policy violation info
|
||||||
pvInfos = append(pvInfos, buildPVInfo(er))
|
pvInfos = append(pvInfos, buildPVInfo(er))
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@ import (
|
||||||
|
|
||||||
"github.com/nirmata/kyverno/pkg/engine/response"
|
"github.com/nirmata/kyverno/pkg/engine/response"
|
||||||
"gotest.tools/assert"
|
"gotest.tools/assert"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_GeneratePVsFromEngineResponse_PathNotExist(t *testing.T) {
|
func Test_GeneratePVsFromEngineResponse_PathNotExist(t *testing.T) {
|
||||||
|
@ -53,6 +52,6 @@ func Test_GeneratePVsFromEngineResponse_PathNotExist(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
pvInfos := GeneratePVsFromEngineResponse(ers, log.Log)
|
pvInfos := GeneratePVsFromEngineResponse(ers)
|
||||||
assert.Assert(t, len(pvInfos) == 1)
|
assert.Assert(t, len(pvInfos) == 1)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
"github.com/golang/glog"
|
||||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||||
kyvernov1 "github.com/nirmata/kyverno/pkg/client/clientset/versioned/typed/kyverno/v1"
|
kyvernov1 "github.com/nirmata/kyverno/pkg/client/clientset/versioned/typed/kyverno/v1"
|
||||||
kyvernolister "github.com/nirmata/kyverno/pkg/client/listers/kyverno/v1"
|
kyvernolister "github.com/nirmata/kyverno/pkg/client/listers/kyverno/v1"
|
||||||
|
@ -21,13 +21,11 @@ type clusterPV struct {
|
||||||
cpvLister kyvernolister.ClusterPolicyViolationLister
|
cpvLister kyvernolister.ClusterPolicyViolationLister
|
||||||
// policy violation interface
|
// policy violation interface
|
||||||
kyvernoInterface kyvernov1.KyvernoV1Interface
|
kyvernoInterface kyvernov1.KyvernoV1Interface
|
||||||
// logger
|
|
||||||
log logr.Logger
|
|
||||||
// update policy stats with violationCount
|
// update policy stats with violationCount
|
||||||
policyStatusListener policystatus.Listener
|
policyStatusListener policystatus.Listener
|
||||||
}
|
}
|
||||||
|
|
||||||
func newClusterPV(log logr.Logger, dclient *client.Client,
|
func newClusterPV(dclient *client.Client,
|
||||||
cpvLister kyvernolister.ClusterPolicyViolationLister,
|
cpvLister kyvernolister.ClusterPolicyViolationLister,
|
||||||
kyvernoInterface kyvernov1.KyvernoV1Interface,
|
kyvernoInterface kyvernov1.KyvernoV1Interface,
|
||||||
policyStatus policystatus.Listener,
|
policyStatus policystatus.Listener,
|
||||||
|
@ -36,7 +34,6 @@ func newClusterPV(log logr.Logger, dclient *client.Client,
|
||||||
dclient: dclient,
|
dclient: dclient,
|
||||||
cpvLister: cpvLister,
|
cpvLister: cpvLister,
|
||||||
kyvernoInterface: kyvernoInterface,
|
kyvernoInterface: kyvernoInterface,
|
||||||
log: log,
|
|
||||||
policyStatusListener: policyStatus,
|
policyStatusListener: policyStatus,
|
||||||
}
|
}
|
||||||
return &cpv
|
return &cpv
|
||||||
|
@ -59,7 +56,6 @@ func (cpv *clusterPV) create(pv kyverno.PolicyViolationTemplate) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cpv *clusterPV) getExisting(newPv kyverno.ClusterPolicyViolation) (*kyverno.ClusterPolicyViolation, error) {
|
func (cpv *clusterPV) getExisting(newPv kyverno.ClusterPolicyViolation) (*kyverno.ClusterPolicyViolation, error) {
|
||||||
logger := cpv.log.WithValues("namespace", newPv.Namespace, "name", newPv.Name)
|
|
||||||
var err error
|
var err error
|
||||||
// use labels
|
// use labels
|
||||||
policyLabelmap := map[string]string{"policy": newPv.Spec.Policy, "resource": newPv.Spec.ResourceSpec.ToKey()}
|
policyLabelmap := map[string]string{"policy": newPv.Spec.Policy, "resource": newPv.Spec.ResourceSpec.ToKey()}
|
||||||
|
@ -70,7 +66,7 @@ func (cpv *clusterPV) getExisting(newPv kyverno.ClusterPolicyViolation) (*kyvern
|
||||||
|
|
||||||
pvs, err := cpv.cpvLister.List(ls)
|
pvs, err := cpv.cpvLister.List(ls)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "failed to list cluster policy violations")
|
glog.Errorf("unable to list cluster policy violations : %v", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,8 +83,7 @@ func (cpv *clusterPV) getExisting(newPv kyverno.ClusterPolicyViolation) (*kyvern
|
||||||
|
|
||||||
func (cpv *clusterPV) createPV(newPv *kyverno.ClusterPolicyViolation) error {
|
func (cpv *clusterPV) createPV(newPv *kyverno.ClusterPolicyViolation) error {
|
||||||
var err error
|
var err error
|
||||||
logger := cpv.log.WithValues("policy", newPv.Spec.Policy, "kind", newPv.Spec.ResourceSpec.Kind, "namespace", newPv.Spec.ResourceSpec.Namespace, "name", newPv.Spec.ResourceSpec.Name)
|
glog.V(4).Infof("creating new policy violation for policy %s & resource %s/%s", newPv.Spec.Policy, newPv.Spec.ResourceSpec.Kind, newPv.Spec.ResourceSpec.Name)
|
||||||
logger.V(4).Info("creating new policy violation")
|
|
||||||
obj, err := retryGetResource(cpv.dclient, newPv.Spec.ResourceSpec)
|
obj, err := retryGetResource(cpv.dclient, newPv.Spec.ResourceSpec)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to retry getting resource for policy violation %s/%s: %v", newPv.Name, newPv.Spec.Policy, err)
|
return fmt.Errorf("failed to retry getting resource for policy violation %s/%s: %v", newPv.Name, newPv.Spec.Policy, err)
|
||||||
|
@ -100,7 +95,7 @@ func (cpv *clusterPV) createPV(newPv *kyverno.ClusterPolicyViolation) error {
|
||||||
// create resource
|
// create resource
|
||||||
_, err = cpv.kyvernoInterface.ClusterPolicyViolations().Create(newPv)
|
_, err = cpv.kyvernoInterface.ClusterPolicyViolations().Create(newPv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "failed to create cluster policy violation")
|
glog.V(4).Infof("failed to create Cluster Policy Violation: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,16 +103,15 @@ func (cpv *clusterPV) createPV(newPv *kyverno.ClusterPolicyViolation) error {
|
||||||
cpv.policyStatusListener.Send(violationCount{policyName: newPv.Spec.Policy, violatedRules: newPv.Spec.ViolatedRules})
|
cpv.policyStatusListener.Send(violationCount{policyName: newPv.Spec.Policy, violatedRules: newPv.Spec.ViolatedRules})
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Info("cluster policy violation created")
|
glog.Infof("policy violation created for resource %v", newPv.Spec.ResourceSpec)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cpv *clusterPV) updatePV(newPv, oldPv *kyverno.ClusterPolicyViolation) error {
|
func (cpv *clusterPV) updatePV(newPv, oldPv *kyverno.ClusterPolicyViolation) error {
|
||||||
logger := cpv.log.WithValues("policy", newPv.Spec.Policy, "kind", newPv.Spec.ResourceSpec.Kind, "namespace", newPv.Spec.ResourceSpec.Namespace, "name", newPv.Spec.ResourceSpec.Name)
|
|
||||||
var err error
|
var err error
|
||||||
// check if there is any update
|
// check if there is any update
|
||||||
if reflect.DeepEqual(newPv.Spec, oldPv.Spec) {
|
if reflect.DeepEqual(newPv.Spec, oldPv.Spec) {
|
||||||
logger.V(4).Info("policy violation spec did not change, not upadating the resource")
|
glog.V(4).Infof("policy violation spec %v did not change so not updating it", newPv.Spec)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// set name
|
// set name
|
||||||
|
@ -129,7 +123,7 @@ func (cpv *clusterPV) updatePV(newPv, oldPv *kyverno.ClusterPolicyViolation) err
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to update cluster policy violation: %v", err)
|
return fmt.Errorf("failed to update cluster policy violation: %v", err)
|
||||||
}
|
}
|
||||||
logger.Info("cluster policy violation created")
|
glog.Infof("cluster policy violation updated for resource %v", newPv.Spec.ResourceSpec)
|
||||||
|
|
||||||
if newPv.Annotations["fromSync"] != "true" {
|
if newPv.Annotations["fromSync"] != "true" {
|
||||||
cpv.policyStatusListener.Send(violationCount{policyName: newPv.Spec.Policy, violatedRules: newPv.Spec.ViolatedRules})
|
cpv.policyStatusListener.Send(violationCount{policyName: newPv.Spec.Policy, violatedRules: newPv.Spec.ViolatedRules})
|
||||||
|
|
|
@ -5,13 +5,13 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
backoff "github.com/cenkalti/backoff"
|
backoff "github.com/cenkalti/backoff"
|
||||||
|
"github.com/golang/glog"
|
||||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||||
v1 "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
v1 "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||||
client "github.com/nirmata/kyverno/pkg/dclient"
|
client "github.com/nirmata/kyverno/pkg/dclient"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
unstructured "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
unstructured "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func createOwnerReference(resource *unstructured.Unstructured) metav1.OwnerReference {
|
func createOwnerReference(resource *unstructured.Unstructured) metav1.OwnerReference {
|
||||||
|
@ -34,7 +34,7 @@ func retryGetResource(client *client.Client, rspec kyverno.ResourceSpec) (*unstr
|
||||||
var err error
|
var err error
|
||||||
getResource := func() error {
|
getResource := func() error {
|
||||||
obj, err = client.GetResource(rspec.Kind, rspec.Namespace, rspec.Name)
|
obj, err = client.GetResource(rspec.Kind, rspec.Namespace, rspec.Name)
|
||||||
log.Log.V(4).Info(fmt.Sprintf("retry %v getting %s/%s/%s", i, rspec.Kind, rspec.Namespace, rspec.Name))
|
glog.V(4).Infof("retry %v getting %s/%s/%s", i, rspec.Kind, rspec.Namespace, rspec.Name)
|
||||||
i++
|
i++
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
"github.com/golang/glog"
|
||||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||||
kyvernoclient "github.com/nirmata/kyverno/pkg/client/clientset/versioned"
|
kyvernoclient "github.com/nirmata/kyverno/pkg/client/clientset/versioned"
|
||||||
kyvernov1 "github.com/nirmata/kyverno/pkg/client/clientset/versioned/typed/kyverno/v1"
|
kyvernov1 "github.com/nirmata/kyverno/pkg/client/clientset/versioned/typed/kyverno/v1"
|
||||||
|
@ -38,7 +38,6 @@ type Generator struct {
|
||||||
// returns true if the cluster policy store has been synced at least once
|
// returns true if the cluster policy store has been synced at least once
|
||||||
pvSynced cache.InformerSynced
|
pvSynced cache.InformerSynced
|
||||||
// returns true if the namespaced cluster policy store has been synced at at least once
|
// returns true if the namespaced cluster policy store has been synced at at least once
|
||||||
log logr.Logger
|
|
||||||
nspvSynced cache.InformerSynced
|
nspvSynced cache.InformerSynced
|
||||||
queue workqueue.RateLimitingInterface
|
queue workqueue.RateLimitingInterface
|
||||||
dataStore *dataStore
|
dataStore *dataStore
|
||||||
|
@ -108,8 +107,7 @@ func NewPVGenerator(client *kyvernoclient.Clientset,
|
||||||
dclient *dclient.Client,
|
dclient *dclient.Client,
|
||||||
pvInformer kyvernoinformer.ClusterPolicyViolationInformer,
|
pvInformer kyvernoinformer.ClusterPolicyViolationInformer,
|
||||||
nspvInformer kyvernoinformer.PolicyViolationInformer,
|
nspvInformer kyvernoinformer.PolicyViolationInformer,
|
||||||
policyStatus policystatus.Listener,
|
policyStatus policystatus.Listener) *Generator {
|
||||||
log logr.Logger) *Generator {
|
|
||||||
gen := Generator{
|
gen := Generator{
|
||||||
kyvernoInterface: client.KyvernoV1(),
|
kyvernoInterface: client.KyvernoV1(),
|
||||||
dclient: dclient,
|
dclient: dclient,
|
||||||
|
@ -119,7 +117,6 @@ func NewPVGenerator(client *kyvernoclient.Clientset,
|
||||||
nspvSynced: nspvInformer.Informer().HasSynced,
|
nspvSynced: nspvInformer.Informer().HasSynced,
|
||||||
queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), workQueueName),
|
queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), workQueueName),
|
||||||
dataStore: newDataStore(),
|
dataStore: newDataStore(),
|
||||||
log: log,
|
|
||||||
policyStatusListener: policyStatus,
|
policyStatusListener: policyStatus,
|
||||||
}
|
}
|
||||||
return &gen
|
return &gen
|
||||||
|
@ -138,18 +135,18 @@ func (gen *Generator) enqueue(info Info) {
|
||||||
func (gen *Generator) Add(infos ...Info) {
|
func (gen *Generator) Add(infos ...Info) {
|
||||||
for _, info := range infos {
|
for _, info := range infos {
|
||||||
gen.enqueue(info)
|
gen.enqueue(info)
|
||||||
|
glog.V(3).Infof("Added policy violation: %s", info.toKey())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run starts the workers
|
// Run starts the workers
|
||||||
func (gen *Generator) Run(workers int, stopCh <-chan struct{}) {
|
func (gen *Generator) Run(workers int, stopCh <-chan struct{}) {
|
||||||
logger := gen.log
|
|
||||||
defer utilruntime.HandleCrash()
|
defer utilruntime.HandleCrash()
|
||||||
logger.Info("start")
|
glog.Info("Start policy violation generator")
|
||||||
defer logger.Info("shutting down")
|
defer glog.Info("Shutting down policy violation generator")
|
||||||
|
|
||||||
if !cache.WaitForCacheSync(stopCh, gen.pvSynced, gen.nspvSynced) {
|
if !cache.WaitForCacheSync(stopCh, gen.pvSynced, gen.nspvSynced) {
|
||||||
logger.Info("failed to sync informer cache")
|
glog.Error("policy violation generator: failed to sync informer cache")
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < workers; i++ {
|
for i := 0; i < workers; i++ {
|
||||||
|
@ -164,7 +161,6 @@ func (gen *Generator) runWorker() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gen *Generator) handleErr(err error, key interface{}) {
|
func (gen *Generator) handleErr(err error, key interface{}) {
|
||||||
logger := gen.log
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
gen.queue.Forget(key)
|
gen.queue.Forget(key)
|
||||||
return
|
return
|
||||||
|
@ -172,22 +168,23 @@ func (gen *Generator) handleErr(err error, key interface{}) {
|
||||||
|
|
||||||
// retires requests if there is error
|
// retires requests if there is error
|
||||||
if gen.queue.NumRequeues(key) < workQueueRetryLimit {
|
if gen.queue.NumRequeues(key) < workQueueRetryLimit {
|
||||||
logger.Error(err, "failed to sync policy violation", "key", key)
|
glog.V(4).Infof("Error syncing policy violation %v: %v", key, err)
|
||||||
// Re-enqueue the key rate limited. Based on the rate limiter on the
|
// Re-enqueue the key rate limited. Based on the rate limiter on the
|
||||||
// queue and the re-enqueue history, the key will be processed later again.
|
// queue and the re-enqueue history, the key will be processed later again.
|
||||||
gen.queue.AddRateLimited(key)
|
gen.queue.AddRateLimited(key)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
gen.queue.Forget(key)
|
gen.queue.Forget(key)
|
||||||
|
glog.Error(err)
|
||||||
// remove from data store
|
// remove from data store
|
||||||
if keyHash, ok := key.(string); ok {
|
if keyHash, ok := key.(string); ok {
|
||||||
gen.dataStore.delete(keyHash)
|
gen.dataStore.delete(keyHash)
|
||||||
}
|
}
|
||||||
logger.Error(err, "dropping key out of the queue", "key", key)
|
|
||||||
|
glog.Warningf("Dropping the key out of the queue: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gen *Generator) processNextWorkitem() bool {
|
func (gen *Generator) processNextWorkitem() bool {
|
||||||
logger := gen.log
|
|
||||||
obj, shutdown := gen.queue.Get()
|
obj, shutdown := gen.queue.Get()
|
||||||
if shutdown {
|
if shutdown {
|
||||||
return false
|
return false
|
||||||
|
@ -199,7 +196,7 @@ func (gen *Generator) processNextWorkitem() bool {
|
||||||
var ok bool
|
var ok bool
|
||||||
if keyHash, ok = obj.(string); !ok {
|
if keyHash, ok = obj.(string); !ok {
|
||||||
gen.queue.Forget(obj)
|
gen.queue.Forget(obj)
|
||||||
logger.Info("incorrect type; expecting type 'string'", "obj", obj)
|
glog.Warningf("Expecting type string but got %v\n", obj)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// lookup data store
|
// lookup data store
|
||||||
|
@ -207,7 +204,7 @@ func (gen *Generator) processNextWorkitem() bool {
|
||||||
if reflect.DeepEqual(info, Info{}) {
|
if reflect.DeepEqual(info, Info{}) {
|
||||||
// empty key
|
// empty key
|
||||||
gen.queue.Forget(obj)
|
gen.queue.Forget(obj)
|
||||||
logger.Info("empty key")
|
glog.Warningf("Got empty key %v\n", obj)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
err := gen.syncHandler(info)
|
err := gen.syncHandler(info)
|
||||||
|
@ -215,22 +212,22 @@ func (gen *Generator) processNextWorkitem() bool {
|
||||||
return nil
|
return nil
|
||||||
}(obj)
|
}(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "failed to process item")
|
glog.Error(err)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gen *Generator) syncHandler(info Info) error {
|
func (gen *Generator) syncHandler(info Info) error {
|
||||||
logger := gen.log
|
glog.V(4).Infof("received info:%v", info)
|
||||||
var handler pvGenerator
|
var handler pvGenerator
|
||||||
builder := newPvBuilder()
|
builder := newPvBuilder()
|
||||||
if info.Resource.GetNamespace() == "" {
|
if info.Resource.GetNamespace() == "" {
|
||||||
// cluster scope resource generate a clusterpolicy violation
|
// cluster scope resource generate a clusterpolicy violation
|
||||||
handler = newClusterPV(gen.log.WithName("ClusterPV"), gen.dclient, gen.cpvLister, gen.kyvernoInterface, gen.policyStatusListener)
|
handler = newClusterPV(gen.dclient, gen.cpvLister, gen.kyvernoInterface, gen.policyStatusListener)
|
||||||
} else {
|
} else {
|
||||||
// namespaced resources generated a namespaced policy violation in the namespace of the resource
|
// namespaced resources generated a namespaced policy violation in the namespace of the resource
|
||||||
handler = newNamespacedPV(gen.log.WithName("NamespacedPV"), gen.dclient, gen.nspvLister, gen.kyvernoInterface, gen.policyStatusListener)
|
handler = newNamespacedPV(gen.dclient, gen.nspvLister, gen.kyvernoInterface, gen.policyStatusListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
failure := false
|
failure := false
|
||||||
|
@ -243,12 +240,12 @@ func (gen *Generator) syncHandler(info Info) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create Policy Violations
|
// Create Policy Violations
|
||||||
logger.V(4).Info("creating policy violation", "key", info.toKey())
|
glog.V(3).Infof("Creating policy violation: %s", info.toKey())
|
||||||
if err := handler.create(pv); err != nil {
|
if err := handler.create(pv); err != nil {
|
||||||
failure = true
|
failure = true
|
||||||
logger.Error(err, "failed to create policy violation")
|
glog.V(3).Infof("Failed to create policy violation: %v", err)
|
||||||
} else {
|
} else {
|
||||||
logger.Info("created policy violation", "key", info.toKey())
|
glog.V(3).Infof("Policy violation created: %s", info.toKey())
|
||||||
}
|
}
|
||||||
|
|
||||||
if failure {
|
if failure {
|
||||||
|
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
"github.com/golang/glog"
|
||||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||||
kyvernov1 "github.com/nirmata/kyverno/pkg/client/clientset/versioned/typed/kyverno/v1"
|
kyvernov1 "github.com/nirmata/kyverno/pkg/client/clientset/versioned/typed/kyverno/v1"
|
||||||
kyvernolister "github.com/nirmata/kyverno/pkg/client/listers/kyverno/v1"
|
kyvernolister "github.com/nirmata/kyverno/pkg/client/listers/kyverno/v1"
|
||||||
|
@ -21,13 +21,11 @@ type namespacedPV struct {
|
||||||
nspvLister kyvernolister.PolicyViolationLister
|
nspvLister kyvernolister.PolicyViolationLister
|
||||||
// policy violation interface
|
// policy violation interface
|
||||||
kyvernoInterface kyvernov1.KyvernoV1Interface
|
kyvernoInterface kyvernov1.KyvernoV1Interface
|
||||||
// logger
|
|
||||||
log logr.Logger
|
|
||||||
// update policy status with violationCount
|
// update policy status with violationCount
|
||||||
policyStatusListener policystatus.Listener
|
policyStatusListener policystatus.Listener
|
||||||
}
|
}
|
||||||
|
|
||||||
func newNamespacedPV(log logr.Logger, dclient *client.Client,
|
func newNamespacedPV(dclient *client.Client,
|
||||||
nspvLister kyvernolister.PolicyViolationLister,
|
nspvLister kyvernolister.PolicyViolationLister,
|
||||||
kyvernoInterface kyvernov1.KyvernoV1Interface,
|
kyvernoInterface kyvernov1.KyvernoV1Interface,
|
||||||
policyStatus policystatus.Listener,
|
policyStatus policystatus.Listener,
|
||||||
|
@ -36,7 +34,6 @@ func newNamespacedPV(log logr.Logger, dclient *client.Client,
|
||||||
dclient: dclient,
|
dclient: dclient,
|
||||||
nspvLister: nspvLister,
|
nspvLister: nspvLister,
|
||||||
kyvernoInterface: kyvernoInterface,
|
kyvernoInterface: kyvernoInterface,
|
||||||
log: log,
|
|
||||||
policyStatusListener: policyStatus,
|
policyStatusListener: policyStatus,
|
||||||
}
|
}
|
||||||
return &nspv
|
return &nspv
|
||||||
|
@ -59,7 +56,6 @@ func (nspv *namespacedPV) create(pv kyverno.PolicyViolationTemplate) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (nspv *namespacedPV) getExisting(newPv kyverno.PolicyViolation) (*kyverno.PolicyViolation, error) {
|
func (nspv *namespacedPV) getExisting(newPv kyverno.PolicyViolation) (*kyverno.PolicyViolation, error) {
|
||||||
logger := nspv.log.WithValues("namespace", newPv.Namespace, "name", newPv.Name)
|
|
||||||
var err error
|
var err error
|
||||||
// use labels
|
// use labels
|
||||||
policyLabelmap := map[string]string{"policy": newPv.Spec.Policy, "resource": newPv.Spec.ResourceSpec.ToKey()}
|
policyLabelmap := map[string]string{"policy": newPv.Spec.Policy, "resource": newPv.Spec.ResourceSpec.ToKey()}
|
||||||
|
@ -69,7 +65,7 @@ func (nspv *namespacedPV) getExisting(newPv kyverno.PolicyViolation) (*kyverno.P
|
||||||
}
|
}
|
||||||
pvs, err := nspv.nspvLister.PolicyViolations(newPv.GetNamespace()).List(ls)
|
pvs, err := nspv.nspvLister.PolicyViolations(newPv.GetNamespace()).List(ls)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "failed to list namespaced policy violations")
|
glog.Errorf("unable to list namespaced policy violations : %v", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,8 +82,7 @@ func (nspv *namespacedPV) getExisting(newPv kyverno.PolicyViolation) (*kyverno.P
|
||||||
|
|
||||||
func (nspv *namespacedPV) createPV(newPv *kyverno.PolicyViolation) error {
|
func (nspv *namespacedPV) createPV(newPv *kyverno.PolicyViolation) error {
|
||||||
var err error
|
var err error
|
||||||
logger := nspv.log.WithValues("policy", newPv.Spec.Policy, "kind", newPv.Spec.ResourceSpec.Kind, "namespace", newPv.Spec.ResourceSpec.Namespace, "name", newPv.Spec.ResourceSpec.Name)
|
glog.V(4).Infof("creating new policy violation for policy %s & resource %s/%s/%s", newPv.Spec.Policy, newPv.Spec.ResourceSpec.Kind, newPv.Spec.ResourceSpec.Namespace, newPv.Spec.ResourceSpec.Name)
|
||||||
logger.V(4).Info("creating new policy violation")
|
|
||||||
obj, err := retryGetResource(nspv.dclient, newPv.Spec.ResourceSpec)
|
obj, err := retryGetResource(nspv.dclient, newPv.Spec.ResourceSpec)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to retry getting resource for policy violation %s/%s: %v", newPv.Name, newPv.Spec.Policy, err)
|
return fmt.Errorf("failed to retry getting resource for policy violation %s/%s: %v", newPv.Name, newPv.Spec.Policy, err)
|
||||||
|
@ -99,23 +94,22 @@ func (nspv *namespacedPV) createPV(newPv *kyverno.PolicyViolation) error {
|
||||||
// create resource
|
// create resource
|
||||||
_, err = nspv.kyvernoInterface.PolicyViolations(newPv.GetNamespace()).Create(newPv)
|
_, err = nspv.kyvernoInterface.PolicyViolations(newPv.GetNamespace()).Create(newPv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "failed to create namespaced policy violation")
|
glog.V(4).Infof("failed to create Cluster Policy Violation: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if newPv.Annotations["fromSync"] != "true" {
|
if newPv.Annotations["fromSync"] != "true" {
|
||||||
nspv.policyStatusListener.Send(violationCount{policyName: newPv.Spec.Policy, violatedRules: newPv.Spec.ViolatedRules})
|
nspv.policyStatusListener.Send(violationCount{policyName: newPv.Spec.Policy, violatedRules: newPv.Spec.ViolatedRules})
|
||||||
}
|
}
|
||||||
logger.Info("namespaced policy violation created")
|
glog.Infof("policy violation created for resource %v", newPv.Spec.ResourceSpec)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (nspv *namespacedPV) updatePV(newPv, oldPv *kyverno.PolicyViolation) error {
|
func (nspv *namespacedPV) updatePV(newPv, oldPv *kyverno.PolicyViolation) error {
|
||||||
logger := nspv.log.WithValues("policy", newPv.Spec.Policy, "kind", newPv.Spec.ResourceSpec.Kind, "namespace", newPv.Spec.ResourceSpec.Namespace, "name", newPv.Spec.ResourceSpec.Name)
|
|
||||||
var err error
|
var err error
|
||||||
// check if there is any update
|
// check if there is any update
|
||||||
if reflect.DeepEqual(newPv.Spec, oldPv.Spec) {
|
if reflect.DeepEqual(newPv.Spec, oldPv.Spec) {
|
||||||
logger.V(4).Info("policy violation spec did not change, not upadating the resource")
|
glog.V(4).Infof("policy violation spec %v did not change so not updating it", newPv.Spec)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// set name
|
// set name
|
||||||
|
@ -130,6 +124,6 @@ func (nspv *namespacedPV) updatePV(newPv, oldPv *kyverno.PolicyViolation) error
|
||||||
if newPv.Annotations["fromSync"] != "true" {
|
if newPv.Annotations["fromSync"] != "true" {
|
||||||
nspv.policyStatusListener.Send(violationCount{policyName: newPv.Spec.Policy, violatedRules: newPv.Spec.ViolatedRules})
|
nspv.policyStatusListener.Send(violationCount{policyName: newPv.Spec.Policy, violatedRules: newPv.Spec.ViolatedRules})
|
||||||
}
|
}
|
||||||
logger.Info("namespaced policy violation created")
|
glog.Infof("namespaced policy violation updated for resource %v", newPv.Spec.ResourceSpec)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package testrunner
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"flag"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
ospath "path"
|
ospath "path"
|
||||||
|
@ -18,6 +19,7 @@ import (
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
"k8s.io/client-go/kubernetes/scheme"
|
"k8s.io/client-go/kubernetes/scheme"
|
||||||
|
|
||||||
|
"github.com/golang/glog"
|
||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
apiyaml "k8s.io/apimachinery/pkg/util/yaml"
|
apiyaml "k8s.io/apimachinery/pkg/util/yaml"
|
||||||
)
|
)
|
||||||
|
@ -306,7 +308,7 @@ func loadPolicyResource(t *testing.T, file string) *unstructured.Unstructured {
|
||||||
func getClient(t *testing.T, files []string) *client.Client {
|
func getClient(t *testing.T, files []string) *client.Client {
|
||||||
var objects []runtime.Object
|
var objects []runtime.Object
|
||||||
if files != nil {
|
if files != nil {
|
||||||
|
glog.V(4).Infof("loading resources: %v", files)
|
||||||
for _, file := range files {
|
for _, file := range files {
|
||||||
objects = loadObjects(t, file)
|
objects = loadObjects(t, file)
|
||||||
}
|
}
|
||||||
|
@ -402,7 +404,7 @@ func loadPolicy(t *testing.T, path string) *kyverno.ClusterPolicy {
|
||||||
policy := kyverno.ClusterPolicy{}
|
policy := kyverno.ClusterPolicy{}
|
||||||
pBytes, err := apiyaml.ToJSON(p)
|
pBytes, err := apiyaml.ToJSON(p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
glog.Error(err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -425,8 +427,7 @@ func loadPolicy(t *testing.T, path string) *kyverno.ClusterPolicy {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testScenario(t *testing.T, path string) {
|
func testScenario(t *testing.T, path string) {
|
||||||
|
flag.Set("logtostderr", "true")
|
||||||
// flag.Set("logtostderr", "true")
|
|
||||||
// flag.Set("v", "8")
|
// flag.Set("v", "8")
|
||||||
|
|
||||||
scenario, err := loadScenario(t, path)
|
scenario, err := loadScenario(t, path)
|
||||||
|
|
|
@ -4,8 +4,8 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/golang/glog"
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -42,7 +42,7 @@ func ConvertToUnstructured(data []byte) (*unstructured.Unstructured, error) {
|
||||||
resource := &unstructured.Unstructured{}
|
resource := &unstructured.Unstructured{}
|
||||||
err := resource.UnmarshalJSON(data)
|
err := resource.UnmarshalJSON(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Log.Error(err, "failed to unmarshal resource")
|
glog.V(4).Infof("failed to unmarshall resource: %v", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return resource, nil
|
return resource, nil
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue