mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-30 03:15:05 +00:00
767 resolving merge conflicts
This commit is contained in:
commit
02ff7e6025
125 changed files with 3365 additions and 2177 deletions
18
.codeclimate.yml
Normal file
18
.codeclimate.yml
Normal file
|
@ -0,0 +1,18 @@
|
|||
engines:
|
||||
govet:
|
||||
enabled: true
|
||||
golint:
|
||||
enabled: false
|
||||
gofmt:
|
||||
enabled: true
|
||||
|
||||
ratings:
|
||||
paths:
|
||||
- "**.go"
|
||||
|
||||
exclude_paths:
|
||||
- documentation/
|
||||
- definitions
|
||||
- gh-pages
|
||||
- samples
|
||||
- scripts
|
17
.golangci.yml
Normal file
17
.golangci.yml
Normal file
|
@ -0,0 +1,17 @@
|
|||
linters:
|
||||
enable:
|
||||
- gosec
|
||||
- errcheck
|
||||
- gosimple
|
||||
- bodyclose
|
||||
- staticcheck
|
||||
disable:
|
||||
- ineffassign
|
||||
- deadcode
|
||||
- unused
|
||||
- structcheck
|
||||
|
||||
run:
|
||||
skip-files:
|
||||
- ".+_test.go"
|
||||
- ".+_test_.+.go"
|
|
@ -1 +1,7 @@
|
|||
See: https://github.com/nirmata/kyverno#contributing
|
||||
# Contributing to Kyverno
|
||||
|
||||
## 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,5 +171,6 @@ See [Milestones](https://github.com/nirmata/kyverno/milestones) and [Issues](htt
|
|||
Thanks for your interest in 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.
|
||||
* Browse through the [open issues](https://github.com/nirmata/kyverno/issues)
|
||||
|
|
|
@ -5,23 +5,27 @@ package main
|
|||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/nirmata/kyverno/pkg/config"
|
||||
client "github.com/nirmata/kyverno/pkg/dclient"
|
||||
"github.com/nirmata/kyverno/pkg/signal"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
rest "k8s.io/client-go/rest"
|
||||
clientcmd "k8s.io/client-go/tools/clientcmd"
|
||||
"k8s.io/klog"
|
||||
"k8s.io/klog/klogr"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
)
|
||||
|
||||
var (
|
||||
kubeconfig string
|
||||
setupLog = log.Log.WithName("setup")
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -30,20 +34,30 @@ const (
|
|||
)
|
||||
|
||||
func main() {
|
||||
defer glog.Flush()
|
||||
klog.InitFlags(nil)
|
||||
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
|
||||
stopCh := signal.SetupSignalHandler()
|
||||
// create client config
|
||||
clientConfig, err := createClientConfig(kubeconfig)
|
||||
if err != nil {
|
||||
glog.Fatalf("Error building kubeconfig: %v\n", err)
|
||||
setupLog.Error(err, "Failed to build kubeconfig")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// DYNAMIC CLIENT
|
||||
// - client for all registered resources
|
||||
client, err := client.NewClient(clientConfig, 10*time.Second, stopCh)
|
||||
client, err := client.NewClient(clientConfig, 10*time.Second, stopCh, log.Log)
|
||||
if err != nil {
|
||||
glog.Fatalf("Error creating client: %v\n", err)
|
||||
setupLog.Error(err, "Failed to create client")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Exit for unsupported version of kubernetes cluster
|
||||
|
@ -78,53 +92,46 @@ func main() {
|
|||
for err := range merge(done, stopCh, p1, p2) {
|
||||
if err != nil {
|
||||
failure = true
|
||||
glog.Errorf("failed to cleanup: %v", err)
|
||||
log.Log.Error(err, "failed to cleanup resource")
|
||||
}
|
||||
}
|
||||
// if there is any failure then we fail process
|
||||
if failure {
|
||||
glog.Errorf("failed to cleanup webhook configurations")
|
||||
log.Log.Info("failed to cleanup webhook configurations")
|
||||
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 {
|
||||
logger := log.Log.WithName("removeExistingWebhook").WithValues("kind", kind, "name", name)
|
||||
var err error
|
||||
// Get resource
|
||||
_, err = client.GetResource(kind, "", name)
|
||||
if errors.IsNotFound(err) {
|
||||
glog.V(4).Infof("%s(%s) not found", name, kind)
|
||||
logger.V(4).Info("resource not found")
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
glog.Errorf("failed to get resource %s(%s)", name, kind)
|
||||
logger.Error(err, "failed to get resource")
|
||||
return err
|
||||
}
|
||||
// Delete resource
|
||||
err = client.DeleteResource(kind, "", name, false)
|
||||
if err != nil {
|
||||
glog.Errorf("failed to delete resource %s(%s)", name, kind)
|
||||
logger.Error(err, "failed to delete resource")
|
||||
return err
|
||||
}
|
||||
glog.Infof("cleaned up resource %s(%s)", name, kind)
|
||||
logger.Info("removed the resource")
|
||||
return nil
|
||||
}
|
||||
|
||||
func createClientConfig(kubeconfig string) (*rest.Config, error) {
|
||||
logger := log.Log
|
||||
if kubeconfig == "" {
|
||||
glog.Info("Using in-cluster configuration")
|
||||
logger.Info("Using in-cluster configuration")
|
||||
return rest.InClusterConfig()
|
||||
}
|
||||
glog.Infof("Using configuration from '%s'", kubeconfig)
|
||||
logger.Info(fmt.Sprintf("Using configuration from '%s'", kubeconfig))
|
||||
return clientcmd.BuildConfigFromFlags("", kubeconfig)
|
||||
}
|
||||
|
||||
|
@ -163,6 +170,7 @@ func gen(done <-chan struct{}, stopCh <-chan struct{}, requests ...request) <-ch
|
|||
|
||||
// processes the requests
|
||||
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)
|
||||
go func() {
|
||||
defer close(out)
|
||||
|
@ -170,10 +178,10 @@ func process(client *client.Client, done <-chan struct{}, stopCh <-chan struct{}
|
|||
select {
|
||||
case out <- removeWebhookIfExists(client, req.kind, req.name):
|
||||
case <-done:
|
||||
println("done process")
|
||||
logger.Info("done")
|
||||
return
|
||||
case <-stopCh:
|
||||
println("shutting down process")
|
||||
logger.Info("shutting down")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -183,6 +191,7 @@ func process(client *client.Client, done <-chan struct{}, stopCh <-chan struct{}
|
|||
|
||||
// waits for all processes to be complete and merges result
|
||||
func merge(done <-chan struct{}, stopCh <-chan struct{}, processes ...<-chan error) <-chan error {
|
||||
logger := log.Log.WithName("merge")
|
||||
var wg sync.WaitGroup
|
||||
out := make(chan error)
|
||||
// gets the output from each process
|
||||
|
@ -192,10 +201,10 @@ func merge(done <-chan struct{}, stopCh <-chan struct{}, processes ...<-chan err
|
|||
select {
|
||||
case out <- err:
|
||||
case <-done:
|
||||
println("done merge")
|
||||
logger.Info("done")
|
||||
return
|
||||
case <-stopCh:
|
||||
println("shutting down merge")
|
||||
logger.Info("shutting down")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -215,30 +224,37 @@ func merge(done <-chan struct{}, stopCh <-chan struct{}, processes ...<-chan err
|
|||
}
|
||||
|
||||
func isVersionSupported(client *client.Client) {
|
||||
logger := log.Log
|
||||
serverVersion, err := client.DiscoveryClient.GetServerVersion()
|
||||
if err != nil {
|
||||
glog.Fatalf("Failed to get kubernetes server version: %v\n", err)
|
||||
logger.Error(err, "Failed to get kubernetes server version")
|
||||
os.Exit(1)
|
||||
}
|
||||
exp := regexp.MustCompile(`v(\d*).(\d*).(\d*)`)
|
||||
groups := exp.FindAllStringSubmatch(serverVersion.String(), -1)
|
||||
if len(groups) != 1 || len(groups[0]) != 4 {
|
||||
glog.Fatalf("Failed to extract kubernetes server version: %v.err %v\n", serverVersion, err)
|
||||
logger.Error(err, "Failed to extract kubernetes server version", "serverVersion", serverVersion)
|
||||
os.Exit(1)
|
||||
}
|
||||
// convert string to int
|
||||
// assuming the version are always intergers
|
||||
major, err := strconv.Atoi(groups[0][1])
|
||||
if err != nil {
|
||||
glog.Fatalf("Failed to extract kubernetes major server version: %v.err %v\n", serverVersion, err)
|
||||
logger.Error(err, "Failed to extract kubernetes major server version", "serverVersion", serverVersion)
|
||||
os.Exit(1)
|
||||
}
|
||||
minor, err := strconv.Atoi(groups[0][2])
|
||||
if err != nil {
|
||||
glog.Fatalf("Failed to extract kubernetes minor server version: %v.err %v\n", serverVersion, err)
|
||||
logger.Error(err, "Failed to extract kubernetes minor server version", "serverVersion", serverVersion)
|
||||
os.Exit(1)
|
||||
}
|
||||
sub, err := strconv.Atoi(groups[0][3])
|
||||
if err != nil {
|
||||
glog.Fatalf("Failed to extract kubernetes sub minor server version:%v. err %v\n", serverVersion, err)
|
||||
logger.Error(err, "Failed to extract kubernetes sub minor server version", "serverVersion", serverVersion)
|
||||
os.Exit(1)
|
||||
}
|
||||
if major <= 1 && minor <= 12 && sub < 7 {
|
||||
glog.Fatalf("Unsupported kubernetes server version %s. Kyverno is supported from version v1.12.7+", serverVersion)
|
||||
logger.Info("Unsupported kubernetes server version %s. Kyverno is supported from version v1.12.7+", "serverVersion", serverVersion)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,11 +3,12 @@ package main
|
|||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/nirmata/kyverno/pkg/openapi"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/nirmata/kyverno/pkg/checker"
|
||||
kyvernoclient "github.com/nirmata/kyverno/pkg/client/clientset/versioned"
|
||||
kyvernoinformer "github.com/nirmata/kyverno/pkg/client/informers/externalversions"
|
||||
|
@ -27,6 +28,9 @@ import (
|
|||
"github.com/nirmata/kyverno/pkg/webhooks"
|
||||
webhookgenerate "github.com/nirmata/kyverno/pkg/webhooks/generate"
|
||||
kubeinformers "k8s.io/client-go/informers"
|
||||
"k8s.io/klog"
|
||||
"k8s.io/klog/klogr"
|
||||
log "sigs.k8s.io/controller-runtime/pkg/log"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -38,20 +42,38 @@ var (
|
|||
// will be removed in future and the configuration will be set only via configmaps
|
||||
filterK8Resources string
|
||||
// User FQDN as CSR CN
|
||||
fqdncn bool
|
||||
fqdncn bool
|
||||
setupLog = log.Log.WithName("setup")
|
||||
)
|
||||
|
||||
func main() {
|
||||
defer glog.Flush()
|
||||
version.PrintVersionInfo()
|
||||
klog.InitFlags(nil)
|
||||
log.SetLogger(klogr.New())
|
||||
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 := make(chan struct{})
|
||||
// handle os signals
|
||||
stopCh := signal.SetupSignalHandler()
|
||||
// CLIENT CONFIG
|
||||
clientConfig, err := config.CreateClientConfig(kubeconfig)
|
||||
clientConfig, err := config.CreateClientConfig(kubeconfig, log.Log)
|
||||
if err != nil {
|
||||
glog.Fatalf("Error building kubeconfig: %v\n", err)
|
||||
setupLog.Error(err, "Failed to build kubeconfig")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// KYVENO CRD CLIENT
|
||||
|
@ -60,29 +82,33 @@ func main() {
|
|||
// - PolicyViolation
|
||||
pclient, err := kyvernoclient.NewForConfig(clientConfig)
|
||||
if err != nil {
|
||||
glog.Fatalf("Error creating client: %v\n", err)
|
||||
setupLog.Error(err, "Failed to create client")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// 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)
|
||||
client, err := dclient.NewClient(clientConfig, 10*time.Second, stopCh, log.Log)
|
||||
if err != nil {
|
||||
glog.Fatalf("Error creating client: %v\n", err)
|
||||
setupLog.Error(err, "Failed to create client")
|
||||
os.Exit(1)
|
||||
}
|
||||
// CRD CHECK
|
||||
// - verify if the CRD for Policy & PolicyViolation are available
|
||||
if !utils.CRDInstalled(client.DiscoveryClient) {
|
||||
glog.Fatalf("Required CRDs unavailable")
|
||||
if !utils.CRDInstalled(client.DiscoveryClient, log.Log) {
|
||||
setupLog.Error(fmt.Errorf("pre-requisite CRDs not installed"), "Failed to create watch on kyverno CRDs")
|
||||
os.Exit(1)
|
||||
}
|
||||
// KUBERNETES CLIENT
|
||||
kubeClient, err := utils.NewKubeClient(clientConfig)
|
||||
if err != nil {
|
||||
glog.Fatalf("Error creating kubernetes client: %v\n", err)
|
||||
setupLog.Error(err, "Failed to create kubernetes client")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// TODO(shuting): To be removed for v1.2.0
|
||||
utils.CleanupOldCrd(client)
|
||||
utils.CleanupOldCrd(client, log.Log)
|
||||
|
||||
// KUBERNETES RESOURCES INFORMER
|
||||
// watches namespace resource
|
||||
|
@ -99,16 +125,18 @@ func main() {
|
|||
clientConfig,
|
||||
client,
|
||||
serverIP,
|
||||
int32(webhookTimeout))
|
||||
int32(webhookTimeout),
|
||||
log.Log)
|
||||
|
||||
// Resource Mutating Webhook Watcher
|
||||
lastReqTime := checker.NewLastReqTime()
|
||||
lastReqTime := checker.NewLastReqTime(log.Log.WithName("LastReqTime"))
|
||||
rWebhookWatcher := webhookconfig.NewResourceWebhookRegister(
|
||||
lastReqTime,
|
||||
kubeInformer.Admissionregistration().V1beta1().MutatingWebhookConfigurations(),
|
||||
kubeInformer.Admissionregistration().V1beta1().ValidatingWebhookConfigurations(),
|
||||
webhookRegistrationClient,
|
||||
runValidationInMutatingWebhook,
|
||||
log.Log.WithName("ResourceWebhookRegister"),
|
||||
)
|
||||
|
||||
// KYVERNO CRD INFORMER
|
||||
|
@ -127,16 +155,19 @@ func main() {
|
|||
configData := config.NewConfigData(
|
||||
kubeClient,
|
||||
kubeInformer.Core().V1().ConfigMaps(),
|
||||
filterK8Resources)
|
||||
filterK8Resources,
|
||||
log.Log.WithName("ConfigData"),
|
||||
)
|
||||
|
||||
// Policy meta-data store
|
||||
policyMetaStore := policystore.NewPolicyStore(pInformer.Kyverno().V1().ClusterPolicies())
|
||||
policyMetaStore := policystore.NewPolicyStore(pInformer.Kyverno().V1().ClusterPolicies(), log.Log.WithName("PolicyStore"))
|
||||
|
||||
// EVENT GENERATOR
|
||||
// - generate event with retry mechanism
|
||||
egen := event.NewEventGenerator(
|
||||
client,
|
||||
pInformer.Kyverno().V1().ClusterPolicies())
|
||||
pInformer.Kyverno().V1().ClusterPolicies(),
|
||||
log.Log.WithName("EventGenerator"))
|
||||
|
||||
// Policy Status Handler - deals with all logic related to policy status
|
||||
statusSync := policystatus.NewSync(
|
||||
|
@ -149,7 +180,9 @@ func main() {
|
|||
client,
|
||||
pInformer.Kyverno().V1().ClusterPolicyViolations(),
|
||||
pInformer.Kyverno().V1().PolicyViolations(),
|
||||
statusSync.Listener)
|
||||
statusSync.Listener,
|
||||
log.Log.WithName("PolicyViolationGenerator"),
|
||||
)
|
||||
|
||||
// POLICY CONTROLLER
|
||||
// - reconciliation policy and policy violation
|
||||
|
@ -165,13 +198,16 @@ func main() {
|
|||
egen,
|
||||
pvgen,
|
||||
policyMetaStore,
|
||||
rWebhookWatcher)
|
||||
rWebhookWatcher,
|
||||
log.Log.WithName("PolicyController"),
|
||||
)
|
||||
if err != nil {
|
||||
glog.Fatalf("error creating policy controller: %v\n", err)
|
||||
setupLog.Error(err, "Failed to create policy controller")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// GENERATE REQUEST GENERATOR
|
||||
grgen := webhookgenerate.NewGenerator(pclient, stopCh)
|
||||
grgen := webhookgenerate.NewGenerator(pclient, stopCh, log.Log.WithName("GenerateRequestGenerator"))
|
||||
|
||||
// GENERATE CONTROLLER
|
||||
// - applies generate rules on resources based on generate requests created by webhook
|
||||
|
@ -184,6 +220,7 @@ func main() {
|
|||
pvgen,
|
||||
kubedynamicInformer,
|
||||
statusSync.Listener,
|
||||
log.Log.WithName("GenerateController"),
|
||||
)
|
||||
// GENERATE REQUEST CLEANUP
|
||||
// -- cleans up the generate requests that have not been processed(i.e. state = [Pending, Failed]) for more than defined timeout
|
||||
|
@ -193,12 +230,14 @@ func main() {
|
|||
pInformer.Kyverno().V1().ClusterPolicies(),
|
||||
pInformer.Kyverno().V1().GenerateRequests(),
|
||||
kubedynamicInformer,
|
||||
log.Log.WithName("GenerateCleanUpController"),
|
||||
)
|
||||
|
||||
// CONFIGURE CERTIFICATES
|
||||
tlsPair, err := client.InitTLSPemPair(clientConfig, fqdncn)
|
||||
if err != nil {
|
||||
glog.Fatalf("Failed to initialize TLS key/certificate pair: %v\n", err)
|
||||
setupLog.Error(err, "Failed to initialize TLS key/certificate pair")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// WEBHOOK REGISTRATION
|
||||
|
@ -207,7 +246,8 @@ func main() {
|
|||
// resource webhook confgiuration is generated dynamically in the webhook server and policy controller
|
||||
// based on the policy resources created
|
||||
if err = webhookRegistrationClient.Register(); err != nil {
|
||||
glog.Fatalf("Failed registering Admission Webhooks: %v\n", err)
|
||||
setupLog.Error(err, "Failed to register Admission webhooks")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Sync openAPI definitions of resources
|
||||
|
@ -234,9 +274,12 @@ func main() {
|
|||
pvgen,
|
||||
grgen,
|
||||
rWebhookWatcher,
|
||||
cleanUp)
|
||||
cleanUp,
|
||||
log.Log.WithName("WebhookServer"),
|
||||
)
|
||||
if err != nil {
|
||||
glog.Fatalf("Unable to create webhook server: %v\n", err)
|
||||
setupLog.Error(err, "Failed to create webhook server")
|
||||
os.Exit(1)
|
||||
}
|
||||
// Start the components
|
||||
pInformer.Start(stopCh)
|
||||
|
@ -252,7 +295,7 @@ func main() {
|
|||
go grcc.Run(1, stopCh)
|
||||
go pvgen.Run(1, stopCh)
|
||||
go statusSync.Run(1, stopCh)
|
||||
go openApiSync.Run(1, stopCh)
|
||||
openApiSync.Run(1, stopCh)
|
||||
|
||||
// verifys if the admission control is enabled and active
|
||||
// resync: 60 seconds
|
||||
|
@ -274,18 +317,5 @@ func main() {
|
|||
// resource cleanup
|
||||
// remove webhook configurations
|
||||
<-cleanUp
|
||||
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()
|
||||
setupLog.Info("Kyverno shutdown successful")
|
||||
}
|
||||
|
|
32
go.mod
32
go.mod
|
@ -5,39 +5,37 @@ go 1.13
|
|||
require (
|
||||
github.com/cenkalti/backoff v2.2.1+incompatible
|
||||
github.com/evanphx/json-patch v4.5.0+incompatible
|
||||
github.com/gogo/protobuf v1.3.1 // indirect
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
|
||||
github.com/go-logr/logr v0.1.0
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7 // indirect
|
||||
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/imdario/mergo v0.3.8 // indirect
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af
|
||||
github.com/json-iterator/go v1.1.9 // indirect
|
||||
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/pflag v1.0.5 // indirect
|
||||
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/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect
|
||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1 // indirect
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect
|
||||
google.golang.org/appengine v1.6.5 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.2.7
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
|
||||
gopkg.in/yaml.v2 v2.2.8
|
||||
gotest.tools v2.2.0+incompatible
|
||||
k8s.io/api v0.0.0-20190409021203-6e4e0e4f393b
|
||||
k8s.io/apimachinery v0.0.0-20190404173353-6a84e37a896d
|
||||
k8s.io/cli-runtime v0.0.0-20191004110135-b9eb767d2e1a
|
||||
k8s.io/client-go v11.0.1-0.20190516230509-ae8359b20417+incompatible
|
||||
k8s.io/klog v1.0.0 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a
|
||||
k8s.io/api v0.17.4
|
||||
k8s.io/apimachinery v0.17.4
|
||||
k8s.io/cli-runtime v0.17.4
|
||||
k8s.io/client-go v0.17.4
|
||||
k8s.io/klog v1.0.0
|
||||
k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c
|
||||
k8s.io/utils v0.0.0-20200109141947-94aeca20bf09 // indirect
|
||||
sigs.k8s.io/kustomize v2.0.3+incompatible // indirect
|
||||
sigs.k8s.io/controller-runtime v0.5.0
|
||||
)
|
||||
|
||||
// Added for go1.13 migration https://github.com/golang/go/issues/32805
|
||||
replace github.com/gorilla/rpc v1.2.0+incompatible => github.com/gorilla/rpc v1.2.0
|
||||
replace (
|
||||
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,6 +15,13 @@ 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/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/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/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=
|
||||
|
@ -26,21 +33,29 @@ 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/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.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/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/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/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/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/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/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/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-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-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.23.19/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/aws/aws-xray-sdk-go v0.9.4/go.mod h1:XtMKdBQfpVut+tJEwI7+dJFRxxRdxHDyVNp2tHXRq04=
|
||||
|
@ -50,6 +65,7 @@ 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 v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
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/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
|
||||
github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
|
||||
|
@ -64,6 +80,7 @@ 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/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/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/codegangsta/negroni v1.0.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2iZY63YTKWo0=
|
||||
github.com/containerd/continuity v0.0.0-20181203112020-004b46473808/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
|
||||
|
@ -73,11 +90,16 @@ 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.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-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.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/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/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 v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
|
@ -85,9 +107,13 @@ 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/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/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-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/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 v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
|
||||
|
@ -96,9 +122,14 @@ 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/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/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/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 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/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
|
@ -113,21 +144,68 @@ 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.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/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-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-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-logr/logr v0.1.0 h1:M1Tv3VzNlEHg6uyACnRdtrploV2P7wZqH8BoQMtz0cg=
|
||||
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-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/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/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/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/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.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
|
@ -301,14 +379,18 @@ 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/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/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.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/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
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/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/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-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7 h1:5ZkaAPbicIKTF2I64qf5Fh8Aa83Q/dnOafMYV0OMwjA=
|
||||
|
@ -333,6 +415,7 @@ 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/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-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
|
||||
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/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
|
@ -341,11 +424,13 @@ 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.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.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.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.3.1 h1:WeAefnSUHlBb0iJKwxFDZdbfGwkd7xRNuV+IpXMJhYk=
|
||||
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-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20190328170749-bb2674552d8f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
|
@ -358,9 +443,12 @@ 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/sessions v1.1.2/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.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
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/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
|
@ -368,6 +456,7 @@ 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/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.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
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.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
|
@ -399,6 +488,8 @@ 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-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
|
||||
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/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf/go.mod h1:hyb9oH7vZsitZCiBt0ZvifOrB+qc8PS5IiilCIb87rg=
|
||||
|
@ -415,7 +506,10 @@ 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/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-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.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/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
|
@ -445,11 +539,14 @@ 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/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.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
|
||||
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/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.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/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
|
||||
|
@ -457,6 +554,12 @@ 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-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-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.5/go.mod h1:gRRbPbbuA8TmMiRvaOzUlRfzfjeCCBqX2A6arxN01MM=
|
||||
github.com/markbates/going v1.0.2/go.mod h1:UWCk3zm0UKefHZ7l8BNqi26UyiEMniznk8naLdTcy6c=
|
||||
|
@ -483,6 +586,7 @@ 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.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-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-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
|
@ -525,7 +629,9 @@ 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/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-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/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/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=
|
||||
|
@ -545,15 +651,21 @@ 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/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
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/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.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/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.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.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/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
||||
github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
|
||||
|
@ -591,10 +703,12 @@ 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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
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.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/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-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
|
@ -602,10 +716,12 @@ 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.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.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-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-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/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=
|
||||
|
@ -666,6 +782,7 @@ 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/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
||||
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.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
|
@ -677,6 +794,7 @@ 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/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.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
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.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||
|
@ -690,6 +808,7 @@ 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/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
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/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=
|
||||
|
@ -701,8 +820,10 @@ 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/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/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/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/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
|
@ -712,6 +833,10 @@ 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=
|
||||
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/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.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA=
|
||||
|
@ -734,15 +859,22 @@ 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-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-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-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-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-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-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-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-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-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
|
@ -771,16 +903,22 @@ 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-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-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-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-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-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-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-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-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/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
|
@ -822,9 +960,11 @@ 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-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-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-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-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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
@ -832,8 +972,10 @@ 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-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-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-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-20191105231009-c1f44814a5cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1 h1:gZpLHxUX5BdYLA08Lj4YCJNN/jk7KtquiArPoeX0WvA=
|
||||
|
@ -844,6 +986,7 @@ 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.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
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-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs=
|
||||
|
@ -875,6 +1018,7 @@ 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-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-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-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
|
@ -884,9 +1028,14 @@ 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-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-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-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-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.5.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
|
@ -918,6 +1067,7 @@ 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.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
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/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=
|
||||
|
@ -925,12 +1075,15 @@ 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 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-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/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
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/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/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/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
|
@ -942,6 +1095,7 @@ 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/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/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/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=
|
||||
|
@ -955,6 +1109,8 @@ 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.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
|
||||
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/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
@ -963,24 +1119,53 @@ 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=
|
||||
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.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/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/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/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-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.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/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/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/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
|
||||
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/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 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/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) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
out.ListMeta = in.ListMeta
|
||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]ClusterPolicy, len(*in))
|
||||
|
@ -135,7 +135,7 @@ func (in *ClusterPolicyViolation) DeepCopyObject() runtime.Object {
|
|||
func (in *ClusterPolicyViolationList) DeepCopyInto(out *ClusterPolicyViolationList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
out.ListMeta = in.ListMeta
|
||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]ClusterPolicyViolation, len(*in))
|
||||
|
@ -241,7 +241,7 @@ func (in *GenerateRequestContext) DeepCopy() *GenerateRequestContext {
|
|||
func (in *GenerateRequestList) DeepCopyInto(out *GenerateRequestList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
out.ListMeta = in.ListMeta
|
||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]GenerateRequest, len(*in))
|
||||
|
@ -420,7 +420,7 @@ func (in *PolicyViolation) DeepCopyObject() runtime.Object {
|
|||
func (in *PolicyViolationList) DeepCopyInto(out *PolicyViolationList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
out.ListMeta = in.ListMeta
|
||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]PolicyViolation, len(*in))
|
||||
|
|
108
pkg/auth/auth.go
Normal file
108
pkg/auth/auth.go
Normal file
|
@ -0,0 +1,108 @@
|
|||
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
|
||||
}
|
48
pkg/auth/auth_test.go
Normal file
48
pkg/auth/auth_test.go
Normal file
|
@ -0,0 +1,48 @@
|
|||
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"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/go-logr/logr"
|
||||
kyvernolister "github.com/nirmata/kyverno/pkg/client/listers/kyverno/v1"
|
||||
dclient "github.com/nirmata/kyverno/pkg/dclient"
|
||||
"github.com/nirmata/kyverno/pkg/event"
|
||||
|
@ -20,8 +20,9 @@ const (
|
|||
|
||||
// LastReqTime stores the lastrequest times for incoming api-requests
|
||||
type LastReqTime struct {
|
||||
t time.Time
|
||||
mu sync.RWMutex
|
||||
t time.Time
|
||||
mu sync.RWMutex
|
||||
log logr.Logger
|
||||
}
|
||||
|
||||
//Time returns the lastrequest time
|
||||
|
@ -39,16 +40,17 @@ func (t *LastReqTime) SetTime(tm time.Time) {
|
|||
}
|
||||
|
||||
//NewLastReqTime returns a new instance of LastRequestTime store
|
||||
func NewLastReqTime() *LastReqTime {
|
||||
func NewLastReqTime(log logr.Logger) *LastReqTime {
|
||||
return &LastReqTime{
|
||||
t: time.Now(),
|
||||
t: time.Now(),
|
||||
log: log,
|
||||
}
|
||||
}
|
||||
|
||||
func checkIfPolicyWithMutateAndGenerateExists(pLister kyvernolister.ClusterPolicyLister) bool {
|
||||
func checkIfPolicyWithMutateAndGenerateExists(pLister kyvernolister.ClusterPolicyLister, log logr.Logger) bool {
|
||||
policies, err := pLister.ListResources(labels.NewSelector())
|
||||
if err != nil {
|
||||
glog.Error()
|
||||
log.Error(err, "failed to list cluster policies")
|
||||
}
|
||||
for _, policy := range policies {
|
||||
if policy.HasMutateOrValidateOrGenerate() {
|
||||
|
@ -62,15 +64,16 @@ func checkIfPolicyWithMutateAndGenerateExists(pLister kyvernolister.ClusterPolic
|
|||
|
||||
//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{}) {
|
||||
glog.V(2).Infof("starting default resync for webhook checker with resync time %d nanoseconds", defaultResync)
|
||||
logger := t.log
|
||||
logger.V(2).Info("tarting default resync for webhook checker", "resyncTime", defaultResync)
|
||||
maxDeadline := deadline * time.Duration(MaxRetryCount)
|
||||
ticker := time.NewTicker(defaultResync)
|
||||
/// interface to update and increment kyverno webhook status via annotations
|
||||
statuscontrol := NewVerifyControl(client, eventGen)
|
||||
statuscontrol := NewVerifyControl(client, eventGen, logger.WithName("StatusControl"))
|
||||
// send the initial update status
|
||||
if checkIfPolicyWithMutateAndGenerateExists(pLister) {
|
||||
if checkIfPolicyWithMutateAndGenerateExists(pLister, logger) {
|
||||
if err := statuscontrol.SuccessStatus(); err != nil {
|
||||
glog.Error(err)
|
||||
logger.Error(err, "failed to set 'success' status")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -84,36 +87,36 @@ func (t *LastReqTime) Run(pLister kyvernolister.ClusterPolicyLister, eventGen ev
|
|||
case <-ticker.C:
|
||||
// if there are no policies then we dont have a webhook on resource.
|
||||
// we indirectly check if the resource
|
||||
if !checkIfPolicyWithMutateAndGenerateExists(pLister) {
|
||||
if !checkIfPolicyWithMutateAndGenerateExists(pLister, logger) {
|
||||
continue
|
||||
}
|
||||
// get current time
|
||||
timeDiff := time.Since(t.Time())
|
||||
if timeDiff > maxDeadline {
|
||||
glog.Infof("failed to receive any request for more than %v ", maxDeadline)
|
||||
glog.Info("Admission Control failing: Webhook is not receiving requests forwarded by api-server as per webhook configurations")
|
||||
logger.Info("request exceeded max deadline", "deadline", maxDeadline)
|
||||
logger.Info("Admission Control failing: Webhook is not receiving requests forwarded by api-server as per webhook configurations")
|
||||
// set the status unavailable
|
||||
if err := statuscontrol.FailedStatus(); err != nil {
|
||||
glog.Error(err)
|
||||
logger.Error(err, "failed to set 'failed' status")
|
||||
}
|
||||
continue
|
||||
}
|
||||
if timeDiff > deadline {
|
||||
glog.Info("Admission Control failing: Webhook is not receiving requests forwarded by api-server as per webhook configurations")
|
||||
logger.Info("Admission Control failing: Webhook is not receiving requests forwarded by api-server as per webhook configurations")
|
||||
// send request to update the kyverno deployment
|
||||
if err := statuscontrol.IncrementAnnotation(); err != nil {
|
||||
glog.Error(err)
|
||||
logger.Error(err, "failed to increment annotation")
|
||||
}
|
||||
continue
|
||||
}
|
||||
// if the status was false before then we update it to true
|
||||
// send request to update the kyverno deployment
|
||||
if err := statuscontrol.SuccessStatus(); err != nil {
|
||||
glog.Error(err)
|
||||
logger.Error(err, "failed to update success status")
|
||||
}
|
||||
case <-stopCh:
|
||||
// handler termination signal
|
||||
glog.V(2).Infof("stopping default resync for webhook checker")
|
||||
logger.V(2).Info("stopping default resync for webhook checker")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import (
|
|||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/go-logr/logr"
|
||||
dclient "github.com/nirmata/kyverno/pkg/dclient"
|
||||
"github.com/nirmata/kyverno/pkg/event"
|
||||
)
|
||||
|
@ -29,6 +29,7 @@ type StatusInterface interface {
|
|||
type StatusControl struct {
|
||||
client *dclient.Client
|
||||
eventGen event.Interface
|
||||
log logr.Logger
|
||||
}
|
||||
|
||||
//SuccessStatus ...
|
||||
|
@ -42,20 +43,22 @@ func (vc StatusControl) FailedStatus() error {
|
|||
}
|
||||
|
||||
// NewVerifyControl ...
|
||||
func NewVerifyControl(client *dclient.Client, eventGen event.Interface) *StatusControl {
|
||||
func NewVerifyControl(client *dclient.Client, eventGen event.Interface, log logr.Logger) *StatusControl {
|
||||
return &StatusControl{
|
||||
client: client,
|
||||
eventGen: eventGen,
|
||||
log: log,
|
||||
}
|
||||
}
|
||||
|
||||
func (vc StatusControl) setStatus(status string) error {
|
||||
glog.Infof("setting deployment %s in ns %s annotation %s to %s", deployName, deployNamespace, annWebhookStats, status)
|
||||
logger := vc.log
|
||||
logger.Info(fmt.Sprintf("setting deployment %s in ns %s annotation %s to %s", deployName, deployNamespace, annWebhookStats, status))
|
||||
var ann map[string]string
|
||||
var err error
|
||||
deploy, err := vc.client.GetResource("Deployment", deployNamespace, deployName)
|
||||
if err != nil {
|
||||
glog.V(4).Infof("failed to get deployment %s in namespace %s: %v", deployName, deployNamespace, err)
|
||||
logger.Error(err, "failed to get deployment resource")
|
||||
return err
|
||||
}
|
||||
ann = deploy.GetAnnotations()
|
||||
|
@ -67,7 +70,7 @@ func (vc StatusControl) setStatus(status string) error {
|
|||
if ok {
|
||||
// annotatiaion is present
|
||||
if webhookAction == status {
|
||||
glog.V(4).Infof("annotation %s already set to '%s'", annWebhookStats, status)
|
||||
logger.V(4).Info(fmt.Sprintf("annotation %s already set to '%s'", annWebhookStats, status))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -77,7 +80,7 @@ func (vc StatusControl) setStatus(status string) error {
|
|||
// update counter
|
||||
_, err = vc.client.UpdateResource("Deployment", deployNamespace, deploy, false)
|
||||
if err != nil {
|
||||
glog.V(4).Infof("failed to update annotation %s for deployment %s in namespace %s: %v", annWebhookStats, deployName, deployNamespace, err)
|
||||
logger.Error(err, fmt.Sprintf("failed to update annotation %s for deployment %s in namespace %s", annWebhookStats, deployName, deployNamespace))
|
||||
return err
|
||||
}
|
||||
// create event on kyverno deployment
|
||||
|
@ -97,12 +100,13 @@ func createStatusUpdateEvent(status string, eventGen event.Interface) {
|
|||
|
||||
//IncrementAnnotation ...
|
||||
func (vc StatusControl) IncrementAnnotation() error {
|
||||
glog.Infof("setting deployment %s in ns %s annotation %s", deployName, deployNamespace, annCounter)
|
||||
logger := vc.log
|
||||
logger.Info(fmt.Sprintf("setting deployment %s in ns %s annotation %s", deployName, deployNamespace, annCounter))
|
||||
var ann map[string]string
|
||||
var err error
|
||||
deploy, err := vc.client.GetResource("Deployment", deployNamespace, deployName)
|
||||
if err != nil {
|
||||
glog.V(4).Infof("failed to get deployment %s in namespace %s: %v", deployName, deployNamespace, err)
|
||||
logger.Error(err, "failed to get deployment %s in namespace %s", deployName, deployNamespace)
|
||||
return err
|
||||
}
|
||||
ann = deploy.GetAnnotations()
|
||||
|
@ -112,18 +116,18 @@ func (vc StatusControl) IncrementAnnotation() error {
|
|||
}
|
||||
counter, err := strconv.Atoi(ann[annCounter])
|
||||
if err != nil {
|
||||
glog.V(4).Infof("failed to parse string: %v", err)
|
||||
logger.Error(err, "Failed to parse string")
|
||||
return err
|
||||
}
|
||||
// increment counter
|
||||
counter++
|
||||
ann[annCounter] = strconv.Itoa(counter)
|
||||
glog.Infof("incrementing annotation %s counter to %d", annCounter, counter)
|
||||
logger.Info("incrementing annotation", "old", annCounter, "new", counter)
|
||||
deploy.SetAnnotations(ann)
|
||||
// update counter
|
||||
_, err = vc.client.UpdateResource("Deployment", deployNamespace, deploy, false)
|
||||
if err != nil {
|
||||
glog.V(4).Infof("failed to update annotation %s for deployment %s in namespace %s: %v", annCounter, deployName, deployNamespace, err)
|
||||
logger.Error(err, fmt.Sprintf("failed to update annotation %s for deployment %s in namespace %s", annCounter, deployName, deployNamespace))
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -19,6 +19,8 @@ limitations under the License.
|
|||
package versioned
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
kyvernov1 "github.com/nirmata/kyverno/pkg/client/clientset/versioned/typed/kyverno/v1"
|
||||
discovery "k8s.io/client-go/discovery"
|
||||
rest "k8s.io/client-go/rest"
|
||||
|
@ -51,9 +53,14 @@ func (c *Clientset) Discovery() discovery.DiscoveryInterface {
|
|||
}
|
||||
|
||||
// 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) {
|
||||
configShallowCopy := *c
|
||||
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)
|
||||
}
|
||||
var cs Clientset
|
||||
|
|
|
@ -41,7 +41,7 @@ func NewSimpleClientset(objects ...runtime.Object) *Clientset {
|
|||
}
|
||||
}
|
||||
|
||||
cs := &Clientset{}
|
||||
cs := &Clientset{tracker: o}
|
||||
cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake}
|
||||
cs.AddReactor("*", "*", testing.ObjectReaction(o))
|
||||
cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) {
|
||||
|
@ -63,12 +63,17 @@ func NewSimpleClientset(objects ...runtime.Object) *Clientset {
|
|||
type Clientset struct {
|
||||
testing.Fake
|
||||
discovery *fakediscovery.FakeDiscovery
|
||||
tracker testing.ObjectTracker
|
||||
}
|
||||
|
||||
func (c *Clientset) Discovery() discovery.DiscoveryInterface {
|
||||
return c.discovery
|
||||
}
|
||||
|
||||
func (c *Clientset) Tracker() testing.ObjectTracker {
|
||||
return c.tracker
|
||||
}
|
||||
|
||||
var _ clientset.Interface = &Clientset{}
|
||||
|
||||
// KyvernoV1 retrieves the KyvernoV1Client
|
||||
|
|
|
@ -29,7 +29,8 @@ import (
|
|||
|
||||
var scheme = runtime.NewScheme()
|
||||
var codecs = serializer.NewCodecFactory(scheme)
|
||||
var parameterCodec = runtime.NewParameterCodec(scheme)
|
||||
|
||||
// var parameterCodec = runtime.NewParameterCodec(scheme)
|
||||
var localSchemeBuilder = runtime.SchemeBuilder{
|
||||
kyvernov1.AddToScheme,
|
||||
}
|
||||
|
|
|
@ -21,7 +21,6 @@ package v1
|
|||
import (
|
||||
v1 "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||
"github.com/nirmata/kyverno/pkg/client/clientset/versioned/scheme"
|
||||
serializer "k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
rest "k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
|
@ -86,7 +85,7 @@ func setConfigDefaults(config *rest.Config) error {
|
|||
gv := v1.SchemeGroupVersion
|
||||
config.GroupVersion = &gv
|
||||
config.APIPath = "/apis"
|
||||
config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: scheme.Codecs}
|
||||
config.NegotiatedSerializer = scheme.Codecs.WithoutConversion()
|
||||
|
||||
if config.UserAgent == "" {
|
||||
config.UserAgent = rest.DefaultKubernetesUserAgent()
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"flag"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/go-logr/logr"
|
||||
rest "k8s.io/client-go/rest"
|
||||
clientcmd "k8s.io/client-go/tools/clientcmd"
|
||||
)
|
||||
|
@ -74,29 +72,13 @@ var (
|
|||
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
|
||||
func CreateClientConfig(kubeconfig string) (*rest.Config, error) {
|
||||
func CreateClientConfig(kubeconfig string, log logr.Logger) (*rest.Config, error) {
|
||||
logger := log.WithName("CreateClientConfig")
|
||||
if kubeconfig == "" {
|
||||
glog.Info("Using in-cluster configuration")
|
||||
logger.Info("Using in-cluster configuration")
|
||||
return rest.InClusterConfig()
|
||||
}
|
||||
glog.V(4).Infof("Using configuration from '%s'", kubeconfig)
|
||||
logger.V(4).Info("Using specified kubeconfig", "kubeconfig", kubeconfig)
|
||||
return clientcmd.BuildConfigFromFlags("", kubeconfig)
|
||||
}
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/go-logr/logr"
|
||||
"github.com/minio/minio/pkg/wildcard"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
informers "k8s.io/client-go/informers/core/v1"
|
||||
|
@ -31,6 +30,7 @@ type ConfigData struct {
|
|||
filters []k8Resource
|
||||
// hasynced
|
||||
cmSycned cache.InformerSynced
|
||||
log logr.Logger
|
||||
}
|
||||
|
||||
// ToFilter checks if the given resource is set to be filtered in the configuration
|
||||
|
@ -51,20 +51,21 @@ type Interface interface {
|
|||
}
|
||||
|
||||
// NewConfigData ...
|
||||
func NewConfigData(rclient kubernetes.Interface, cmInformer informers.ConfigMapInformer, filterK8Resources string) *ConfigData {
|
||||
func NewConfigData(rclient kubernetes.Interface, cmInformer informers.ConfigMapInformer, filterK8Resources string, log logr.Logger) *ConfigData {
|
||||
// environment var is read at start only
|
||||
if cmNameEnv == "" {
|
||||
glog.Info("ConfigMap name not defined in env:INIT_CONFIG: loading no default configuration")
|
||||
log.Info("ConfigMap name not defined in env:INIT_CONFIG: loading no default configuration")
|
||||
}
|
||||
cd := ConfigData{
|
||||
client: rclient,
|
||||
cmName: os.Getenv(cmNameEnv),
|
||||
cmSycned: cmInformer.Informer().HasSynced,
|
||||
log: log,
|
||||
}
|
||||
//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
|
||||
if filterK8Resources != "" {
|
||||
glog.Info("Init configuration from commandline arguments")
|
||||
cd.log.Info("init configuration from commandline arguments")
|
||||
cd.initFilters(filterK8Resources)
|
||||
}
|
||||
|
||||
|
@ -78,9 +79,10 @@ func NewConfigData(rclient kubernetes.Interface, cmInformer informers.ConfigMapI
|
|||
|
||||
//Run checks syncing
|
||||
func (cd *ConfigData) Run(stopCh <-chan struct{}) {
|
||||
logger := cd.log
|
||||
// wait for cache to populate first time
|
||||
if !cache.WaitForCacheSync(stopCh, cd.cmSycned) {
|
||||
glog.Error("configuration: failed to sync informer cache")
|
||||
logger.Info("configuration: failed to sync informer cache")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -103,16 +105,17 @@ func (cd *ConfigData) updateCM(old, cur interface{}) {
|
|||
}
|
||||
|
||||
func (cd *ConfigData) deleteCM(obj interface{}) {
|
||||
logger := cd.log
|
||||
cm, ok := obj.(*v1.ConfigMap)
|
||||
if !ok {
|
||||
tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
|
||||
if !ok {
|
||||
glog.Info(fmt.Errorf("Couldn't get object from tombstone %#v", obj))
|
||||
logger.Info("failed to get object from tombstone")
|
||||
return
|
||||
}
|
||||
_, ok = tombstone.Obj.(*v1.ConfigMap)
|
||||
if !ok {
|
||||
glog.Info(fmt.Errorf("Tombstone contained object that is not a ConfigMap %#v", obj))
|
||||
logger.Info("Tombstone contained object that is not a ConfigMap", "object", obj)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -125,19 +128,20 @@ func (cd *ConfigData) deleteCM(obj interface{}) {
|
|||
}
|
||||
|
||||
func (cd *ConfigData) load(cm v1.ConfigMap) {
|
||||
logger := cd.log.WithValues("name", cm.Name, "namespace", cm.Namespace)
|
||||
if cm.Data == nil {
|
||||
glog.V(4).Infof("Configuration: No data defined in ConfigMap %s", cm.Name)
|
||||
logger.V(4).Info("configuration: No data defined in ConfigMap")
|
||||
return
|
||||
}
|
||||
// get resource filters
|
||||
filters, ok := cm.Data["resourceFilters"]
|
||||
if !ok {
|
||||
glog.V(4).Infof("Configuration: No resourceFilters defined in ConfigMap %s", cm.Name)
|
||||
logger.V(4).Info("configuration: No resourceFilters defined in ConfigMap")
|
||||
return
|
||||
}
|
||||
// filters is a string
|
||||
if filters == "" {
|
||||
glog.V(4).Infof("Configuration: resourceFilters is empty in ConfigMap %s", cm.Name)
|
||||
logger.V(4).Info("configuration: resourceFilters is empty in ConfigMap")
|
||||
return
|
||||
}
|
||||
// parse and load the configuration
|
||||
|
@ -146,11 +150,10 @@ func (cd *ConfigData) load(cm v1.ConfigMap) {
|
|||
|
||||
newFilters := parseKinds(filters)
|
||||
if reflect.DeepEqual(newFilters, cd.filters) {
|
||||
glog.V(4).Infof("Configuration: resourceFilters did not change in ConfigMap %s", cm.Name)
|
||||
logger.V(4).Info("resourceFilters did not change")
|
||||
return
|
||||
}
|
||||
glog.V(4).Infof("Configuration: Old resource filters %v", cd.filters)
|
||||
glog.Infof("Configuration: New resource filters to %v", newFilters)
|
||||
logger.V(4).Info(" Updated resource filters", "oldFilters", cd.filters, "newFilters", newFilters)
|
||||
// update filters
|
||||
cd.filters = newFilters
|
||||
}
|
||||
|
@ -158,20 +161,20 @@ func (cd *ConfigData) load(cm v1.ConfigMap) {
|
|||
//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
|
||||
func (cd *ConfigData) initFilters(filters string) {
|
||||
logger := cd.log
|
||||
// parse and load the configuration
|
||||
cd.mux.Lock()
|
||||
defer cd.mux.Unlock()
|
||||
|
||||
newFilters := parseKinds(filters)
|
||||
glog.Infof("Configuration: Init resource filters to %v", newFilters)
|
||||
logger.Info("Init resource filters", "filters", newFilters)
|
||||
// update filters
|
||||
cd.filters = newFilters
|
||||
}
|
||||
|
||||
func (cd *ConfigData) unload(cm v1.ConfigMap) {
|
||||
// TODO pick one msg
|
||||
glog.Infof("Configuration: ConfigMap %s deleted, removing configuration filters", cm.Name)
|
||||
glog.Infof("Configuration: Removing all resource filters as ConfigMap %s deleted", cm.Name)
|
||||
logger := cd.log
|
||||
logger.Info("ConfigMap deleted, removing configuration filters", "name", cm.Name, "namespace", cm.Namespace)
|
||||
cd.mux.Lock()
|
||||
defer cd.mux.Unlock()
|
||||
cd.filters = []k8Resource{}
|
||||
|
|
|
@ -6,7 +6,6 @@ import (
|
|||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/nirmata/kyverno/pkg/config"
|
||||
tls "github.com/nirmata/kyverno/pkg/tls"
|
||||
certificates "k8s.io/api/certificates/v1beta1"
|
||||
|
@ -19,13 +18,14 @@ import (
|
|||
// Created pair is stored in cluster's secret.
|
||||
// Returns struct with key/certificate pair.
|
||||
func (c *Client) InitTLSPemPair(configuration *rest.Config, fqdncn bool) (*tls.TlsPemPair, error) {
|
||||
logger := c.log
|
||||
certProps, err := c.GetTLSCertProps(configuration)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tlsPair := c.ReadTlsPair(certProps)
|
||||
if tls.IsTLSPairShouldBeUpdated(tlsPair) {
|
||||
glog.Info("Generating new key/certificate pair for TLS")
|
||||
logger.Info("Generating new key/certificate pair for TLS")
|
||||
tlsPair, err = c.generateTLSPemPair(certProps, fqdncn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -35,8 +35,7 @@ func (c *Client) InitTLSPemPair(configuration *rest.Config, fqdncn bool) (*tls.T
|
|||
}
|
||||
return tlsPair, nil
|
||||
}
|
||||
|
||||
glog.Infoln("Using existing TLS key/certificate pair")
|
||||
logger.Info("Using existing TLS key/certificate pair")
|
||||
return tlsPair, nil
|
||||
}
|
||||
|
||||
|
@ -71,6 +70,7 @@ func (c *Client) generateTLSPemPair(props tls.TlsCertificateProps, fqdncn bool)
|
|||
|
||||
// Submits and approves certificate request, returns request which need to be fetched
|
||||
func (c *Client) submitAndApproveCertificateRequest(req *certificates.CertificateSigningRequest) (*certificates.CertificateSigningRequest, error) {
|
||||
logger := c.log.WithName("submitAndApproveCertificateRequest")
|
||||
certClient, err := c.GetCSRInterface()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -86,7 +86,7 @@ func (c *Client) submitAndApproveCertificateRequest(req *certificates.Certificat
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to delete existing certificate request: %v", err)
|
||||
}
|
||||
glog.Info("Old certificate request is deleted")
|
||||
logger.Info("Old certificate request is deleted")
|
||||
break
|
||||
}
|
||||
}
|
||||
|
@ -95,7 +95,7 @@ func (c *Client) submitAndApproveCertificateRequest(req *certificates.Certificat
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
glog.Infof("Certificate request %s is created", unstrRes.GetName())
|
||||
logger.Info("Certificate request created", "name", unstrRes.GetName())
|
||||
|
||||
res, err := convertToCSR(unstrRes)
|
||||
if err != nil {
|
||||
|
@ -110,7 +110,7 @@ func (c *Client) submitAndApproveCertificateRequest(req *certificates.Certificat
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to approve certificate request: %v", err)
|
||||
}
|
||||
glog.Infof("Certificate request %s is approved", res.ObjectMeta.Name)
|
||||
logger.Info("Certificate request is approved", "name", res.ObjectMeta.Name)
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
@ -144,9 +144,10 @@ func (c *Client) fetchCertificateFromRequest(req *certificates.CertificateSignin
|
|||
|
||||
//ReadRootCASecret returns the RootCA from the pre-defined secret
|
||||
func (c *Client) ReadRootCASecret() (result []byte) {
|
||||
logger := c.log.WithName("ReadRootCASecret")
|
||||
certProps, err := c.GetTLSCertProps(c.clientConfig)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
logger.Error(err, "failed to get TLS Cert Properties")
|
||||
return result
|
||||
}
|
||||
sname := generateRootCASecretName(certProps)
|
||||
|
@ -156,16 +157,16 @@ func (c *Client) ReadRootCASecret() (result []byte) {
|
|||
}
|
||||
tlsca, err := convertToSecret(stlsca)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
logger.Error(err, "failed to convert secret", "name", sname, "namespace", certProps.Namespace)
|
||||
return result
|
||||
}
|
||||
|
||||
result = tlsca.Data[rootCAKey]
|
||||
if len(result) == 0 {
|
||||
glog.Warningf("root CA certificate not found in secret %s/%s", certProps.Namespace, tlsca.Name)
|
||||
logger.Info("root CA certificate not found in secret", "name", tlsca.Name, "namespace", certProps.Namespace)
|
||||
return result
|
||||
}
|
||||
glog.V(4).Infof("using CA bundle defined in secret %s/%s to validate the webhook's server certificate", certProps.Namespace, tlsca.Name)
|
||||
logger.V(4).Info("using CA bundle defined in secret to validate the webhook's server certificate", "name", tlsca.Name, "namespace", certProps.Namespace)
|
||||
return result
|
||||
}
|
||||
|
||||
|
@ -174,10 +175,11 @@ const rootCAKey string = "rootCA.crt"
|
|||
|
||||
//ReadTlsPair Reads the pair of TLS certificate and key from the specified secret.
|
||||
func (c *Client) ReadTlsPair(props tls.TlsCertificateProps) *tls.TlsPemPair {
|
||||
logger := c.log.WithName("ReadTlsPair")
|
||||
sname := generateTLSPairSecretName(props)
|
||||
unstrSecret, err := c.GetResource(Secrets, props.Namespace, sname)
|
||||
if err != nil {
|
||||
glog.Warningf("Unable to get secret %s/%s: %s", props.Namespace, sname, err)
|
||||
logger.Error(err, "Failed to get secret", "name", sname, "namespace", props.Namespace)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -188,7 +190,7 @@ func (c *Client) ReadTlsPair(props tls.TlsCertificateProps) *tls.TlsPemPair {
|
|||
sname := generateRootCASecretName(props)
|
||||
_, err := c.GetResource(Secrets, props.Namespace, sname)
|
||||
if err != nil {
|
||||
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)
|
||||
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)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -201,11 +203,11 @@ func (c *Client) ReadTlsPair(props tls.TlsCertificateProps) *tls.TlsPemPair {
|
|||
PrivateKey: secret.Data[v1.TLSPrivateKeyKey],
|
||||
}
|
||||
if len(pemPair.Certificate) == 0 {
|
||||
glog.Warningf("TLS Certificate not found in secret %s/%s", props.Namespace, sname)
|
||||
logger.Info("TLS Certificate not found in secret", "name", sname, "namespace", props.Namespace)
|
||||
return nil
|
||||
}
|
||||
if len(pemPair.PrivateKey) == 0 {
|
||||
glog.Warningf("TLS PrivateKey not found in secret %s/%s", props.Namespace, sname)
|
||||
logger.Info("TLS PrivateKey not found in secret", "name", sname, "namespace", props.Namespace)
|
||||
return nil
|
||||
}
|
||||
return &pemPair
|
||||
|
@ -214,6 +216,7 @@ func (c *Client) ReadTlsPair(props tls.TlsCertificateProps) *tls.TlsPemPair {
|
|||
//WriteTlsPair Writes the pair of TLS certificate and key to the specified secret.
|
||||
// Updates existing secret or creates new one.
|
||||
func (c *Client) WriteTlsPair(props tls.TlsCertificateProps, pemPair *tls.TlsPemPair) error {
|
||||
logger := c.log.WithName("WriteTlsPair")
|
||||
name := generateTLSPairSecretName(props)
|
||||
_, err := c.GetResource(Secrets, props.Namespace, name)
|
||||
if err != nil {
|
||||
|
@ -235,7 +238,7 @@ func (c *Client) WriteTlsPair(props tls.TlsCertificateProps, pemPair *tls.TlsPem
|
|||
|
||||
_, err := c.CreateResource(Secrets, props.Namespace, secret, false)
|
||||
if err == nil {
|
||||
glog.Infof("Secret %s is created", name)
|
||||
logger.Info("secret created", "name", name, "namespace", props.Namespace)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
@ -251,7 +254,7 @@ func (c *Client) WriteTlsPair(props tls.TlsCertificateProps, pemPair *tls.TlsPem
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
glog.Infof("Secret %s is updated", name)
|
||||
logger.Info("secret updated", "name", name, "namespace", props.Namespace)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -5,9 +5,8 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
openapi_v2 "github.com/googleapis/gnostic/OpenAPIv2"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/nirmata/kyverno/pkg/config"
|
||||
apps "k8s.io/api/apps/v1"
|
||||
certificates "k8s.io/api/certificates/v1beta1"
|
||||
|
@ -32,13 +31,15 @@ import (
|
|||
//Client enables interaction with k8 resource
|
||||
type Client struct {
|
||||
client dynamic.Interface
|
||||
log logr.Logger
|
||||
clientConfig *rest.Config
|
||||
kclient kubernetes.Interface
|
||||
DiscoveryClient IDiscovery
|
||||
}
|
||||
|
||||
//NewClient creates new instance of client
|
||||
func NewClient(config *rest.Config, resync time.Duration, stopCh <-chan struct{}) (*Client, error) {
|
||||
func NewClient(config *rest.Config, resync time.Duration, stopCh <-chan struct{}, log logr.Logger) (*Client, error) {
|
||||
|
||||
dclient, err := dynamic.NewForConfig(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -51,9 +52,10 @@ func NewClient(config *rest.Config, resync time.Duration, stopCh <-chan struct{}
|
|||
client: dclient,
|
||||
clientConfig: config,
|
||||
kclient: kclient,
|
||||
log: log.WithName("Client"),
|
||||
}
|
||||
// Set discovery client
|
||||
discoveryClient := ServerPreferredResources{memory.NewMemCacheClient(kclient.Discovery())}
|
||||
discoveryClient := ServerPreferredResources{cachedClient: memory.NewMemCacheClient(kclient.Discovery()), log: client.log}
|
||||
// client will invalidate registered resources cache every x seconds,
|
||||
// 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
|
||||
|
@ -189,7 +191,6 @@ func (c *Client) UpdateStatusResource(kind string, namespace string, obj interfa
|
|||
func convertToUnstructured(obj interface{}) *unstructured.Unstructured {
|
||||
unstructuredObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&obj)
|
||||
if err != nil {
|
||||
glog.Errorf("Unable to convert : %v", err)
|
||||
return nil
|
||||
}
|
||||
return &unstructured.Unstructured{Object: unstructuredObj}
|
||||
|
@ -228,22 +229,24 @@ func (c *Client) SetDiscovery(discoveryClient IDiscovery) {
|
|||
//ServerPreferredResources stores the cachedClient instance for discovery client
|
||||
type ServerPreferredResources struct {
|
||||
cachedClient discovery.CachedDiscoveryInterface
|
||||
log logr.Logger
|
||||
}
|
||||
|
||||
//Poll will keep invalidate the local cache
|
||||
func (c ServerPreferredResources) Poll(resync time.Duration, stopCh <-chan struct{}) {
|
||||
logger := c.log.WithName("Poll")
|
||||
// start a ticker
|
||||
ticker := time.NewTicker(resync)
|
||||
defer func() { ticker.Stop() }()
|
||||
glog.Infof("Starting registered resources sync: every %d seconds", resync)
|
||||
logger.Info("starting registered resources sync", "period", resync)
|
||||
for {
|
||||
select {
|
||||
case <-stopCh:
|
||||
glog.Info("Stopping registered resources sync")
|
||||
logger.Info("stopping registered resources sync")
|
||||
return
|
||||
case <-ticker.C:
|
||||
// set cache as stale
|
||||
glog.V(6).Info("invalidating local client cache for registered resources")
|
||||
logger.V(6).Info("invalidating local client cache for registered resources")
|
||||
c.cachedClient.Invalidate()
|
||||
}
|
||||
}
|
||||
|
@ -261,12 +264,12 @@ func (c ServerPreferredResources) OpenAPISchema() (*openapi_v2.Document, error)
|
|||
func (c ServerPreferredResources) GetGVRFromKind(kind string) schema.GroupVersionResource {
|
||||
var gvr schema.GroupVersionResource
|
||||
var err error
|
||||
gvr, err = loadServerResources(kind, c.cachedClient)
|
||||
gvr, err = loadServerResources(kind, c.cachedClient, c.log)
|
||||
if err != nil && !c.cachedClient.Fresh() {
|
||||
|
||||
// invalidate cahce & re-try once more
|
||||
c.cachedClient.Invalidate()
|
||||
gvr, err = loadServerResources(kind, c.cachedClient)
|
||||
gvr, err = loadServerResources(kind, c.cachedClient, c.log)
|
||||
if err == nil {
|
||||
return gvr
|
||||
}
|
||||
|
@ -279,11 +282,12 @@ func (c ServerPreferredResources) GetServerVersion() (*version.Info, error) {
|
|||
return c.cachedClient.ServerVersion()
|
||||
}
|
||||
|
||||
func loadServerResources(k string, cdi discovery.CachedDiscoveryInterface) (schema.GroupVersionResource, error) {
|
||||
serverresources, err := cdi.ServerPreferredResources()
|
||||
func loadServerResources(k string, cdi discovery.CachedDiscoveryInterface, log logr.Logger) (schema.GroupVersionResource, error) {
|
||||
logger := log.WithName("loadServerResources")
|
||||
emptyGVR := schema.GroupVersionResource{}
|
||||
serverresources, err := cdi.ServerPreferredResources()
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
logger.Error(err, "failed to get registered preferred resources")
|
||||
return emptyGVR, err
|
||||
}
|
||||
for _, serverresource := range serverresources {
|
||||
|
@ -293,7 +297,7 @@ func loadServerResources(k string, cdi discovery.CachedDiscoveryInterface) (sche
|
|||
if resource.Kind == k && !strings.Contains(resource.Name, "/") {
|
||||
gv, err := schema.ParseGroupVersion(serverresource.GroupVersion)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
logger.Error(err, "failed to parse groupVersion from schema", "groupVersion", serverresource.GroupVersion)
|
||||
return emptyGVR, err
|
||||
}
|
||||
return gv.WithResource(resource.Name), nil
|
||||
|
|
|
@ -4,7 +4,8 @@ import (
|
|||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/go-logr/logr"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
)
|
||||
|
||||
//ValidationHandler for element processes
|
||||
|
@ -12,7 +13,7 @@ type ValidationHandler interface {
|
|||
Handle(handler resourceElementHandler, resourceMap map[string]interface{}, originPattern interface{}) (string, error)
|
||||
}
|
||||
|
||||
type resourceElementHandler = func(resourceElement, patternElement, originPattern interface{}, path string) (string, error)
|
||||
type resourceElementHandler = func(log logr.Logger, resourceElement, patternElement, originPattern interface{}, path string) (string, error)
|
||||
|
||||
//CreateElementHandler factory to process elements
|
||||
func CreateElementHandler(element string, pattern interface{}, path string) ValidationHandler {
|
||||
|
@ -82,7 +83,7 @@ func (eh EqualityHandler) Handle(handler resourceElementHandler, resourceMap map
|
|||
// check if anchor is present in resource
|
||||
if value, ok := resourceMap[anchorKey]; ok {
|
||||
// validate the values of the pattern
|
||||
returnPath, err := handler(value, eh.pattern, originPattern, currentPath)
|
||||
returnPath, err := handler(log.Log, value, eh.pattern, originPattern, currentPath)
|
||||
if err != nil {
|
||||
return returnPath, err
|
||||
}
|
||||
|
@ -115,7 +116,7 @@ func (dh DefaultHandler) Handle(handler resourceElementHandler, resourceMap map[
|
|||
} 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)
|
||||
} else {
|
||||
path, err := handler(resourceMap[dh.element], dh.pattern, originPattern, currentPath)
|
||||
path, err := handler(log.Log, resourceMap[dh.element], dh.pattern, originPattern, currentPath)
|
||||
if err != nil {
|
||||
return path, err
|
||||
}
|
||||
|
@ -146,7 +147,7 @@ func (ch ConditionAnchorHandler) Handle(handler resourceElementHandler, resource
|
|||
// check if anchor is present in resource
|
||||
if value, ok := resourceMap[anchorKey]; ok {
|
||||
// validate the values of the pattern
|
||||
returnPath, err := handler(value, ch.pattern, originPattern, currentPath)
|
||||
returnPath, err := handler(log.Log, value, ch.pattern, originPattern, currentPath)
|
||||
if err != nil {
|
||||
return returnPath, err
|
||||
}
|
||||
|
@ -194,7 +195,6 @@ func (eh ExistenceHandler) Handle(handler resourceElementHandler, resourceMap ma
|
|||
}
|
||||
return validateExistenceListResource(handler, typedResource, typedPatternMap, originPattern, currentPath)
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -206,10 +206,9 @@ func validateExistenceListResource(handler resourceElementHandler, resourceList
|
|||
// if non satisfy then throw an error
|
||||
for i, resourceElement := range resourceList {
|
||||
currentPath := path + strconv.Itoa(i) + "/"
|
||||
_, err := handler(resourceElement, patternMap, originPattern, currentPath)
|
||||
_, err := handler(log.Log, resourceElement, patternMap, originPattern, currentPath)
|
||||
if err == nil {
|
||||
// condition is satisfied, dont check further
|
||||
glog.V(4).Infof("Existence check satisfied at path %s, for pattern %v", currentPath, patternMap)
|
||||
return "", nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,8 +6,9 @@ import (
|
|||
"sync"
|
||||
|
||||
jsonpatch "github.com/evanphx/json-patch"
|
||||
"github.com/golang/glog"
|
||||
"github.com/go-logr/logr"
|
||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
)
|
||||
|
||||
//Interface to manage context operations
|
||||
|
@ -33,6 +34,7 @@ type Context struct {
|
|||
mu sync.RWMutex
|
||||
jsonRaw []byte
|
||||
whiteListVars []string
|
||||
log logr.Logger
|
||||
}
|
||||
|
||||
//NewContext returns a new context
|
||||
|
@ -42,6 +44,7 @@ func NewContext(whiteListVars ...string) *Context {
|
|||
// data: map[string]interface{}{},
|
||||
jsonRaw: []byte(`{}`), // empty json struct
|
||||
whiteListVars: whiteListVars,
|
||||
log: log.Log.WithName("context"),
|
||||
}
|
||||
return &ctx
|
||||
}
|
||||
|
@ -54,7 +57,7 @@ func (ctx *Context) AddJSON(dataRaw []byte) error {
|
|||
// merge json
|
||||
ctx.jsonRaw, err = jsonpatch.MergePatch(ctx.jsonRaw, dataRaw)
|
||||
if err != nil {
|
||||
glog.V(4).Infof("failed to merge JSON data: %v", err)
|
||||
ctx.log.Error(err, "failed to merge JSON data")
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
@ -66,7 +69,7 @@ func (ctx *Context) AddResource(dataRaw []byte) error {
|
|||
// unmarshall the resource struct
|
||||
var data interface{}
|
||||
if err := json.Unmarshal(dataRaw, &data); err != nil {
|
||||
glog.V(4).Infof("failed to unmarshall the context data: %v", err)
|
||||
ctx.log.Error(err, "failed to unmarshall the resource")
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -82,7 +85,7 @@ func (ctx *Context) AddResource(dataRaw []byte) error {
|
|||
|
||||
objRaw, err := json.Marshal(modifiedResource)
|
||||
if err != nil {
|
||||
glog.V(4).Infof("failed to marshall the updated context data")
|
||||
ctx.log.Error(err, "failed to marshal the resource")
|
||||
return err
|
||||
}
|
||||
return ctx.AddJSON(objRaw)
|
||||
|
@ -98,7 +101,7 @@ func (ctx *Context) AddUserInfo(userRequestInfo kyverno.RequestInfo) error {
|
|||
|
||||
objRaw, err := json.Marshal(modifiedResource)
|
||||
if err != nil {
|
||||
glog.V(4).Infof("failed to marshall the updated context data")
|
||||
ctx.log.Error(err, "failed to marshal the UserInfo")
|
||||
return err
|
||||
}
|
||||
return ctx.AddJSON(objRaw)
|
||||
|
@ -118,8 +121,6 @@ func (ctx *Context) AddSA(userName string) error {
|
|||
// filter namespace
|
||||
groups := strings.Split(sa, ":")
|
||||
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]
|
||||
saNamespace = groups[0]
|
||||
}
|
||||
|
@ -131,7 +132,7 @@ func (ctx *Context) AddSA(userName string) error {
|
|||
}
|
||||
saNameRaw, err := json.Marshal(saNameObj)
|
||||
if err != nil {
|
||||
glog.V(4).Infof("failed to marshall the updated context data")
|
||||
ctx.log.Error(err, "failed to marshal the SA")
|
||||
return err
|
||||
}
|
||||
if err := ctx.AddJSON(saNameRaw); err != nil {
|
||||
|
@ -145,7 +146,7 @@ func (ctx *Context) AddSA(userName string) error {
|
|||
}
|
||||
saNsRaw, err := json.Marshal(saNsObj)
|
||||
if err != nil {
|
||||
glog.V(4).Infof("failed to marshall the updated context data")
|
||||
ctx.log.Error(err, "failed to marshal the SA namespace")
|
||||
return err
|
||||
}
|
||||
if err := ctx.AddJSON(saNsRaw); err != nil {
|
||||
|
|
|
@ -4,7 +4,6 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/golang/glog"
|
||||
jmespath "github.com/jmespath/go-jmespath"
|
||||
)
|
||||
|
||||
|
@ -19,7 +18,7 @@ func (ctx *Context) Query(query string) (interface{}, error) {
|
|||
// compile the query
|
||||
queryPath, err := jmespath.Compile(query)
|
||||
if err != nil {
|
||||
glog.V(4).Infof("incorrect query %s: %v", query, err)
|
||||
ctx.log.Error(err, "incorrect query", "query", query)
|
||||
return emptyResult, fmt.Errorf("incorrect query %s: %v", query, err)
|
||||
}
|
||||
// search
|
||||
|
@ -28,13 +27,13 @@ func (ctx *Context) Query(query string) (interface{}, error) {
|
|||
|
||||
var data interface{}
|
||||
if err := json.Unmarshal(ctx.jsonRaw, &data); err != nil {
|
||||
glog.V(4).Infof("failed to unmarshall context: %v", err)
|
||||
ctx.log.Error(err, "failed to unmarshal context")
|
||||
return emptyResult, fmt.Errorf("failed to unmarshall context: %v", err)
|
||||
}
|
||||
|
||||
result, err := queryPath.Search(data)
|
||||
if err != nil {
|
||||
glog.V(4).Infof("failed to search query %s: %v", query, err)
|
||||
ctx.log.Error(err, "failed to search query", "query", query)
|
||||
return emptyResult, fmt.Errorf("failed to search query %s: %v", query, err)
|
||||
}
|
||||
return result, nil
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"github.com/nirmata/kyverno/pkg/engine/utils"
|
||||
"github.com/nirmata/kyverno/pkg/engine/variables"
|
||||
"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) {
|
||||
|
@ -57,7 +58,7 @@ func ForceMutate(ctx context.EvalInterface, policy kyverno.ClusterPolicy, resour
|
|||
if mutation.Overlay != nil {
|
||||
overlay := mutation.Overlay
|
||||
if ctx != nil {
|
||||
if overlay, err = variables.SubstituteVars(ctx, overlay); err != nil {
|
||||
if overlay, err = variables.SubstituteVars(log.Log, ctx, overlay); err != nil {
|
||||
return unstructured.Unstructured{}, err
|
||||
}
|
||||
} else {
|
||||
|
@ -72,7 +73,7 @@ func ForceMutate(ctx context.EvalInterface, policy kyverno.ClusterPolicy, resour
|
|||
|
||||
if rule.Mutation.Patches != nil {
|
||||
var resp response.RuleResponse
|
||||
resp, resource = mutate.ProcessPatches(rule, resource)
|
||||
resp, resource = mutate.ProcessPatches(log.Log, rule, resource)
|
||||
if !resp.Success {
|
||||
return unstructured.Unstructured{}, fmt.Errorf(resp.Message)
|
||||
}
|
||||
|
|
|
@ -3,12 +3,14 @@ package engine
|
|||
import (
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/go-logr/logr"
|
||||
|
||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||
"github.com/nirmata/kyverno/pkg/engine/context"
|
||||
"github.com/nirmata/kyverno/pkg/engine/response"
|
||||
"github.com/nirmata/kyverno/pkg/engine/variables"
|
||||
"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
|
||||
|
@ -20,10 +22,11 @@ func Generate(policyContext PolicyContext) (resp response.EngineResponse) {
|
|||
resource := policyContext.NewResource
|
||||
admissionInfo := policyContext.AdmissionInfo
|
||||
ctx := policyContext.Context
|
||||
return filterRules(policy, resource, admissionInfo, ctx)
|
||||
logger := log.Log.WithName("Generate").WithValues("policy", policy.Name, "kind", resource.GetKind(), "namespace", resource.GetNamespace(), "name", resource.GetName())
|
||||
return filterRules(policy, resource, admissionInfo, ctx, logger)
|
||||
}
|
||||
|
||||
func filterRule(rule kyverno.Rule, resource unstructured.Unstructured, admissionInfo kyverno.RequestInfo, ctx context.EvalInterface) *response.RuleResponse {
|
||||
func filterRule(rule kyverno.Rule, resource unstructured.Unstructured, admissionInfo kyverno.RequestInfo, ctx context.EvalInterface, log logr.Logger) *response.RuleResponse {
|
||||
if !rule.HasGenerate() {
|
||||
return nil
|
||||
}
|
||||
|
@ -31,15 +34,14 @@ func filterRule(rule kyverno.Rule, resource unstructured.Unstructured, admission
|
|||
startTime := time.Now()
|
||||
|
||||
if err := MatchesResourceDescription(resource, rule, admissionInfo); err != nil {
|
||||
glog.V(4).Infof(err.Error())
|
||||
return nil
|
||||
}
|
||||
// operate on the copy of the conditions, as we perform variable substitution
|
||||
copyConditions := copyConditions(rule.Conditions)
|
||||
|
||||
// evaluate pre-conditions
|
||||
if !variables.EvaluateConditions(ctx, copyConditions) {
|
||||
glog.V(4).Infof("resource %s/%s does not satisfy the conditions for the rule ", resource.GetNamespace(), resource.GetName())
|
||||
if !variables.EvaluateConditions(log, ctx, copyConditions) {
|
||||
log.V(4).Info("preconditions not satisfied, skipping rule", "rule", rule.Name)
|
||||
return nil
|
||||
}
|
||||
// build rule Response
|
||||
|
@ -53,7 +55,7 @@ func filterRule(rule kyverno.Rule, resource unstructured.Unstructured, admission
|
|||
}
|
||||
}
|
||||
|
||||
func filterRules(policy kyverno.ClusterPolicy, resource unstructured.Unstructured, admissionInfo kyverno.RequestInfo, ctx context.EvalInterface) response.EngineResponse {
|
||||
func filterRules(policy kyverno.ClusterPolicy, resource unstructured.Unstructured, admissionInfo kyverno.RequestInfo, ctx context.EvalInterface, log logr.Logger) response.EngineResponse {
|
||||
resp := response.EngineResponse{
|
||||
PolicyResponse: response.PolicyResponse{
|
||||
Policy: policy.Name,
|
||||
|
@ -66,7 +68,7 @@ func filterRules(policy kyverno.ClusterPolicy, resource unstructured.Unstructure
|
|||
}
|
||||
|
||||
for _, rule := range policy.Spec.Rules {
|
||||
if ruleResp := filterRule(rule, resource, admissionInfo, ctx); ruleResp != nil {
|
||||
if ruleResp := filterRule(rule, resource, admissionInfo, ctx, log); ruleResp != nil {
|
||||
resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, *ruleResp)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,51 +10,53 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
|
||||
jsonpatch "github.com/evanphx/json-patch"
|
||||
"github.com/go-logr/logr"
|
||||
"github.com/nirmata/kyverno/pkg/engine/anchor"
|
||||
"github.com/nirmata/kyverno/pkg/engine/response"
|
||||
"github.com/nirmata/kyverno/pkg/engine/utils"
|
||||
)
|
||||
|
||||
// ProcessOverlay processes mutation overlay on the resource
|
||||
func ProcessOverlay(ruleName string, overlay interface{}, resource unstructured.Unstructured) (resp response.RuleResponse, patchedResource unstructured.Unstructured) {
|
||||
func ProcessOverlay(log logr.Logger, ruleName string, overlay interface{}, resource unstructured.Unstructured) (resp response.RuleResponse, patchedResource unstructured.Unstructured) {
|
||||
startTime := time.Now()
|
||||
glog.V(4).Infof("started applying overlay rule %q (%v)", ruleName, startTime)
|
||||
logger := log.WithValues("rule", ruleName)
|
||||
logger.V(4).Info("started applying overlay rule ", "startTime", startTime)
|
||||
resp.Name = ruleName
|
||||
resp.Type = utils.Mutation.String()
|
||||
defer func() {
|
||||
resp.RuleStats.ProcessingTime = time.Since(startTime)
|
||||
glog.V(4).Infof("finished applying overlay rule %q (%v)", resp.Name, resp.RuleStats.ProcessingTime)
|
||||
logger.V(4).Info("finished applying overlay rule", "processingTime", resp.RuleStats.ProcessingTime)
|
||||
}()
|
||||
|
||||
patches, overlayerr := processOverlayPatches(resource.UnstructuredContent(), overlay)
|
||||
patches, overlayerr := processOverlayPatches(logger, resource.UnstructuredContent(), overlay)
|
||||
// resource does not satisfy the overlay pattern, we don't apply this rule
|
||||
if !reflect.DeepEqual(overlayerr, overlayError{}) {
|
||||
switch overlayerr.statusCode {
|
||||
// condition key is not present in the resource, don't apply this rule
|
||||
// consider as success
|
||||
case conditionNotPresent:
|
||||
glog.V(3).Infof("Skip applying rule '%s' on resource '%s/%s/%s': %s", ruleName, resource.GetKind(), resource.GetNamespace(), resource.GetName(), overlayerr.ErrorMsg())
|
||||
logger.V(3).Info("skip applying rule")
|
||||
resp.Success = true
|
||||
return resp, resource
|
||||
// conditions are not met, don't apply this rule
|
||||
case conditionFailure:
|
||||
glog.V(3).Infof("Skip applying rule '%s' on resource '%s/%s/%s': %s", ruleName, resource.GetKind(), resource.GetNamespace(), resource.GetName(), overlayerr.ErrorMsg())
|
||||
logger.V(3).Info("skip applying rule")
|
||||
//TODO: send zero response and not consider this as applied?
|
||||
resp.Success = true
|
||||
resp.Message = overlayerr.ErrorMsg()
|
||||
return resp, resource
|
||||
// rule application failed
|
||||
case overlayFailure:
|
||||
glog.Errorf("Resource %s/%s/%s: failed to process overlay: %v in the rule %s", resource.GetKind(), resource.GetNamespace(), resource.GetName(), overlayerr.ErrorMsg(), ruleName)
|
||||
logger.Info("failed to process overlay")
|
||||
resp.Success = false
|
||||
resp.Message = fmt.Sprintf("failed to process overlay: %v", overlayerr.ErrorMsg())
|
||||
return resp, resource
|
||||
default:
|
||||
glog.Errorf("Resource %s/%s/%s: Unknown type of error: %v", resource.GetKind(), resource.GetNamespace(), resource.GetName(), overlayerr.Error())
|
||||
logger.Info("failed to process overlay")
|
||||
resp.Success = false
|
||||
resp.Message = fmt.Sprintf("Unknown type of error: %v", overlayerr.Error())
|
||||
return resp, resource
|
||||
|
@ -70,7 +72,7 @@ func ProcessOverlay(ruleName string, overlay interface{}, resource unstructured.
|
|||
resourceRaw, err := resource.MarshalJSON()
|
||||
if err != nil {
|
||||
resp.Success = false
|
||||
glog.Infof("unable to marshall resource: %v", err)
|
||||
logger.Error(err, "failed to marshal resource")
|
||||
resp.Message = fmt.Sprintf("failed to process JSON patches: %v", err)
|
||||
return resp, resource
|
||||
}
|
||||
|
@ -79,7 +81,7 @@ func ProcessOverlay(ruleName string, overlay interface{}, resource unstructured.
|
|||
patchResource, err = utils.ApplyPatches(resourceRaw, patches)
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("failed to apply JSON patches: %v", err)
|
||||
glog.V(2).Infof("%s, patches=%s", msg, string(utils.JoinPatches(patches)))
|
||||
logger.V(2).Info("applying patches", "patches", string(utils.JoinPatches(patches)))
|
||||
resp.Success = false
|
||||
resp.Message = msg
|
||||
return resp, resource
|
||||
|
@ -87,7 +89,7 @@ func ProcessOverlay(ruleName string, overlay interface{}, resource unstructured.
|
|||
|
||||
err = patchedResource.UnmarshalJSON(patchResource)
|
||||
if err != nil {
|
||||
glog.Infof("failed to unmarshall resource to undstructured: %v", err)
|
||||
logger.Error(err, "failed to unmarshal resource")
|
||||
resp.Success = false
|
||||
resp.Message = fmt.Sprintf("failed to process JSON patches: %v", err)
|
||||
return resp, resource
|
||||
|
@ -101,17 +103,17 @@ func ProcessOverlay(ruleName string, overlay interface{}, resource unstructured.
|
|||
return resp, patchedResource
|
||||
}
|
||||
|
||||
func processOverlayPatches(resource, overlay interface{}) ([][]byte, overlayError) {
|
||||
if path, overlayerr := meetConditions(resource, overlay); !reflect.DeepEqual(overlayerr, overlayError{}) {
|
||||
func processOverlayPatches(log logr.Logger, resource, overlay interface{}) ([][]byte, overlayError) {
|
||||
if path, overlayerr := meetConditions(log, resource, overlay); !reflect.DeepEqual(overlayerr, overlayError{}) {
|
||||
switch overlayerr.statusCode {
|
||||
// anchor key does not exist in the resource, skip applying policy
|
||||
case conditionNotPresent:
|
||||
glog.V(4).Infof("Mutate rule: skip applying policy: %v at %s", overlayerr, path)
|
||||
log.V(4).Info("skip applying policy", "path", path, "error", overlayerr)
|
||||
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
|
||||
case conditionFailure:
|
||||
// anchor key is not satisfied in the resource, skip applying policy
|
||||
glog.V(4).Infof("Mutate rule: failed to validate condition at %s, err: %v", path, overlayerr)
|
||||
log.V(4).Info("failed to validate condition", "path", path, "error", overlayerr)
|
||||
return nil, newOverlayError(overlayerr.statusCode, fmt.Sprintf("Policy not applied, conditions are not met at %s, %v", path, overlayerr))
|
||||
}
|
||||
}
|
||||
|
@ -383,7 +385,7 @@ func prepareJSONValue(overlay interface{}) string {
|
|||
overlayWithoutAnchors := removeAnchorFromSubTree(overlay)
|
||||
jsonOverlay, err := json.Marshal(overlayWithoutAnchors)
|
||||
if err != nil || hasOnlyAnchors(overlay) {
|
||||
glog.V(3).Info(err)
|
||||
log.Log.Error(err, "failed to marshall withoutanchors or has only anchors")
|
||||
return ""
|
||||
}
|
||||
|
||||
|
@ -409,7 +411,7 @@ func removeAnchorFromSubTree(overlay interface{}) interface{} {
|
|||
}
|
||||
|
||||
func removeAnchroFromMap(overlay map[string]interface{}) map[string]interface{} {
|
||||
result := make(map[string]interface{}, 0)
|
||||
result := make(map[string]interface{})
|
||||
for k, v := range overlay {
|
||||
result[getRawKeyIfWrappedWithAttributes(k)] = removeAnchorFromSubTree(v)
|
||||
}
|
||||
|
|
|
@ -5,17 +5,18 @@ import (
|
|||
"reflect"
|
||||
"strconv"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/go-logr/logr"
|
||||
"github.com/nirmata/kyverno/pkg/engine/anchor"
|
||||
"github.com/nirmata/kyverno/pkg/engine/validate"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
)
|
||||
|
||||
func meetConditions(resource, overlay interface{}) (string, overlayError) {
|
||||
return checkConditions(resource, overlay, "/")
|
||||
func meetConditions(log logr.Logger, resource, overlay interface{}) (string, overlayError) {
|
||||
return checkConditions(log, resource, overlay, "/")
|
||||
}
|
||||
|
||||
// resource and overlay should be the same type
|
||||
func checkConditions(resource, overlay interface{}, path string) (string, overlayError) {
|
||||
func checkConditions(log logr.Logger, resource, overlay interface{}, path string) (string, overlayError) {
|
||||
// overlay has no anchor, return true
|
||||
if !hasNestedAnchors(overlay) {
|
||||
return "", overlayError{}
|
||||
|
@ -26,7 +27,7 @@ func checkConditions(resource, overlay interface{}, path string) (string, overla
|
|||
// condition never be true in this case
|
||||
if reflect.TypeOf(resource) != reflect.TypeOf(overlay) {
|
||||
if hasNestedAnchors(overlay) {
|
||||
glog.V(4).Infof("Found anchor on different types of element at path %s: overlay %T, resource %T", path, overlay, resource)
|
||||
log.V(4).Info(fmt.Sprintf("Found anchor on different types of element at path %s: overlay %T, resource %T", path, overlay, resource))
|
||||
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))
|
||||
|
||||
|
@ -44,7 +45,7 @@ func checkConditions(resource, overlay interface{}, path string) (string, overla
|
|||
default:
|
||||
// anchor on non map/array is invalid:
|
||||
// - anchor defined on values
|
||||
glog.Warningln("Found invalid conditional anchor: anchor defined on values")
|
||||
log.Info("Found invalid conditional anchor: anchor defined on values")
|
||||
return "", overlayError{}
|
||||
}
|
||||
}
|
||||
|
@ -68,12 +69,12 @@ func checkConditionOnMap(resourceMap, overlayMap map[string]interface{}, path st
|
|||
|
||||
func checkConditionOnArray(resource, overlay []interface{}, path string) (string, overlayError) {
|
||||
if 0 == len(overlay) {
|
||||
glog.Infof("Mutate overlay pattern is empty, path %s", path)
|
||||
log.Log.V(4).Info("Mutate overlay pattern is empty", "path", path)
|
||||
return "", overlayError{}
|
||||
}
|
||||
|
||||
if reflect.TypeOf(resource[0]) != reflect.TypeOf(overlay[0]) {
|
||||
glog.V(4).Infof("Overlay array and resource array have elements of different types: %T and %T", overlay[0], resource[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]))
|
||||
return path, newOverlayError(conditionFailure,
|
||||
fmt.Sprintf("Overlay array and resource array have elements of different types: %T and %T", overlay[0], resource[0]))
|
||||
}
|
||||
|
@ -111,7 +112,7 @@ func validateConditionAnchorMap(resourceMap, anchors map[string]interface{}, pat
|
|||
// resource - A: B2
|
||||
func compareOverlay(resource, overlay interface{}, path string) (string, overlayError) {
|
||||
if reflect.TypeOf(resource) != reflect.TypeOf(overlay) {
|
||||
glog.V(4).Infof("Found anchor on different types of element: overlay %T, resource %T", overlay, resource)
|
||||
log.Log.V(4).Info("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))
|
||||
}
|
||||
|
||||
|
@ -139,8 +140,8 @@ func compareOverlay(resource, overlay interface{}, path string) (string, overlay
|
|||
}
|
||||
}
|
||||
case string, float64, int, int64, bool, nil:
|
||||
if !validate.ValidateValueWithPattern(resource, overlay) {
|
||||
glog.V(4).Infof("Mutate rule: failed validating value %v with overlay %v", resource, overlay)
|
||||
if !validate.ValidateValueWithPattern(log.Log, resource, overlay) {
|
||||
log.Log.V(4).Info(fmt.Sprintf("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))
|
||||
}
|
||||
default:
|
||||
|
@ -165,7 +166,7 @@ func validateNonAnchorOverlayMap(resourceMap, overlayWithoutAnchor map[string]in
|
|||
continue
|
||||
}
|
||||
}
|
||||
if newPath, err := checkConditions(resourceValue, overlayValue, curPath); !reflect.DeepEqual(err, overlayError{}) {
|
||||
if newPath, err := checkConditions(log.Log, resourceValue, overlayValue, curPath); !reflect.DeepEqual(err, overlayError{}) {
|
||||
return newPath, err
|
||||
}
|
||||
}
|
||||
|
@ -179,7 +180,7 @@ func checkConditionsOnArrayOfSameTypes(resource, overlay []interface{}, path str
|
|||
default:
|
||||
for i, overlayElement := range overlay {
|
||||
curPath := path + strconv.Itoa(i) + "/"
|
||||
path, err := checkConditions(resource[i], overlayElement, curPath)
|
||||
path, err := checkConditions(log.Log, resource[i], overlayElement, curPath)
|
||||
if !reflect.DeepEqual(err, overlayError{}) {
|
||||
return path, err
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"gotest.tools/assert"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
)
|
||||
|
||||
func TestMeetConditions_NoAnchor(t *testing.T) {
|
||||
|
@ -26,9 +27,11 @@ func TestMeetConditions_NoAnchor(t *testing.T) {
|
|||
}`)
|
||||
var overlay interface{}
|
||||
|
||||
json.Unmarshal(overlayRaw, &overlay)
|
||||
err := 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{}))
|
||||
}
|
||||
|
||||
|
@ -78,10 +81,12 @@ func TestMeetConditions_conditionalAnchorOnMap(t *testing.T) {
|
|||
|
||||
var resource, overlay interface{}
|
||||
|
||||
json.Unmarshal(resourceRaw, &resource)
|
||||
json.Unmarshal(overlayRaw, &overlay)
|
||||
err := json.Unmarshal(resourceRaw, &resource)
|
||||
assert.NilError(t, err)
|
||||
err = json.Unmarshal(overlayRaw, &overlay)
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err := meetConditions(resource, overlay)
|
||||
_, err = meetConditions(log.Log, resource, overlay)
|
||||
assert.Assert(t, !reflect.DeepEqual(err, overlayError{}))
|
||||
|
||||
overlayRaw = []byte(`
|
||||
|
@ -99,9 +104,10 @@ func TestMeetConditions_conditionalAnchorOnMap(t *testing.T) {
|
|||
]
|
||||
}`)
|
||||
|
||||
json.Unmarshal(overlayRaw, &overlay)
|
||||
err = json.Unmarshal(overlayRaw, &overlay)
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, overlayerr := meetConditions(resource, overlay)
|
||||
_, overlayerr := meetConditions(log.Log, resource, overlay)
|
||||
assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{}))
|
||||
}
|
||||
|
||||
|
@ -136,11 +142,14 @@ func TestMeetConditions_DifferentTypes(t *testing.T) {
|
|||
}`)
|
||||
var resource, overlay interface{}
|
||||
|
||||
json.Unmarshal(resourceRaw, &resource)
|
||||
json.Unmarshal(overlayRaw, &overlay)
|
||||
err := json.Unmarshal(resourceRaw, &resource)
|
||||
assert.NilError(t, err)
|
||||
err = json.Unmarshal(overlayRaw, &overlay)
|
||||
assert.NilError(t, err)
|
||||
|
||||
// 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/"))
|
||||
}
|
||||
|
||||
|
@ -190,10 +199,12 @@ func TestMeetConditions_anchosInSameObject(t *testing.T) {
|
|||
|
||||
var resource, overlay interface{}
|
||||
|
||||
json.Unmarshal(resourceRaw, &resource)
|
||||
json.Unmarshal(overlayRaw, &overlay)
|
||||
err := json.Unmarshal(resourceRaw, &resource)
|
||||
assert.NilError(t, err)
|
||||
err = json.Unmarshal(overlayRaw, &overlay)
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err := meetConditions(resource, overlay)
|
||||
_, err = meetConditions(log.Log, resource, overlay)
|
||||
assert.Error(t, err, "[overlayError:0] Failed validating value 443 with overlay 444")
|
||||
}
|
||||
|
||||
|
@ -248,10 +259,13 @@ func TestMeetConditions_anchorOnPeer(t *testing.T) {
|
|||
|
||||
var resource, overlay interface{}
|
||||
|
||||
json.Unmarshal(resourceRaw, &resource)
|
||||
json.Unmarshal(overlayRaw, &overlay)
|
||||
err := json.Unmarshal(resourceRaw, &resource)
|
||||
assert.NilError(t, err)
|
||||
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{}))
|
||||
}
|
||||
|
||||
|
@ -325,10 +339,13 @@ func TestMeetConditions_anchorsOnMetaAndSpec(t *testing.T) {
|
|||
|
||||
var resource, overlay interface{}
|
||||
|
||||
json.Unmarshal(resourceRaw, &resource)
|
||||
json.Unmarshal(overlayRaw, &overlay)
|
||||
err := json.Unmarshal(resourceRaw, &resource)
|
||||
assert.NilError(t, err)
|
||||
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{}))
|
||||
}
|
||||
|
||||
|
@ -406,10 +423,13 @@ func TestMeetConditions_anchorsOnPeer_single(t *testing.T) {
|
|||
|
||||
var resource, overlay interface{}
|
||||
|
||||
json.Unmarshal(resourceRawAnchorOnPeers, &resource)
|
||||
json.Unmarshal(overlayRaw, &overlay)
|
||||
err := json.Unmarshal(resourceRawAnchorOnPeers, &resource)
|
||||
assert.NilError(t, err)
|
||||
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{}))
|
||||
}
|
||||
|
||||
|
@ -440,10 +460,13 @@ func TestMeetConditions_anchorsOnPeer_two(t *testing.T) {
|
|||
|
||||
var resource, overlay interface{}
|
||||
|
||||
json.Unmarshal(resourceRawAnchorOnPeers, &resource)
|
||||
json.Unmarshal(overlayRaw, &overlay)
|
||||
err := json.Unmarshal(resourceRawAnchorOnPeers, &resource)
|
||||
assert.NilError(t, err)
|
||||
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")
|
||||
|
||||
overlayRaw = []byte(`{
|
||||
|
@ -470,9 +493,10 @@ func TestMeetConditions_anchorsOnPeer_two(t *testing.T) {
|
|||
}
|
||||
}`)
|
||||
|
||||
json.Unmarshal(overlayRaw, &overlay)
|
||||
err = json.Unmarshal(overlayRaw, &overlay)
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = meetConditions(resource, overlay)
|
||||
_, err = meetConditions(log.Log, resource, overlay)
|
||||
assert.Assert(t, reflect.DeepEqual(err, overlayError{}))
|
||||
|
||||
overlayRaw = []byte(`{
|
||||
|
@ -499,9 +523,10 @@ func TestMeetConditions_anchorsOnPeer_two(t *testing.T) {
|
|||
}
|
||||
}`)
|
||||
|
||||
json.Unmarshal(overlayRaw, &overlay)
|
||||
err = json.Unmarshal(overlayRaw, &overlay)
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = meetConditions(resource, overlay)
|
||||
_, err = meetConditions(log.Log, resource, overlay)
|
||||
assert.Assert(t, reflect.DeepEqual(err, overlayError{}))
|
||||
}
|
||||
|
||||
|
@ -532,10 +557,13 @@ func TestMeetConditions_anchorsOnPeer_multiple(t *testing.T) {
|
|||
|
||||
var resource, overlay interface{}
|
||||
|
||||
json.Unmarshal(resourceRawAnchorOnPeers, &resource)
|
||||
json.Unmarshal(overlayRaw, &overlay)
|
||||
err := json.Unmarshal(resourceRawAnchorOnPeers, &resource)
|
||||
assert.NilError(t, err)
|
||||
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{}))
|
||||
|
||||
overlayRaw = []byte(`{
|
||||
|
@ -562,9 +590,10 @@ func TestMeetConditions_anchorsOnPeer_multiple(t *testing.T) {
|
|||
}
|
||||
}`)
|
||||
|
||||
json.Unmarshal(overlayRaw, &overlay)
|
||||
err = json.Unmarshal(overlayRaw, &overlay)
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = meetConditions(resource, overlay)
|
||||
_, err = meetConditions(log.Log, resource, overlay)
|
||||
assert.Assert(t, reflect.DeepEqual(err, overlayError{}))
|
||||
|
||||
overlayRaw = []byte(`{
|
||||
|
@ -591,9 +620,10 @@ func TestMeetConditions_anchorsOnPeer_multiple(t *testing.T) {
|
|||
}
|
||||
}`)
|
||||
|
||||
json.Unmarshal(overlayRaw, &overlay)
|
||||
err = json.Unmarshal(overlayRaw, &overlay)
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = meetConditions(resource, overlay)
|
||||
_, err = meetConditions(log.Log, resource, overlay)
|
||||
assert.Error(t, err, "[overlayError:0] Failed validating value ENV_VALUE with overlay ENV_VALUE1")
|
||||
}
|
||||
|
||||
|
@ -649,10 +679,13 @@ func TestMeetConditions_AtleastOneExist(t *testing.T) {
|
|||
|
||||
var resource, overlay interface{}
|
||||
|
||||
json.Unmarshal(resourceRaw, &resource)
|
||||
json.Unmarshal(overlayRaw, &overlay)
|
||||
err := json.Unmarshal(resourceRaw, &resource)
|
||||
assert.NilError(t, err)
|
||||
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, len(path) == 0)
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
jsonpatch "github.com/evanphx/json-patch"
|
||||
"github.com/nirmata/kyverno/pkg/engine/utils"
|
||||
"gotest.tools/assert"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
)
|
||||
|
||||
func compareJSONAsMap(t *testing.T, expected, actual []byte) {
|
||||
|
@ -63,10 +64,12 @@ func TestProcessOverlayPatches_NestedListWithAnchor(t *testing.T) {
|
|||
|
||||
var resource, overlay interface{}
|
||||
|
||||
json.Unmarshal(resourceRaw, &resource)
|
||||
json.Unmarshal(overlayRaw, &overlay)
|
||||
err := json.Unmarshal(resourceRaw, &resource)
|
||||
assert.NilError(t, err)
|
||||
err = json.Unmarshal(overlayRaw, &overlay)
|
||||
assert.NilError(t, err)
|
||||
|
||||
patches, overlayerr := processOverlayPatches(resource, overlay)
|
||||
patches, overlayerr := processOverlayPatches(log.Log, resource, overlay)
|
||||
assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{}))
|
||||
assert.Assert(t, patches != nil)
|
||||
|
||||
|
@ -163,10 +166,12 @@ func TestProcessOverlayPatches_InsertIntoArray(t *testing.T) {
|
|||
|
||||
var resource, overlay interface{}
|
||||
|
||||
json.Unmarshal(resourceRaw, &resource)
|
||||
json.Unmarshal(overlayRaw, &overlay)
|
||||
err := json.Unmarshal(resourceRaw, &resource)
|
||||
assert.NilError(t, err)
|
||||
err = json.Unmarshal(overlayRaw, &overlay)
|
||||
assert.NilError(t, err)
|
||||
|
||||
patches, overlayerr := processOverlayPatches(resource, overlay)
|
||||
patches, overlayerr := processOverlayPatches(log.Log, resource, overlay)
|
||||
assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{}))
|
||||
assert.Assert(t, patches != nil)
|
||||
|
||||
|
@ -284,10 +289,12 @@ func TestProcessOverlayPatches_TestInsertToArray(t *testing.T) {
|
|||
|
||||
var resource, overlay interface{}
|
||||
|
||||
json.Unmarshal(resourceRaw, &resource)
|
||||
json.Unmarshal(overlayRaw, &overlay)
|
||||
err := json.Unmarshal(resourceRaw, &resource)
|
||||
assert.NilError(t, err)
|
||||
err = json.Unmarshal(overlayRaw, &overlay)
|
||||
assert.NilError(t, err)
|
||||
|
||||
patches, overlayerr := processOverlayPatches(resource, overlay)
|
||||
patches, overlayerr := processOverlayPatches(log.Log, resource, overlay)
|
||||
assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{}))
|
||||
assert.Assert(t, patches != nil)
|
||||
|
||||
|
@ -367,10 +374,12 @@ func TestProcessOverlayPatches_ImagePullPolicy(t *testing.T) {
|
|||
|
||||
var resource, overlay interface{}
|
||||
|
||||
json.Unmarshal(resourceRaw, &resource)
|
||||
json.Unmarshal(overlayRaw, &overlay)
|
||||
err := json.Unmarshal(resourceRaw, &resource)
|
||||
assert.NilError(t, err)
|
||||
err = json.Unmarshal(overlayRaw, &overlay)
|
||||
assert.NilError(t, err)
|
||||
|
||||
patches, overlayerr := processOverlayPatches(resource, overlay)
|
||||
patches, overlayerr := processOverlayPatches(log.Log, resource, overlay)
|
||||
assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{}))
|
||||
assert.Assert(t, len(patches) != 0)
|
||||
|
||||
|
@ -456,9 +465,10 @@ func TestProcessOverlayPatches_ImagePullPolicy(t *testing.T) {
|
|||
}
|
||||
}`)
|
||||
|
||||
json.Unmarshal(overlayRaw, &overlay)
|
||||
err = json.Unmarshal(overlayRaw, &overlay)
|
||||
assert.NilError(t, err)
|
||||
|
||||
patches, err = processOverlayPatches(resource, overlay)
|
||||
patches, err = processOverlayPatches(log.Log, resource, overlay)
|
||||
assert.Assert(t, reflect.DeepEqual(err, overlayError{}))
|
||||
assert.Assert(t, len(patches) != 0)
|
||||
|
||||
|
@ -492,9 +502,10 @@ func TestProcessOverlayPatches_ImagePullPolicy(t *testing.T) {
|
|||
}
|
||||
}`)
|
||||
|
||||
json.Unmarshal(overlayRaw, &overlay)
|
||||
err = json.Unmarshal(overlayRaw, &overlay)
|
||||
assert.NilError(t, err)
|
||||
|
||||
patches, err = processOverlayPatches(resource, overlay)
|
||||
patches, err = processOverlayPatches(log.Log, 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.Assert(t, len(patches) == 0)
|
||||
}
|
||||
|
@ -520,10 +531,12 @@ func TestProcessOverlayPatches_AddingAnchor(t *testing.T) {
|
|||
|
||||
var resource, overlay interface{}
|
||||
|
||||
json.Unmarshal(resourceRaw, &resource)
|
||||
json.Unmarshal(overlayRaw, &overlay)
|
||||
err := json.Unmarshal(resourceRaw, &resource)
|
||||
assert.NilError(t, err)
|
||||
err = json.Unmarshal(overlayRaw, &overlay)
|
||||
assert.NilError(t, err)
|
||||
|
||||
patches, overlayerr := processOverlayPatches(resource, overlay)
|
||||
patches, overlayerr := processOverlayPatches(log.Log, resource, overlay)
|
||||
assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{}))
|
||||
assert.Assert(t, len(patches) != 0)
|
||||
|
||||
|
@ -605,10 +618,12 @@ func TestProcessOverlayPatches_AddingAnchorInsideListElement(t *testing.T) {
|
|||
|
||||
var resource, overlay interface{}
|
||||
|
||||
json.Unmarshal(resourceRaw, &resource)
|
||||
json.Unmarshal(overlayRaw, &overlay)
|
||||
err := json.Unmarshal(resourceRaw, &resource)
|
||||
assert.NilError(t, err)
|
||||
err = json.Unmarshal(overlayRaw, &overlay)
|
||||
assert.NilError(t, err)
|
||||
|
||||
patches, overlayerr := processOverlayPatches(resource, overlay)
|
||||
patches, overlayerr := processOverlayPatches(log.Log, resource, overlay)
|
||||
assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{}))
|
||||
assert.Assert(t, len(patches) != 0)
|
||||
|
||||
|
@ -684,9 +699,10 @@ func TestProcessOverlayPatches_AddingAnchorInsideListElement(t *testing.T) {
|
|||
}
|
||||
}`)
|
||||
|
||||
json.Unmarshal(overlayRaw, &overlay)
|
||||
err = json.Unmarshal(overlayRaw, &overlay)
|
||||
assert.NilError(t, err)
|
||||
|
||||
patches, err = processOverlayPatches(resource, overlay)
|
||||
patches, err = processOverlayPatches(log.Log, resource, overlay)
|
||||
assert.Assert(t, reflect.DeepEqual(err, overlayError{}))
|
||||
assert.Assert(t, len(patches) != 0)
|
||||
|
||||
|
@ -747,10 +763,12 @@ func TestProcessOverlayPatches_anchorOnPeer(t *testing.T) {
|
|||
|
||||
var resource, overlay interface{}
|
||||
|
||||
json.Unmarshal(resourceRaw, &resource)
|
||||
json.Unmarshal(overlayRaw, &overlay)
|
||||
err := json.Unmarshal(resourceRaw, &resource)
|
||||
assert.NilError(t, err)
|
||||
err = json.Unmarshal(overlayRaw, &overlay)
|
||||
assert.NilError(t, err)
|
||||
|
||||
patches, overlayerr := processOverlayPatches(resource, overlay)
|
||||
patches, overlayerr := processOverlayPatches(log.Log, resource, overlay)
|
||||
assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{}))
|
||||
assert.Assert(t, len(patches) != 0)
|
||||
|
||||
|
@ -805,9 +823,10 @@ func TestProcessOverlayPatches_anchorOnPeer(t *testing.T) {
|
|||
]
|
||||
}`)
|
||||
|
||||
json.Unmarshal(overlayRaw, &overlay)
|
||||
err = json.Unmarshal(overlayRaw, &overlay)
|
||||
assert.NilError(t, err)
|
||||
|
||||
patches, err = processOverlayPatches(resource, overlay)
|
||||
patches, err = processOverlayPatches(log.Log, 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.Assert(t, len(patches) == 0)
|
||||
}
|
||||
|
@ -886,10 +905,12 @@ func TestProcessOverlayPatches_insertWithCondition(t *testing.T) {
|
|||
|
||||
var resource, overlay interface{}
|
||||
|
||||
json.Unmarshal(resourceRaw, &resource)
|
||||
json.Unmarshal(overlayRaw, &overlay)
|
||||
err := json.Unmarshal(resourceRaw, &resource)
|
||||
assert.NilError(t, err)
|
||||
err = json.Unmarshal(overlayRaw, &overlay)
|
||||
assert.NilError(t, err)
|
||||
|
||||
patches, overlayerr := processOverlayPatches(resource, overlay)
|
||||
patches, overlayerr := processOverlayPatches(log.Log, resource, overlay)
|
||||
assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{}))
|
||||
assert.Assert(t, len(patches) != 0)
|
||||
|
||||
|
@ -997,10 +1018,12 @@ func TestProcessOverlayPatches_InsertIfNotPresentWithConditions(t *testing.T) {
|
|||
|
||||
var resource, overlay interface{}
|
||||
|
||||
json.Unmarshal(resourceRaw, &resource)
|
||||
json.Unmarshal(overlayRaw, &overlay)
|
||||
err := json.Unmarshal(resourceRaw, &resource)
|
||||
assert.NilError(t, err)
|
||||
err = json.Unmarshal(overlayRaw, &overlay)
|
||||
assert.NilError(t, err)
|
||||
|
||||
patches, overlayerr := processOverlayPatches(resource, overlay)
|
||||
patches, overlayerr := processOverlayPatches(log.Log, resource, overlay)
|
||||
assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{}))
|
||||
assert.Assert(t, len(patches) != 0)
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/go-logr/logr"
|
||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||
"github.com/nirmata/kyverno/pkg/engine/response"
|
||||
"github.com/nirmata/kyverno/pkg/engine/utils"
|
||||
|
@ -20,21 +20,22 @@ func applyPatch(resource []byte, patchRaw []byte) ([]byte, error) {
|
|||
}
|
||||
|
||||
//ProcessPatches applies the patches on the resource and returns the patched resource
|
||||
func ProcessPatches(rule kyverno.Rule, resource unstructured.Unstructured) (resp response.RuleResponse, patchedResource unstructured.Unstructured) {
|
||||
func ProcessPatches(log logr.Logger, rule kyverno.Rule, resource unstructured.Unstructured) (resp response.RuleResponse, patchedResource unstructured.Unstructured) {
|
||||
logger := log.WithValues("rule", rule.Name)
|
||||
startTime := time.Now()
|
||||
glog.V(4).Infof("started JSON patch rule %q (%v)", rule.Name, startTime)
|
||||
logger.V(4).Info("started JSON patch", "startTime", startTime)
|
||||
resp.Name = rule.Name
|
||||
resp.Type = utils.Mutation.String()
|
||||
defer func() {
|
||||
resp.RuleStats.ProcessingTime = time.Since(startTime)
|
||||
glog.V(4).Infof("finished JSON patch rule %q (%v)", resp.Name, resp.RuleStats.ProcessingTime)
|
||||
logger.V(4).Info("finished JSON patch", "processingTime", resp.RuleStats.ProcessingTime)
|
||||
}()
|
||||
|
||||
// convert to RAW
|
||||
resourceRaw, err := resource.MarshalJSON()
|
||||
if err != nil {
|
||||
resp.Success = false
|
||||
glog.Infof("unable to marshall resource: %v", err)
|
||||
logger.Error(err, "failed to marshal resource")
|
||||
resp.Message = fmt.Sprintf("failed to process JSON patches: %v", err)
|
||||
return resp, resource
|
||||
}
|
||||
|
@ -45,14 +46,14 @@ func ProcessPatches(rule kyverno.Rule, resource unstructured.Unstructured) (resp
|
|||
// JSON patch
|
||||
patchRaw, err := json.Marshal(patch)
|
||||
if err != nil {
|
||||
glog.V(4).Infof("failed to marshall JSON patch %v: %v", patch, err)
|
||||
logger.Error(err, "failed to marshal JSON patch")
|
||||
errs = append(errs, err)
|
||||
continue
|
||||
}
|
||||
patchResource, err := applyPatch(resourceRaw, patchRaw)
|
||||
// TODO: continue on error if one of the patches fails, will add the failure event in such case
|
||||
if err != nil && patch.Operation == "remove" {
|
||||
glog.Info(err)
|
||||
log.Error(err, "failed to process JSON path or patch is a 'remove' operation")
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
|
@ -77,7 +78,7 @@ func ProcessPatches(rule kyverno.Rule, resource unstructured.Unstructured) (resp
|
|||
}
|
||||
err = patchedResource.UnmarshalJSON(resourceRaw)
|
||||
if err != nil {
|
||||
glog.Infof("failed to unmarshall resource to undstructured: %v", err)
|
||||
logger.Error(err, "failed to unmmarshal resource")
|
||||
resp.Success = false
|
||||
resp.Message = fmt.Sprintf("failed to process JSON patches: %v", err)
|
||||
return resp, resource
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
|
||||
"gotest.tools/assert"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
|
||||
types "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||
"github.com/nirmata/kyverno/pkg/engine/utils"
|
||||
|
@ -41,7 +42,7 @@ func TestProcessPatches_EmptyPatches(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
rr, _ := ProcessPatches(emptyRule, *resourceUnstructured)
|
||||
rr, _ := ProcessPatches(log.Log, emptyRule, *resourceUnstructured)
|
||||
assert.Check(t, rr.Success)
|
||||
assert.Assert(t, len(rr.Patches) == 0)
|
||||
}
|
||||
|
@ -70,14 +71,14 @@ func makeRuleWithPatches(patches []types.Patch) types.Rule {
|
|||
|
||||
func TestProcessPatches_EmptyDocument(t *testing.T) {
|
||||
rule := makeRuleWithPatch(makeAddIsMutatedLabelPatch())
|
||||
rr, _ := ProcessPatches(rule, unstructured.Unstructured{})
|
||||
rr, _ := ProcessPatches(log.Log, rule, unstructured.Unstructured{})
|
||||
assert.Assert(t, !rr.Success)
|
||||
assert.Assert(t, len(rr.Patches) == 0)
|
||||
}
|
||||
|
||||
func TestProcessPatches_AllEmpty(t *testing.T) {
|
||||
emptyRule := types.Rule{}
|
||||
rr, _ := ProcessPatches(emptyRule, unstructured.Unstructured{})
|
||||
rr, _ := ProcessPatches(log.Log, emptyRule, unstructured.Unstructured{})
|
||||
assert.Check(t, !rr.Success)
|
||||
assert.Assert(t, len(rr.Patches) == 0)
|
||||
}
|
||||
|
@ -90,7 +91,7 @@ func TestProcessPatches_AddPathDoesntExist(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
rr, _ := ProcessPatches(rule, *resourceUnstructured)
|
||||
rr, _ := ProcessPatches(log.Log, rule, *resourceUnstructured)
|
||||
assert.Check(t, !rr.Success)
|
||||
assert.Assert(t, len(rr.Patches) == 0)
|
||||
}
|
||||
|
@ -102,7 +103,7 @@ func TestProcessPatches_RemovePathDoesntExist(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
rr, _ := ProcessPatches(rule, *resourceUnstructured)
|
||||
rr, _ := ProcessPatches(log.Log, rule, *resourceUnstructured)
|
||||
assert.Check(t, rr.Success)
|
||||
assert.Assert(t, len(rr.Patches) == 0)
|
||||
}
|
||||
|
@ -115,7 +116,7 @@ func TestProcessPatches_AddAndRemovePathsDontExist_EmptyResult(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
rr, _ := ProcessPatches(rule, *resourceUnstructured)
|
||||
rr, _ := ProcessPatches(log.Log, rule, *resourceUnstructured)
|
||||
assert.Check(t, !rr.Success)
|
||||
assert.Assert(t, len(rr.Patches) == 0)
|
||||
}
|
||||
|
@ -129,7 +130,7 @@ func TestProcessPatches_AddAndRemovePathsDontExist_ContinueOnError_NotEmptyResul
|
|||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
rr, _ := ProcessPatches(rule, *resourceUnstructured)
|
||||
rr, _ := ProcessPatches(log.Log, rule, *resourceUnstructured)
|
||||
assert.Check(t, rr.Success)
|
||||
assert.Assert(t, len(rr.Patches) != 0)
|
||||
assertEqStringAndData(t, `{"path":"/metadata/labels/label3","op":"add","value":"label3Value"}`, rr.Patches[0])
|
||||
|
@ -142,7 +143,7 @@ func TestProcessPatches_RemovePathDoesntExist_EmptyResult(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
rr, _ := ProcessPatches(rule, *resourceUnstructured)
|
||||
rr, _ := ProcessPatches(log.Log, rule, *resourceUnstructured)
|
||||
assert.Check(t, rr.Success)
|
||||
assert.Assert(t, len(rr.Patches) == 0)
|
||||
}
|
||||
|
@ -155,7 +156,7 @@ func TestProcessPatches_RemovePathDoesntExist_NotEmptyResult(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
rr, _ := ProcessPatches(rule, *resourceUnstructured)
|
||||
rr, _ := ProcessPatches(log.Log, rule, *resourceUnstructured)
|
||||
assert.Check(t, rr.Success)
|
||||
assert.Assert(t, len(rr.Patches) == 1)
|
||||
assertEqStringAndData(t, `{"path":"/metadata/labels/label2","op":"add","value":"label2Value"}`, rr.Patches[0])
|
||||
|
|
|
@ -5,12 +5,13 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/go-logr/logr"
|
||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||
"github.com/nirmata/kyverno/pkg/engine/mutate"
|
||||
"github.com/nirmata/kyverno/pkg/engine/response"
|
||||
"github.com/nirmata/kyverno/pkg/engine/variables"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -28,26 +29,25 @@ func Mutate(policyContext PolicyContext) (resp response.EngineResponse) {
|
|||
policy := policyContext.Policy
|
||||
resource := policyContext.NewResource
|
||||
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)
|
||||
glog.V(4).Infof("started applying mutation rules of policy %q (%v)", policy.Name, startTime)
|
||||
defer endMutateResultResponse(&resp, startTime)
|
||||
defer endMutateResultResponse(logger, &resp, startTime)
|
||||
|
||||
patchedResource := policyContext.NewResource
|
||||
for _, rule := range policy.Spec.Rules {
|
||||
var ruleResponse response.RuleResponse
|
||||
logger := logger.WithValues("rule", rule.Name)
|
||||
//TODO: to be checked before calling the resources as well
|
||||
if !rule.HasMutate() && !strings.Contains(PodControllers, resource.GetKind()) {
|
||||
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
|
||||
//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
|
||||
if err := MatchesResourceDescription(resource, rule, policyContext.AdmissionInfo); err != nil {
|
||||
glog.V(4).Infof("resource %s/%s does not satisfy the resource description for the rule:\n%s", resource.GetNamespace(), resource.GetName(), err.Error())
|
||||
logger.V(4).Info("resource fails the match description")
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -55,8 +55,8 @@ func Mutate(policyContext PolicyContext) (resp response.EngineResponse) {
|
|||
copyConditions := copyConditions(rule.Conditions)
|
||||
// evaluate pre-conditions
|
||||
// - handle variable subsitutions
|
||||
if !variables.EvaluateConditions(ctx, copyConditions) {
|
||||
glog.V(4).Infof("resource %s/%s does not satisfy the conditions for the rule ", resource.GetNamespace(), resource.GetName())
|
||||
if !variables.EvaluateConditions(logger, ctx, copyConditions) {
|
||||
logger.V(4).Info("resource fails the preconditions")
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -66,7 +66,7 @@ func Mutate(policyContext PolicyContext) (resp response.EngineResponse) {
|
|||
overlay := mutation.Overlay
|
||||
// subsiitue the variables
|
||||
var err error
|
||||
if overlay, err = variables.SubstituteVars(ctx, overlay); err != nil {
|
||||
if overlay, err = variables.SubstituteVars(logger, ctx, overlay); err != nil {
|
||||
// variable subsitution failed
|
||||
ruleResponse.Success = false
|
||||
ruleResponse.Message = err.Error()
|
||||
|
@ -74,15 +74,13 @@ func Mutate(policyContext PolicyContext) (resp response.EngineResponse) {
|
|||
continue
|
||||
}
|
||||
|
||||
ruleResponse, patchedResource = mutate.ProcessOverlay(rule.Name, overlay, patchedResource)
|
||||
ruleResponse, patchedResource = mutate.ProcessOverlay(logger, rule.Name, overlay, patchedResource)
|
||||
if ruleResponse.Success {
|
||||
// - overlay pattern does not match the resource conditions
|
||||
if ruleResponse.Patches == nil {
|
||||
glog.V(4).Infof(ruleResponse.Message)
|
||||
continue
|
||||
}
|
||||
|
||||
glog.V(4).Infof("Mutate overlay in rule '%s' successfully applied on %s/%s/%s", rule.Name, resource.GetKind(), resource.GetNamespace(), resource.GetName())
|
||||
logger.V(4).Info("overlay applied succesfully")
|
||||
}
|
||||
|
||||
resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, ruleResponse)
|
||||
|
@ -92,8 +90,8 @@ func Mutate(policyContext PolicyContext) (resp response.EngineResponse) {
|
|||
// Process Patches
|
||||
if rule.Mutation.Patches != nil {
|
||||
var ruleResponse response.RuleResponse
|
||||
ruleResponse, patchedResource = mutate.ProcessPatches(rule, patchedResource)
|
||||
glog.Infof("Mutate patches in rule '%s' successfully applied on %s/%s/%s", rule.Name, resource.GetKind(), resource.GetNamespace(), resource.GetName())
|
||||
ruleResponse, patchedResource = mutate.ProcessPatches(logger, rule, patchedResource)
|
||||
logger.V(4).Info("patches applied successfully")
|
||||
resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, ruleResponse)
|
||||
incrementAppliedRuleCount(&resp)
|
||||
}
|
||||
|
@ -106,14 +104,14 @@ func Mutate(policyContext PolicyContext) (resp response.EngineResponse) {
|
|||
|
||||
if strings.Contains(PodControllers, resource.GetKind()) {
|
||||
var ruleResponse response.RuleResponse
|
||||
ruleResponse, patchedResource = mutate.ProcessOverlay(rule.Name, podTemplateRule, patchedResource)
|
||||
ruleResponse, patchedResource = mutate.ProcessOverlay(logger, rule.Name, podTemplateRule, patchedResource)
|
||||
if !ruleResponse.Success {
|
||||
glog.Errorf("Failed to insert annotation to podTemplate of %s/%s/%s: %s", resource.GetKind(), resource.GetNamespace(), resource.GetName(), ruleResponse.Message)
|
||||
logger.Info("failed to insert annotation for podTemplate", "error", ruleResponse.Message)
|
||||
continue
|
||||
}
|
||||
|
||||
if ruleResponse.Success && ruleResponse.Patches != nil {
|
||||
glog.V(2).Infof("Inserted annotation to podTemplate of %s/%s/%s: %s", resource.GetKind(), resource.GetNamespace(), resource.GetName(), ruleResponse.Message)
|
||||
logger.V(2).Info("inserted annotation for podTemplate")
|
||||
resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, ruleResponse)
|
||||
}
|
||||
}
|
||||
|
@ -137,10 +135,9 @@ func startMutateResultResponse(resp *response.EngineResponse, policy kyverno.Clu
|
|||
// TODO(shuting): set response with mutationFailureAction
|
||||
}
|
||||
|
||||
func endMutateResultResponse(resp *response.EngineResponse, startTime time.Time) {
|
||||
func endMutateResultResponse(logger logr.Logger, resp *response.EngineResponse, startTime time.Time) {
|
||||
resp.PolicyResponse.ProcessingTime = time.Since(startTime)
|
||||
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)
|
||||
logger.V(4).Info("finshed processing", "processingTime", resp.PolicyResponse.ProcessingTime, "mutationRulesApplied", resp.PolicyResponse.RulesAppliedCount)
|
||||
}
|
||||
|
||||
// podTemplateRule mutate pod template with annotation
|
||||
|
|
|
@ -67,11 +67,17 @@ func Test_VariableSubstitutionOverlay(t *testing.T) {
|
|||
expectedPatch := []byte(`{ "op": "add", "path": "/metadata/labels", "value":{"appname":"check-root-user"} }`)
|
||||
|
||||
var policy kyverno.ClusterPolicy
|
||||
json.Unmarshal(rawPolicy, &policy)
|
||||
err := json.Unmarshal(rawPolicy, &policy)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
ctx := context.NewContext()
|
||||
ctx.AddResource(rawResource)
|
||||
err = ctx.AddResource(rawResource)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
value, err := ctx.Query("request.object.metadata.name")
|
||||
t.Log(value)
|
||||
if err != nil {
|
||||
|
@ -139,12 +145,14 @@ func Test_variableSubstitutionPathNotExist(t *testing.T) {
|
|||
}`)
|
||||
|
||||
var policy kyverno.ClusterPolicy
|
||||
json.Unmarshal(policyraw, &policy)
|
||||
err := json.Unmarshal(policyraw, &policy)
|
||||
assert.NilError(t, err)
|
||||
resourceUnstructured, err := utils.ConvertToUnstructured(resourceRaw)
|
||||
assert.NilError(t, err)
|
||||
|
||||
ctx := context.NewContext()
|
||||
ctx.AddResource(resourceRaw)
|
||||
err = ctx.AddResource(resourceRaw)
|
||||
assert.NilError(t, err)
|
||||
|
||||
policyContext := PolicyContext{
|
||||
Policy: policy,
|
||||
|
|
|
@ -9,8 +9,7 @@ import (
|
|||
"github.com/nirmata/kyverno/pkg/utils"
|
||||
authenticationv1 "k8s.io/api/authentication/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
|
||||
"github.com/minio/minio/pkg/wildcard"
|
||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||
|
@ -53,7 +52,7 @@ func checkNameSpace(namespaces []string, resourceNameSpace string) bool {
|
|||
func checkSelector(labelSelector *metav1.LabelSelector, resourceLabels map[string]string) (bool, error) {
|
||||
selector, err := metav1.LabelSelectorAsSelector(labelSelector)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
log.Log.Error(err, "failed to build label selector")
|
||||
return false, err
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
package validate
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/go-logr/logr"
|
||||
"github.com/minio/minio/pkg/wildcard"
|
||||
"github.com/nirmata/kyverno/pkg/engine/operator"
|
||||
apiresource "k8s.io/apimachinery/pkg/api/resource"
|
||||
|
@ -21,52 +22,52 @@ const (
|
|||
)
|
||||
|
||||
// ValidateValueWithPattern validates value with operators and wildcards
|
||||
func ValidateValueWithPattern(value, pattern interface{}) bool {
|
||||
func ValidateValueWithPattern(log logr.Logger, value, pattern interface{}) bool {
|
||||
switch typedPattern := pattern.(type) {
|
||||
case bool:
|
||||
typedValue, ok := value.(bool)
|
||||
if !ok {
|
||||
glog.V(4).Infof("Expected bool, found %T", value)
|
||||
log.V(4).Info("Expected type bool", "type", fmt.Sprintf("%T", value), "value", value)
|
||||
return false
|
||||
}
|
||||
return typedPattern == typedValue
|
||||
case int:
|
||||
return validateValueWithIntPattern(value, int64(typedPattern))
|
||||
return validateValueWithIntPattern(log, value, int64(typedPattern))
|
||||
case int64:
|
||||
return validateValueWithIntPattern(value, typedPattern)
|
||||
return validateValueWithIntPattern(log, value, typedPattern)
|
||||
case float64:
|
||||
return validateValueWithFloatPattern(value, typedPattern)
|
||||
return validateValueWithFloatPattern(log, value, typedPattern)
|
||||
case string:
|
||||
return validateValueWithStringPatterns(value, typedPattern)
|
||||
return validateValueWithStringPatterns(log, value, typedPattern)
|
||||
case nil:
|
||||
return validateValueWithNilPattern(value)
|
||||
return validateValueWithNilPattern(log, value)
|
||||
case map[string]interface{}:
|
||||
// TODO: check if this is ever called?
|
||||
return validateValueWithMapPattern(value, typedPattern)
|
||||
return validateValueWithMapPattern(log, value, typedPattern)
|
||||
case []interface{}:
|
||||
// TODO: check if this is ever called?
|
||||
glog.Warning("Arrays as patterns are not supported")
|
||||
log.Info("arrays as patterns is not supported")
|
||||
return false
|
||||
default:
|
||||
glog.Warningf("Unknown type as pattern: %v", typedPattern)
|
||||
log.Info("Unkown type", "type", fmt.Sprintf("%T", typedPattern), "value", typedPattern)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func validateValueWithMapPattern(value interface{}, typedPattern map[string]interface{}) bool {
|
||||
func validateValueWithMapPattern(log logr.Logger, value interface{}, typedPattern map[string]interface{}) bool {
|
||||
// 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
|
||||
//TODO: check if adding
|
||||
_, ok := value.(map[string]interface{})
|
||||
if !ok {
|
||||
glog.Warningf("Expected map[string]interface{}, found %T\n", value)
|
||||
log.Info("Expected type map[string]interface{}", "type", fmt.Sprintf("%T", value), "value", value)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Handler for int values during validation process
|
||||
func validateValueWithIntPattern(value interface{}, pattern int64) bool {
|
||||
func validateValueWithIntPattern(log logr.Logger, value interface{}, pattern int64) bool {
|
||||
switch typedValue := value.(type) {
|
||||
case int:
|
||||
return int64(typedValue) == pattern
|
||||
|
@ -78,38 +79,38 @@ func validateValueWithIntPattern(value interface{}, pattern int64) bool {
|
|||
return int64(typedValue) == pattern
|
||||
}
|
||||
|
||||
glog.Warningf("Expected int, found float: %f\n", typedValue)
|
||||
log.Info("Expected type int", "type", fmt.Sprintf("%T", typedValue), "value", typedValue)
|
||||
return false
|
||||
case string:
|
||||
// extract int64 from string
|
||||
int64Num, err := strconv.ParseInt(typedValue, 10, 64)
|
||||
if err != nil {
|
||||
glog.Warningf("Failed to parse int64 from string: %v", err)
|
||||
log.Error(err, "Failed to parse int64 from string")
|
||||
return false
|
||||
}
|
||||
return int64Num == pattern
|
||||
default:
|
||||
glog.Warningf("Expected int, found: %T\n", value)
|
||||
log.Info("Expected type int", "type", fmt.Sprintf("%T", value), "value", value)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Handler for float values during validation process
|
||||
func validateValueWithFloatPattern(value interface{}, pattern float64) bool {
|
||||
func validateValueWithFloatPattern(log logr.Logger, value interface{}, pattern float64) bool {
|
||||
switch typedValue := value.(type) {
|
||||
case int:
|
||||
// check that float has no fraction
|
||||
if pattern == math.Trunc(pattern) {
|
||||
return int(pattern) == value
|
||||
}
|
||||
glog.Warningf("Expected float, found int: %d\n", typedValue)
|
||||
log.Info("Expected type float", "type", fmt.Sprintf("%T", typedValue), "value", typedValue)
|
||||
return false
|
||||
case int64:
|
||||
// check that float has no fraction
|
||||
if pattern == math.Trunc(pattern) {
|
||||
return int64(pattern) == value
|
||||
}
|
||||
glog.Warningf("Expected float, found int: %d\n", typedValue)
|
||||
log.Info("Expected type float", "type", fmt.Sprintf("%T", typedValue), "value", typedValue)
|
||||
return false
|
||||
case float64:
|
||||
return typedValue == pattern
|
||||
|
@ -117,18 +118,18 @@ func validateValueWithFloatPattern(value interface{}, pattern float64) bool {
|
|||
// extract float64 from string
|
||||
float64Num, err := strconv.ParseFloat(typedValue, 64)
|
||||
if err != nil {
|
||||
glog.Warningf("Failed to parse float64 from string: %v", err)
|
||||
log.Error(err, "Failed to parse float64 from string")
|
||||
return false
|
||||
}
|
||||
return float64Num == pattern
|
||||
default:
|
||||
glog.Warningf("Expected float, found: %T\n", value)
|
||||
log.Info("Expected type float", "type", fmt.Sprintf("%T", value), "value", value)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Handler for nil values during validation process
|
||||
func validateValueWithNilPattern(value interface{}) bool {
|
||||
func validateValueWithNilPattern(log logr.Logger, value interface{}) bool {
|
||||
switch typed := value.(type) {
|
||||
case float64:
|
||||
return typed == 0.0
|
||||
|
@ -143,20 +144,20 @@ func validateValueWithNilPattern(value interface{}) bool {
|
|||
case nil:
|
||||
return true
|
||||
case map[string]interface{}, []interface{}:
|
||||
glog.Warningf("Maps and arrays could not be checked with nil pattern")
|
||||
log.Info("Maps and arrays could not be checked with nil pattern")
|
||||
return false
|
||||
default:
|
||||
glog.Warningf("Unknown type as value when checking for nil pattern: %T\n", value)
|
||||
log.Info("Unknown type as value when checking for nil pattern", "type", fmt.Sprintf("%T", value), "value", value)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Handler for pattern values during validation process
|
||||
func validateValueWithStringPatterns(value interface{}, pattern string) bool {
|
||||
func validateValueWithStringPatterns(log logr.Logger, value interface{}, pattern string) bool {
|
||||
statements := strings.Split(pattern, "|")
|
||||
for _, statement := range statements {
|
||||
statement = strings.Trim(statement, " ")
|
||||
if validateValueWithStringPattern(value, statement) {
|
||||
if validateValueWithStringPattern(log, value, statement) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
@ -166,24 +167,24 @@ func validateValueWithStringPatterns(value interface{}, pattern string) bool {
|
|||
|
||||
// Handler for single pattern value during validation process
|
||||
// Detects if pattern has a number
|
||||
func validateValueWithStringPattern(value interface{}, pattern string) bool {
|
||||
func validateValueWithStringPattern(log logr.Logger, value interface{}, pattern string) bool {
|
||||
operator := operator.GetOperatorFromStringPattern(pattern)
|
||||
pattern = pattern[len(operator):]
|
||||
number, str := getNumberAndStringPartsFromPattern(pattern)
|
||||
|
||||
if "" == number {
|
||||
return validateString(value, str, operator)
|
||||
return validateString(log, value, str, operator)
|
||||
}
|
||||
|
||||
return validateNumberWithStr(value, pattern, operator)
|
||||
return validateNumberWithStr(log, value, pattern, operator)
|
||||
}
|
||||
|
||||
// Handler for string values
|
||||
func validateString(value interface{}, pattern string, operatorVariable operator.Operator) bool {
|
||||
func validateString(log logr.Logger, value interface{}, pattern string, operatorVariable operator.Operator) bool {
|
||||
if operator.NotEqual == operatorVariable || operator.Equal == operatorVariable {
|
||||
strValue, ok := value.(string)
|
||||
if !ok {
|
||||
glog.Warningf("Expected string, found %T\n", value)
|
||||
log.Info("Expected type string", "type", fmt.Sprintf("%T", value), "value", value)
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -195,17 +196,16 @@ func validateString(value interface{}, pattern string, operatorVariable operator
|
|||
|
||||
return wildcardResult
|
||||
}
|
||||
|
||||
glog.Warningf("Operators >, >=, <, <= are not applicable to strings")
|
||||
log.Info("Operators >, >=, <, <= are not applicable to strings")
|
||||
return false
|
||||
}
|
||||
|
||||
// validateNumberWithStr compares quantity if pattern type is quantity
|
||||
// or a wildcard match to pattern string
|
||||
func validateNumberWithStr(value interface{}, pattern string, operator operator.Operator) bool {
|
||||
func validateNumberWithStr(log logr.Logger, value interface{}, pattern string, operator operator.Operator) bool {
|
||||
typedValue, err := convertToString(value)
|
||||
if err != nil {
|
||||
glog.Warning(err)
|
||||
log.Error(err, "failed to convert to string")
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -214,7 +214,7 @@ func validateNumberWithStr(value interface{}, pattern string, operator operator.
|
|||
if err == nil {
|
||||
valueQuan, err := apiresource.ParseQuantity(typedValue)
|
||||
if err != nil {
|
||||
glog.Warningf("Invalid quantity in resource %s, err: %v\n", typedValue, err)
|
||||
log.Error(err, "invalid quantity in resource", "type", fmt.Sprintf("%T", typedValue), "value", typedValue)
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -223,7 +223,7 @@ func validateNumberWithStr(value interface{}, pattern string, operator operator.
|
|||
|
||||
// 2. wildcard match
|
||||
if !wildcard.Match(pattern, typedValue) {
|
||||
glog.Warningf("Value '%s' has not passed wildcard check: %s", typedValue, pattern)
|
||||
log.Info("value failed wildcard check", "type", fmt.Sprintf("%T", typedValue), "value", typedValue, "check", pattern)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
|
|
|
@ -6,13 +6,14 @@ import (
|
|||
|
||||
"github.com/nirmata/kyverno/pkg/engine/operator"
|
||||
"gotest.tools/assert"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
)
|
||||
|
||||
func TestValidateValueWithPattern_Bool(t *testing.T) {
|
||||
assert.Assert(t, ValidateValueWithPattern(true, true))
|
||||
assert.Assert(t, !ValidateValueWithPattern(true, false))
|
||||
assert.Assert(t, !ValidateValueWithPattern(false, true))
|
||||
assert.Assert(t, ValidateValueWithPattern(false, false))
|
||||
assert.Assert(t, ValidateValueWithPattern(log.Log, true, true))
|
||||
assert.Assert(t, !ValidateValueWithPattern(log.Log, true, false))
|
||||
assert.Assert(t, !ValidateValueWithPattern(log.Log, false, true))
|
||||
assert.Assert(t, ValidateValueWithPattern(log.Log, false, false))
|
||||
}
|
||||
|
||||
func TestValidateString_AsteriskTest(t *testing.T) {
|
||||
|
@ -20,8 +21,8 @@ func TestValidateString_AsteriskTest(t *testing.T) {
|
|||
value := "anything"
|
||||
empty := ""
|
||||
|
||||
assert.Assert(t, validateString(value, pattern, operator.Equal))
|
||||
assert.Assert(t, validateString(empty, pattern, operator.Equal))
|
||||
assert.Assert(t, validateString(log.Log, value, pattern, operator.Equal))
|
||||
assert.Assert(t, validateString(log.Log, empty, pattern, operator.Equal))
|
||||
}
|
||||
|
||||
func TestValidateString_LeftAsteriskTest(t *testing.T) {
|
||||
|
@ -29,32 +30,32 @@ func TestValidateString_LeftAsteriskTest(t *testing.T) {
|
|||
value := "leftright"
|
||||
right := "right"
|
||||
|
||||
assert.Assert(t, validateString(value, pattern, operator.Equal))
|
||||
assert.Assert(t, validateString(right, pattern, operator.Equal))
|
||||
assert.Assert(t, validateString(log.Log, value, pattern, operator.Equal))
|
||||
assert.Assert(t, validateString(log.Log, right, pattern, operator.Equal))
|
||||
|
||||
value = "leftmiddle"
|
||||
middle := "middle"
|
||||
|
||||
assert.Assert(t, !validateString(value, pattern, operator.Equal))
|
||||
assert.Assert(t, !validateString(middle, pattern, operator.Equal))
|
||||
assert.Assert(t, !validateString(log.Log, value, pattern, operator.Equal))
|
||||
assert.Assert(t, !validateString(log.Log, middle, pattern, operator.Equal))
|
||||
}
|
||||
|
||||
func TestValidateString_MiddleAsteriskTest(t *testing.T) {
|
||||
pattern := "ab*ba"
|
||||
value := "abbeba"
|
||||
assert.Assert(t, validateString(value, pattern, operator.Equal))
|
||||
assert.Assert(t, validateString(log.Log, value, pattern, operator.Equal))
|
||||
|
||||
value = "abbca"
|
||||
assert.Assert(t, !validateString(value, pattern, operator.Equal))
|
||||
assert.Assert(t, !validateString(log.Log, value, pattern, operator.Equal))
|
||||
}
|
||||
|
||||
func TestValidateString_QuestionMark(t *testing.T) {
|
||||
pattern := "ab?ba"
|
||||
value := "abbba"
|
||||
assert.Assert(t, validateString(value, pattern, operator.Equal))
|
||||
assert.Assert(t, validateString(log.Log, value, pattern, operator.Equal))
|
||||
|
||||
value = "abbbba"
|
||||
assert.Assert(t, !validateString(value, pattern, operator.Equal))
|
||||
assert.Assert(t, !validateString(log.Log, value, pattern, operator.Equal))
|
||||
}
|
||||
|
||||
func TestValidateValueWithPattern_BoolInJson(t *testing.T) {
|
||||
|
@ -76,7 +77,7 @@ func TestValidateValueWithPattern_BoolInJson(t *testing.T) {
|
|||
err = json.Unmarshal(rawValue, &value)
|
||||
assert.Assert(t, err)
|
||||
|
||||
assert.Assert(t, ValidateValueWithPattern(value["key"], pattern["key"]))
|
||||
assert.Assert(t, ValidateValueWithPattern(log.Log, value["key"], pattern["key"]))
|
||||
}
|
||||
|
||||
func TestValidateValueWithPattern_NullPatternStringValue(t *testing.T) {
|
||||
|
@ -98,7 +99,7 @@ func TestValidateValueWithPattern_NullPatternStringValue(t *testing.T) {
|
|||
err = json.Unmarshal(rawValue, &value)
|
||||
assert.Assert(t, err)
|
||||
|
||||
assert.Assert(t, !ValidateValueWithPattern(value["key"], pattern["key"]))
|
||||
assert.Assert(t, !ValidateValueWithPattern(log.Log, value["key"], pattern["key"]))
|
||||
}
|
||||
|
||||
func TestValidateValueWithPattern_NullPatternDefaultString(t *testing.T) {
|
||||
|
@ -120,7 +121,7 @@ func TestValidateValueWithPattern_NullPatternDefaultString(t *testing.T) {
|
|||
err = json.Unmarshal(rawValue, &value)
|
||||
assert.Assert(t, err)
|
||||
|
||||
assert.Assert(t, ValidateValueWithPattern(value["key"], pattern["key"]))
|
||||
assert.Assert(t, ValidateValueWithPattern(log.Log, value["key"], pattern["key"]))
|
||||
}
|
||||
|
||||
func TestValidateValueWithPattern_NullPatternDefaultFloat(t *testing.T) {
|
||||
|
@ -142,7 +143,7 @@ func TestValidateValueWithPattern_NullPatternDefaultFloat(t *testing.T) {
|
|||
err = json.Unmarshal(rawValue, &value)
|
||||
assert.Assert(t, err)
|
||||
|
||||
assert.Assert(t, ValidateValueWithPattern(value["key"], pattern["key"]))
|
||||
assert.Assert(t, ValidateValueWithPattern(log.Log, value["key"], pattern["key"]))
|
||||
}
|
||||
|
||||
func TestValidateValueWithPattern_NullPatternDefaultInt(t *testing.T) {
|
||||
|
@ -164,7 +165,7 @@ func TestValidateValueWithPattern_NullPatternDefaultInt(t *testing.T) {
|
|||
err = json.Unmarshal(rawValue, &value)
|
||||
assert.Assert(t, err)
|
||||
|
||||
assert.Assert(t, ValidateValueWithPattern(value["key"], pattern["key"]))
|
||||
assert.Assert(t, ValidateValueWithPattern(log.Log, value["key"], pattern["key"]))
|
||||
}
|
||||
|
||||
func TestValidateValueWithPattern_NullPatternDefaultBool(t *testing.T) {
|
||||
|
@ -186,77 +187,77 @@ func TestValidateValueWithPattern_NullPatternDefaultBool(t *testing.T) {
|
|||
err = json.Unmarshal(rawValue, &value)
|
||||
assert.Assert(t, err)
|
||||
|
||||
assert.Assert(t, ValidateValueWithPattern(value["key"], pattern["key"]))
|
||||
assert.Assert(t, ValidateValueWithPattern(log.Log, value["key"], pattern["key"]))
|
||||
}
|
||||
|
||||
func TestValidateValueWithPattern_StringsLogicalOr(t *testing.T) {
|
||||
pattern := "192.168.88.1 | 10.100.11.*"
|
||||
value := "10.100.11.54"
|
||||
assert.Assert(t, ValidateValueWithPattern(value, pattern))
|
||||
assert.Assert(t, ValidateValueWithPattern(log.Log, value, pattern))
|
||||
}
|
||||
|
||||
func TestValidateValueWithPattern_EqualTwoFloats(t *testing.T) {
|
||||
assert.Assert(t, ValidateValueWithPattern(7.0, 7.000))
|
||||
assert.Assert(t, ValidateValueWithPattern(log.Log, 7.0, 7.000))
|
||||
}
|
||||
|
||||
func TestValidateValueWithNilPattern_NullPatternStringValue(t *testing.T) {
|
||||
assert.Assert(t, !validateValueWithNilPattern("value"))
|
||||
assert.Assert(t, !validateValueWithNilPattern(log.Log, "value"))
|
||||
}
|
||||
|
||||
func TestValidateValueWithNilPattern_NullPatternDefaultString(t *testing.T) {
|
||||
assert.Assert(t, validateValueWithNilPattern(""))
|
||||
assert.Assert(t, validateValueWithNilPattern(log.Log, ""))
|
||||
}
|
||||
|
||||
func TestValidateValueWithNilPattern_NullPatternDefaultFloat(t *testing.T) {
|
||||
assert.Assert(t, validateValueWithNilPattern(0.0))
|
||||
assert.Assert(t, validateValueWithNilPattern(log.Log, 0.0))
|
||||
}
|
||||
|
||||
func TestValidateValueWithNilPattern_NullPatternFloat(t *testing.T) {
|
||||
assert.Assert(t, !validateValueWithNilPattern(0.1))
|
||||
assert.Assert(t, !validateValueWithNilPattern(log.Log, 0.1))
|
||||
}
|
||||
|
||||
func TestValidateValueWithNilPattern_NullPatternDefaultInt(t *testing.T) {
|
||||
assert.Assert(t, validateValueWithNilPattern(0))
|
||||
assert.Assert(t, validateValueWithNilPattern(log.Log, 0))
|
||||
}
|
||||
|
||||
func TestValidateValueWithNilPattern_NullPatternInt(t *testing.T) {
|
||||
assert.Assert(t, !validateValueWithNilPattern(1))
|
||||
assert.Assert(t, !validateValueWithNilPattern(log.Log, 1))
|
||||
}
|
||||
|
||||
func TestValidateValueWithNilPattern_NullPatternDefaultBool(t *testing.T) {
|
||||
assert.Assert(t, validateValueWithNilPattern(false))
|
||||
assert.Assert(t, validateValueWithNilPattern(log.Log, false))
|
||||
}
|
||||
|
||||
func TestValidateValueWithNilPattern_NullPatternTrueBool(t *testing.T) {
|
||||
assert.Assert(t, !validateValueWithNilPattern(true))
|
||||
assert.Assert(t, !validateValueWithNilPattern(log.Log, true))
|
||||
}
|
||||
|
||||
func TestValidateValueWithFloatPattern_FloatValue(t *testing.T) {
|
||||
assert.Assert(t, validateValueWithFloatPattern(7.9914, 7.9914))
|
||||
assert.Assert(t, validateValueWithFloatPattern(log.Log, 7.9914, 7.9914))
|
||||
}
|
||||
|
||||
func TestValidateValueWithFloatPattern_FloatValueNotPass(t *testing.T) {
|
||||
assert.Assert(t, !validateValueWithFloatPattern(7.9914, 7.99141))
|
||||
assert.Assert(t, !validateValueWithFloatPattern(log.Log, 7.9914, 7.99141))
|
||||
}
|
||||
|
||||
func TestValidateValueWithFloatPattern_FloatPatternWithoutFractionIntValue(t *testing.T) {
|
||||
assert.Assert(t, validateValueWithFloatPattern(7, 7.000000))
|
||||
assert.Assert(t, validateValueWithFloatPattern(log.Log, 7, 7.000000))
|
||||
}
|
||||
|
||||
func TestValidateValueWithFloatPattern_FloatPatternWithoutFraction(t *testing.T) {
|
||||
assert.Assert(t, validateValueWithFloatPattern(7.000000, 7.000000))
|
||||
assert.Assert(t, validateValueWithFloatPattern(log.Log, 7.000000, 7.000000))
|
||||
}
|
||||
|
||||
func TestValidateValueWithIntPattern_FloatValueWithoutFraction(t *testing.T) {
|
||||
assert.Assert(t, validateValueWithFloatPattern(7.000000, 7))
|
||||
assert.Assert(t, validateValueWithFloatPattern(log.Log, 7.000000, 7))
|
||||
}
|
||||
|
||||
func TestValidateValueWithIntPattern_FloatValueWitFraction(t *testing.T) {
|
||||
assert.Assert(t, !validateValueWithFloatPattern(7.000001, 7))
|
||||
assert.Assert(t, !validateValueWithFloatPattern(log.Log, 7.000001, 7))
|
||||
}
|
||||
|
||||
func TestValidateValueWithIntPattern_NotPass(t *testing.T) {
|
||||
assert.Assert(t, !validateValueWithFloatPattern(8, 7))
|
||||
assert.Assert(t, !validateValueWithFloatPattern(log.Log, 8, 7))
|
||||
}
|
||||
|
||||
func TestGetNumberAndStringPartsFromPattern_NumberAndString(t *testing.T) {
|
||||
|
@ -290,35 +291,35 @@ func TestGetNumberAndStringPartsFromPattern_Empty(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestValidateNumberWithStr_LessFloatAndInt(t *testing.T) {
|
||||
assert.Assert(t, validateNumberWithStr(7.00001, "7.000001", operator.More))
|
||||
assert.Assert(t, validateNumberWithStr(7.00001, "7", operator.NotEqual))
|
||||
assert.Assert(t, validateNumberWithStr(log.Log, 7.00001, "7.000001", operator.More))
|
||||
assert.Assert(t, validateNumberWithStr(log.Log, 7.00001, "7", operator.NotEqual))
|
||||
|
||||
assert.Assert(t, validateNumberWithStr(7.0000, "7", operator.Equal))
|
||||
assert.Assert(t, !validateNumberWithStr(6.000000001, "6", operator.Less))
|
||||
assert.Assert(t, validateNumberWithStr(log.Log, 7.0000, "7", operator.Equal))
|
||||
assert.Assert(t, !validateNumberWithStr(log.Log, 6.000000001, "6", operator.Less))
|
||||
}
|
||||
|
||||
func TestValidateQuantity_InvalidQuantity(t *testing.T) {
|
||||
assert.Assert(t, !validateNumberWithStr("1024Gi", "", operator.Equal))
|
||||
assert.Assert(t, !validateNumberWithStr("gii", "1024Gi", operator.Equal))
|
||||
assert.Assert(t, !validateNumberWithStr(log.Log, "1024Gi", "", operator.Equal))
|
||||
assert.Assert(t, !validateNumberWithStr(log.Log, "gii", "1024Gi", operator.Equal))
|
||||
}
|
||||
|
||||
func TestValidateQuantity_Equal(t *testing.T) {
|
||||
assert.Assert(t, validateNumberWithStr("1024Gi", "1024Gi", operator.Equal))
|
||||
assert.Assert(t, validateNumberWithStr("1024Mi", "1Gi", operator.Equal))
|
||||
assert.Assert(t, validateNumberWithStr("0.2", "200m", operator.Equal))
|
||||
assert.Assert(t, validateNumberWithStr("500", "500", operator.Equal))
|
||||
assert.Assert(t, !validateNumberWithStr("2048", "1024", operator.Equal))
|
||||
assert.Assert(t, validateNumberWithStr(1024, "1024", operator.Equal))
|
||||
assert.Assert(t, validateNumberWithStr(log.Log, "1024Gi", "1024Gi", operator.Equal))
|
||||
assert.Assert(t, validateNumberWithStr(log.Log, "1024Mi", "1Gi", operator.Equal))
|
||||
assert.Assert(t, validateNumberWithStr(log.Log, "0.2", "200m", operator.Equal))
|
||||
assert.Assert(t, validateNumberWithStr(log.Log, "500", "500", operator.Equal))
|
||||
assert.Assert(t, !validateNumberWithStr(log.Log, "2048", "1024", operator.Equal))
|
||||
assert.Assert(t, validateNumberWithStr(log.Log, 1024, "1024", operator.Equal))
|
||||
}
|
||||
|
||||
func TestValidateQuantity_Operation(t *testing.T) {
|
||||
assert.Assert(t, validateNumberWithStr("1Gi", "1000Mi", operator.More))
|
||||
assert.Assert(t, validateNumberWithStr("1G", "1Gi", operator.Less))
|
||||
assert.Assert(t, validateNumberWithStr("500m", "0.5", operator.MoreEqual))
|
||||
assert.Assert(t, validateNumberWithStr("1", "500m", operator.MoreEqual))
|
||||
assert.Assert(t, validateNumberWithStr("0.5", ".5", operator.LessEqual))
|
||||
assert.Assert(t, validateNumberWithStr("0.2", ".5", operator.LessEqual))
|
||||
assert.Assert(t, validateNumberWithStr("0.2", ".5", operator.NotEqual))
|
||||
assert.Assert(t, validateNumberWithStr(log.Log, "1Gi", "1000Mi", operator.More))
|
||||
assert.Assert(t, validateNumberWithStr(log.Log, "1G", "1Gi", operator.Less))
|
||||
assert.Assert(t, validateNumberWithStr(log.Log, "500m", "0.5", operator.MoreEqual))
|
||||
assert.Assert(t, validateNumberWithStr(log.Log, "1", "500m", operator.MoreEqual))
|
||||
assert.Assert(t, validateNumberWithStr(log.Log, "0.5", ".5", operator.LessEqual))
|
||||
assert.Assert(t, validateNumberWithStr(log.Log, "0.2", ".5", operator.LessEqual))
|
||||
assert.Assert(t, validateNumberWithStr(log.Log, "0.2", ".5", operator.NotEqual))
|
||||
}
|
||||
|
||||
func TestGetOperatorFromStringPattern_OneChar(t *testing.T) {
|
||||
|
|
|
@ -8,15 +8,15 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/go-logr/logr"
|
||||
"github.com/nirmata/kyverno/pkg/engine/anchor"
|
||||
"github.com/nirmata/kyverno/pkg/engine/operator"
|
||||
)
|
||||
|
||||
// ValidateResourceWithPattern is a start of element-by-element validation process
|
||||
// It assumes that validation is started from root, so "/" is passed
|
||||
func ValidateResourceWithPattern(resource, pattern interface{}) (string, error) {
|
||||
path, err := validateResourceElement(resource, pattern, pattern, "/")
|
||||
func ValidateResourceWithPattern(log logr.Logger, resource, pattern interface{}) (string, error) {
|
||||
path, err := validateResourceElement(log, resource, pattern, pattern, "/")
|
||||
if err != nil {
|
||||
return path, err
|
||||
}
|
||||
|
@ -27,44 +27,44 @@ func ValidateResourceWithPattern(resource, pattern interface{}) (string, error)
|
|||
// validateResourceElement detects the element type (map, array, nil, string, int, bool, float)
|
||||
// and calls corresponding handler
|
||||
// Pattern tree and resource tree can have different structure. In this case validation fails
|
||||
func validateResourceElement(resourceElement, patternElement, originPattern interface{}, path string) (string, error) {
|
||||
func validateResourceElement(log logr.Logger, resourceElement, patternElement, originPattern interface{}, path string) (string, error) {
|
||||
var err error
|
||||
switch typedPatternElement := patternElement.(type) {
|
||||
// map
|
||||
case map[string]interface{}:
|
||||
typedResourceElement, ok := resourceElement.(map[string]interface{})
|
||||
if !ok {
|
||||
glog.V(4).Infof("Pattern and resource have different structures. Path: %s. Expected %T, found %T", path, patternElement, resourceElement)
|
||||
log.V(4).Info("Pattern and resource have different structures.", "path", path, "expected", fmt.Sprintf("%T", patternElement), "current", fmt.Sprintf("%T", resourceElement))
|
||||
return path, fmt.Errorf("Pattern and resource have different structures. Path: %s. Expected %T, found %T", path, patternElement, resourceElement)
|
||||
}
|
||||
|
||||
return validateMap(typedResourceElement, typedPatternElement, originPattern, path)
|
||||
return validateMap(log, typedResourceElement, typedPatternElement, originPattern, path)
|
||||
// array
|
||||
case []interface{}:
|
||||
typedResourceElement, ok := resourceElement.([]interface{})
|
||||
if !ok {
|
||||
glog.V(4).Infof("Pattern and resource have different structures. Path: %s. Expected %T, found %T", path, patternElement, resourceElement)
|
||||
log.V(4).Info("Pattern and resource have different structures.", "path", path, "expected", fmt.Sprintf("%T", patternElement), "current", fmt.Sprintf("%T", resourceElement))
|
||||
return path, fmt.Errorf("Validation rule Failed at path %s, resource does not satisfy the expected overlay pattern", path)
|
||||
}
|
||||
|
||||
return validateArray(typedResourceElement, typedPatternElement, originPattern, path)
|
||||
return validateArray(log, typedResourceElement, typedPatternElement, originPattern, path)
|
||||
// elementary values
|
||||
case string, float64, int, int64, bool, nil:
|
||||
/*Analyze pattern */
|
||||
if checkedPattern := reflect.ValueOf(patternElement); checkedPattern.Kind() == reflect.String {
|
||||
if isStringIsReference(checkedPattern.String()) { //check for $ anchor
|
||||
patternElement, err = actualizePattern(originPattern, checkedPattern.String(), path)
|
||||
patternElement, err = actualizePattern(log, originPattern, checkedPattern.String(), path)
|
||||
if err != nil {
|
||||
return path, err
|
||||
}
|
||||
}
|
||||
}
|
||||
if !ValidateValueWithPattern(resourceElement, patternElement) {
|
||||
if !ValidateValueWithPattern(log, resourceElement, patternElement) {
|
||||
return path, fmt.Errorf("Validation rule failed at '%s' to validate value '%v' with pattern '%v'", path, resourceElement, patternElement)
|
||||
}
|
||||
|
||||
default:
|
||||
glog.V(4).Infof("Pattern contains unknown type %T. Path: %s", patternElement, path)
|
||||
log.V(4).Info("Pattern contains unknown type", "path", path, "current", fmt.Sprintf("%T", patternElement))
|
||||
return path, fmt.Errorf("Validation rule failed at '%s', pattern contains unknown type", path)
|
||||
}
|
||||
return "", nil
|
||||
|
@ -72,7 +72,7 @@ func validateResourceElement(resourceElement, patternElement, originPattern inte
|
|||
|
||||
// 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
|
||||
func validateMap(resourceMap, patternMap map[string]interface{}, origPattern interface{}, path string) (string, error) {
|
||||
func validateMap(log logr.Logger, resourceMap, patternMap map[string]interface{}, origPattern interface{}, path string) (string, error) {
|
||||
// check if there is anchor in pattern
|
||||
// Phase 1 : Evaluate all the anchors
|
||||
// Phase 2 : Evaluate non-anchors
|
||||
|
@ -91,7 +91,7 @@ func validateMap(resourceMap, patternMap map[string]interface{}, origPattern int
|
|||
if err != nil {
|
||||
// If Conditional anchor fails then we dont process the resources
|
||||
if anchor.IsConditionAnchor(key) {
|
||||
glog.V(4).Infof("condition anchor did not satisfy, wont process the resources: %s", err)
|
||||
log.Error(err, "condition anchor did not satisfy, wont process the resource")
|
||||
return "", nil
|
||||
}
|
||||
return handlerPath, err
|
||||
|
@ -109,7 +109,7 @@ func validateMap(resourceMap, patternMap map[string]interface{}, origPattern int
|
|||
return "", nil
|
||||
}
|
||||
|
||||
func validateArray(resourceArray, patternArray []interface{}, originPattern interface{}, path string) (string, error) {
|
||||
func validateArray(log logr.Logger, resourceArray, patternArray []interface{}, originPattern interface{}, path string) (string, error) {
|
||||
|
||||
if 0 == len(patternArray) {
|
||||
return path, fmt.Errorf("Pattern Array empty")
|
||||
|
@ -119,7 +119,7 @@ func validateArray(resourceArray, patternArray []interface{}, originPattern inte
|
|||
case map[string]interface{}:
|
||||
// This is special case, because maps in arrays can have anchors that must be
|
||||
// processed with the special way affecting the entire array
|
||||
path, err := validateArrayOfMaps(resourceArray, typedPatternElement, originPattern, path)
|
||||
path, err := validateArrayOfMaps(log, resourceArray, typedPatternElement, originPattern, path)
|
||||
if err != nil {
|
||||
return path, err
|
||||
}
|
||||
|
@ -127,7 +127,7 @@ func validateArray(resourceArray, patternArray []interface{}, originPattern inte
|
|||
// In all other cases - detect type and handle each array element with validateResourceElement
|
||||
for i, patternElement := range patternArray {
|
||||
currentPath := path + strconv.Itoa(i) + "/"
|
||||
path, err := validateResourceElement(resourceArray[i], patternElement, originPattern, currentPath)
|
||||
path, err := validateResourceElement(log, resourceArray[i], patternElement, originPattern, currentPath)
|
||||
if err != nil {
|
||||
return path, err
|
||||
}
|
||||
|
@ -137,7 +137,7 @@ func validateArray(resourceArray, patternArray []interface{}, originPattern inte
|
|||
return "", nil
|
||||
}
|
||||
|
||||
func actualizePattern(origPattern interface{}, referencePattern, absolutePath string) (interface{}, error) {
|
||||
func actualizePattern(log logr.Logger, origPattern interface{}, referencePattern, absolutePath string) (interface{}, error) {
|
||||
var foundValue interface{}
|
||||
|
||||
referencePattern = strings.Trim(referencePattern, "$()")
|
||||
|
@ -155,7 +155,7 @@ func actualizePattern(origPattern interface{}, referencePattern, absolutePath st
|
|||
// value :=
|
||||
actualPath := formAbsolutePath(referencePattern, absolutePath)
|
||||
|
||||
valFromReference, err := getValueFromReference(origPattern, actualPath)
|
||||
valFromReference, err := getValueFromReference(log, origPattern, actualPath)
|
||||
if 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
|
||||
func getValueFromReference(origPattern interface{}, reference string) (interface{}, error) {
|
||||
func getValueFromReference(log logr.Logger, origPattern interface{}, reference string) (interface{}, error) {
|
||||
originalPatternMap := origPattern.(map[string]interface{})
|
||||
reference = reference[1:]
|
||||
statements := strings.Split(reference, "/")
|
||||
|
||||
return getValueFromPattern(originalPatternMap, statements, 0)
|
||||
return getValueFromPattern(log, originalPatternMap, statements, 0)
|
||||
}
|
||||
|
||||
func getValueFromPattern(patternMap map[string]interface{}, keys []string, currentKeyIndex int) (interface{}, error) {
|
||||
func getValueFromPattern(log logr.Logger, patternMap map[string]interface{}, keys []string, currentKeyIndex int) (interface{}, error) {
|
||||
|
||||
for key, pattern := range patternMap {
|
||||
rawKey := getRawKeyIfWrappedWithAttributes(key)
|
||||
|
@ -221,19 +221,21 @@ func getValueFromPattern(patternMap map[string]interface{}, keys []string, curre
|
|||
for i, value := range typedPattern {
|
||||
resourceMap, ok := value.(map[string]interface{})
|
||||
if !ok {
|
||||
glog.V(4).Infof("Pattern and resource have different structures. Expected %T, found %T", pattern, value)
|
||||
log.V(4).Info("Pattern and resource have different structures.", "expected", fmt.Sprintf("%T", pattern), "current", fmt.Sprintf("%T", value))
|
||||
return nil, fmt.Errorf("Validation rule failed, resource does not have expected pattern %v", patternMap)
|
||||
}
|
||||
if keys[currentKeyIndex+1] == strconv.Itoa(i) {
|
||||
return getValueFromPattern(resourceMap, keys, currentKeyIndex+2)
|
||||
return getValueFromPattern(log, 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, nil // Just a hack to fix the lint
|
||||
}
|
||||
return nil, errors.New("Reference to non-existent place in the document")
|
||||
case map[string]interface{}:
|
||||
if keys[currentKeyIndex] == rawKey {
|
||||
return getValueFromPattern(typedPattern, keys, currentKeyIndex+1)
|
||||
return getValueFromPattern(log, typedPattern, keys, currentKeyIndex+1)
|
||||
}
|
||||
return nil, errors.New("Reference to non-existent place in the document")
|
||||
case string, float64, int, int64, bool, nil:
|
||||
|
@ -251,12 +253,12 @@ func getValueFromPattern(patternMap map[string]interface{}, keys []string, curre
|
|||
|
||||
// validateArrayOfMaps gets anchors from pattern array map element, applies anchors logic
|
||||
// and then validates each map due to the pattern
|
||||
func validateArrayOfMaps(resourceMapArray []interface{}, patternMap map[string]interface{}, originPattern interface{}, path string) (string, error) {
|
||||
func validateArrayOfMaps(log logr.Logger, resourceMapArray []interface{}, patternMap map[string]interface{}, originPattern interface{}, path string) (string, error) {
|
||||
for i, resourceElement := range resourceMapArray {
|
||||
// check the types of resource element
|
||||
// expect it to be map, but can be anything ?:(
|
||||
currentPath := path + strconv.Itoa(i) + "/"
|
||||
returnpath, err := validateResourceElement(resourceElement, patternMap, originPattern, currentPath)
|
||||
returnpath, err := validateResourceElement(log, resourceElement, patternMap, originPattern, currentPath)
|
||||
if err != nil {
|
||||
return returnpath, err
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"gotest.tools/assert"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
)
|
||||
|
||||
func TestValidateMap(t *testing.T) {
|
||||
|
@ -100,7 +101,7 @@ func TestValidateMap(t *testing.T) {
|
|||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||
|
||||
path, err := validateMap(resource, pattern, pattern, "/")
|
||||
path, err := validateMap(log.Log, resource, pattern, pattern, "/")
|
||||
assert.Equal(t, path, "")
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
@ -196,7 +197,7 @@ func TestValidateMap_AsteriskForInt(t *testing.T) {
|
|||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||
|
||||
path, err := validateMap(resource, pattern, pattern, "/")
|
||||
path, err := validateMap(log.Log, resource, pattern, pattern, "/")
|
||||
t.Log(path)
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
@ -289,7 +290,7 @@ func TestValidateMap_AsteriskForMap(t *testing.T) {
|
|||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||
|
||||
path, err := validateMap(resource, pattern, pattern, "/")
|
||||
path, err := validateMap(log.Log, resource, pattern, pattern, "/")
|
||||
assert.Equal(t, path, "")
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
@ -377,7 +378,7 @@ func TestValidateMap_AsteriskForArray(t *testing.T) {
|
|||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||
|
||||
path, err := validateMap(resource, pattern, pattern, "/")
|
||||
path, err := validateMap(log.Log, resource, pattern, pattern, "/")
|
||||
assert.Equal(t, path, "")
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
@ -468,7 +469,7 @@ func TestValidateMap_AsteriskFieldIsMissing(t *testing.T) {
|
|||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||
|
||||
path, err := validateMap(resource, pattern, pattern, "/")
|
||||
path, err := validateMap(log.Log, resource, pattern, pattern, "/")
|
||||
assert.Equal(t, path, "/spec/template/spec/containers/0/")
|
||||
assert.Assert(t, err != nil)
|
||||
}
|
||||
|
@ -557,9 +558,10 @@ func TestValidateMap_livenessProbeIsNull(t *testing.T) {
|
|||
|
||||
var pattern, resource map[string]interface{}
|
||||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||
json.Unmarshal(rawMap, &resource)
|
||||
err := json.Unmarshal(rawMap, &resource)
|
||||
assert.NilError(t, err)
|
||||
|
||||
path, err := validateMap(resource, pattern, pattern, "/")
|
||||
path, err := validateMap(log.Log, resource, pattern, pattern, "/")
|
||||
assert.Equal(t, path, "")
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
@ -649,7 +651,7 @@ func TestValidateMap_livenessProbeIsMissing(t *testing.T) {
|
|||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||
|
||||
path, err := validateMap(resource, pattern, pattern, "/")
|
||||
path, err := validateMap(log.Log, resource, pattern, pattern, "/")
|
||||
assert.Equal(t, path, "")
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
@ -695,7 +697,7 @@ func TestValidateMapElement_TwoElementsInArrayOnePass(t *testing.T) {
|
|||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||
|
||||
path, err := validateResourceElement(resource, pattern, pattern, "/")
|
||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/")
|
||||
assert.Equal(t, path, "")
|
||||
// assert.Equal(t, path, "/1/object/0/key2/")
|
||||
// assert.NilError(t, err)
|
||||
|
@ -730,7 +732,7 @@ func TestValidateMapElement_OneElementInArrayPass(t *testing.T) {
|
|||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||
|
||||
path, err := validateResourceElement(resource, pattern, pattern, "/")
|
||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/")
|
||||
assert.Equal(t, path, "")
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
@ -784,7 +786,7 @@ func TestValidateMap_CorrectRelativePathInConfig(t *testing.T) {
|
|||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||
|
||||
path, err := validateResourceElement(resource, pattern, pattern, "/")
|
||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/")
|
||||
assert.Equal(t, path, "")
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
@ -838,7 +840,7 @@ func TestValidateMap_RelativePathDoesNotExists(t *testing.T) {
|
|||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||
|
||||
path, err := validateResourceElement(resource, pattern, pattern, "/")
|
||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/")
|
||||
assert.Equal(t, path, "/spec/containers/0/resources/requests/memory/")
|
||||
assert.Assert(t, err != nil)
|
||||
}
|
||||
|
@ -892,7 +894,7 @@ func TestValidateMap_OnlyAnchorsInPath(t *testing.T) {
|
|||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||
|
||||
path, err := validateResourceElement(resource, pattern, pattern, "/")
|
||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/")
|
||||
assert.Equal(t, path, "/spec/containers/0/resources/requests/memory/")
|
||||
assert.Assert(t, err != nil)
|
||||
}
|
||||
|
@ -946,7 +948,7 @@ func TestValidateMap_MalformedReferenceOnlyDolarMark(t *testing.T) {
|
|||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||
|
||||
path, err := validateResourceElement(resource, pattern, pattern, "/")
|
||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/")
|
||||
assert.Equal(t, path, "/spec/containers/0/resources/requests/memory/")
|
||||
assert.Assert(t, err != nil)
|
||||
}
|
||||
|
@ -1000,7 +1002,7 @@ func TestValidateMap_RelativePathWithParentheses(t *testing.T) {
|
|||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||
|
||||
path, err := validateResourceElement(resource, pattern, pattern, "/")
|
||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/")
|
||||
assert.Equal(t, path, "")
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
@ -1054,7 +1056,7 @@ func TestValidateMap_MalformedPath(t *testing.T) {
|
|||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||
|
||||
path, err := validateResourceElement(resource, pattern, pattern, "/")
|
||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/")
|
||||
assert.Equal(t, path, "/spec/containers/0/resources/requests/memory/")
|
||||
assert.Assert(t, err != nil)
|
||||
}
|
||||
|
@ -1108,7 +1110,7 @@ func TestValidateMap_AbosolutePathExists(t *testing.T) {
|
|||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||
|
||||
path, err := validateResourceElement(resource, pattern, pattern, "/")
|
||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/")
|
||||
assert.Equal(t, path, "")
|
||||
assert.Assert(t, err == nil)
|
||||
}
|
||||
|
@ -1149,7 +1151,7 @@ func TestValidateMap_AbsolutePathToMetadata(t *testing.T) {
|
|||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||
|
||||
path, err := validateResourceElement(resource, pattern, pattern, "/")
|
||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/")
|
||||
assert.Equal(t, path, "")
|
||||
assert.Assert(t, err == nil)
|
||||
}
|
||||
|
@ -1191,7 +1193,7 @@ func TestValidateMap_AbsolutePathToMetadata_fail(t *testing.T) {
|
|||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||
|
||||
path, err := validateResourceElement(resource, pattern, pattern, "/")
|
||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/")
|
||||
assert.Equal(t, path, "/spec/containers/0/image/")
|
||||
assert.Assert(t, err != nil)
|
||||
}
|
||||
|
@ -1245,7 +1247,7 @@ func TestValidateMap_AbosolutePathDoesNotExists(t *testing.T) {
|
|||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||
|
||||
path, err := validateResourceElement(resource, pattern, pattern, "/")
|
||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/")
|
||||
assert.Equal(t, path, "/spec/containers/0/resources/requests/memory/")
|
||||
assert.Assert(t, err != nil)
|
||||
}
|
||||
|
@ -1276,7 +1278,7 @@ func TestActualizePattern_GivenRelativePathThatExists(t *testing.T) {
|
|||
|
||||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||
|
||||
pattern, err := actualizePattern(pattern, referencePath, absolutePath)
|
||||
pattern, err := actualizePattern(log.Log, pattern, referencePath, absolutePath)
|
||||
|
||||
assert.Assert(t, err == nil)
|
||||
}
|
||||
|
@ -1344,10 +1346,12 @@ func TestValidateMapElement_OneElementInArrayNotPass(t *testing.T) {
|
|||
]`)
|
||||
|
||||
var pattern, resource interface{}
|
||||
json.Unmarshal(rawPattern, &pattern)
|
||||
json.Unmarshal(rawMap, &resource)
|
||||
err := json.Unmarshal(rawPattern, &pattern)
|
||||
assert.NilError(t, err)
|
||||
err = json.Unmarshal(rawMap, &resource)
|
||||
assert.NilError(t, err)
|
||||
|
||||
path, err := validateResourceElement(resource, pattern, pattern, "/")
|
||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/")
|
||||
assert.Equal(t, path, "/0/object/0/key2/")
|
||||
assert.Assert(t, err != nil)
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ import (
|
|||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/go-logr/logr"
|
||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||
"github.com/nirmata/kyverno/pkg/engine/context"
|
||||
"github.com/nirmata/kyverno/pkg/engine/response"
|
||||
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/nirmata/kyverno/pkg/engine/validate"
|
||||
"github.com/nirmata/kyverno/pkg/engine/variables"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
)
|
||||
|
||||
//Validate applies validation rules from policy on the resource
|
||||
|
@ -23,17 +24,18 @@ func Validate(policyContext PolicyContext) (resp response.EngineResponse) {
|
|||
oldR := policyContext.OldResource
|
||||
ctx := policyContext.Context
|
||||
admissionInfo := policyContext.AdmissionInfo
|
||||
logger := log.Log.WithName("Validate").WithValues("policy", policy.Name, "kind", newR.GetKind(), "namespace", newR.GetNamespace(), "name", newR.GetName())
|
||||
|
||||
// policy information
|
||||
glog.V(4).Infof("started applying validation rules of policy %q (%v)", policy.Name, startTime)
|
||||
logger.V(4).Info("start processing", "startTime", startTime)
|
||||
|
||||
// Process new & old resource
|
||||
if reflect.DeepEqual(oldR, unstructured.Unstructured{}) {
|
||||
// Create Mode
|
||||
// Operate on New Resource only
|
||||
resp := validateResource(ctx, policy, newR, admissionInfo)
|
||||
resp := validateResource(logger, ctx, policy, newR, admissionInfo)
|
||||
startResultResponse(resp, policy, newR)
|
||||
defer endResultResponse(resp, startTime)
|
||||
defer endResultResponse(logger, resp, startTime)
|
||||
// set PatchedResource with origin resource if empty
|
||||
// in order to create policy violation
|
||||
if reflect.DeepEqual(resp.PatchedResource, unstructured.Unstructured{}) {
|
||||
|
@ -44,14 +46,14 @@ func Validate(policyContext PolicyContext) (resp response.EngineResponse) {
|
|||
// Update Mode
|
||||
// Operate on New and Old Resource only
|
||||
// New resource
|
||||
oldResponse := validateResource(ctx, policy, oldR, admissionInfo)
|
||||
newResponse := validateResource(ctx, policy, newR, admissionInfo)
|
||||
oldResponse := validateResource(logger, ctx, policy, oldR, admissionInfo)
|
||||
newResponse := validateResource(logger, ctx, policy, newR, admissionInfo)
|
||||
|
||||
// if the old and new response is same then return empty response
|
||||
if !isSameResponse(oldResponse, newResponse) {
|
||||
// there are changes send response
|
||||
startResultResponse(newResponse, policy, newR)
|
||||
defer endResultResponse(newResponse, startTime)
|
||||
defer endResultResponse(logger, newResponse, startTime)
|
||||
if reflect.DeepEqual(newResponse.PatchedResource, unstructured.Unstructured{}) {
|
||||
newResponse.PatchedResource = newR
|
||||
}
|
||||
|
@ -73,10 +75,9 @@ func startResultResponse(resp *response.EngineResponse, policy kyverno.ClusterPo
|
|||
resp.PolicyResponse.ValidationFailureAction = policy.Spec.ValidationFailureAction
|
||||
}
|
||||
|
||||
func endResultResponse(resp *response.EngineResponse, startTime time.Time) {
|
||||
func endResultResponse(log logr.Logger, resp *response.EngineResponse, startTime time.Time) {
|
||||
resp.PolicyResponse.ProcessingTime = time.Since(startTime)
|
||||
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)
|
||||
log.V(4).Info("finshed processing", "processingTime", resp.PolicyResponse.ProcessingTime, "validationRulesApplied", resp.PolicyResponse.RulesAppliedCount)
|
||||
}
|
||||
|
||||
func incrementAppliedCount(resp *response.EngineResponse) {
|
||||
|
@ -84,20 +85,18 @@ func incrementAppliedCount(resp *response.EngineResponse) {
|
|||
resp.PolicyResponse.RulesAppliedCount++
|
||||
}
|
||||
|
||||
func validateResource(ctx context.EvalInterface, policy kyverno.ClusterPolicy, resource unstructured.Unstructured, admissionInfo kyverno.RequestInfo) *response.EngineResponse {
|
||||
func validateResource(log logr.Logger, ctx context.EvalInterface, policy kyverno.ClusterPolicy, resource unstructured.Unstructured, admissionInfo kyverno.RequestInfo) *response.EngineResponse {
|
||||
resp := &response.EngineResponse{}
|
||||
for _, rule := range policy.Spec.Rules {
|
||||
if !rule.HasValidate() {
|
||||
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
|
||||
// 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
|
||||
if err := MatchesResourceDescription(resource, rule, admissionInfo); err != nil {
|
||||
glog.V(4).Infof("resource %s/%s does not satisfy the resource description for the rule:\n%s", resource.GetNamespace(), resource.GetName(), err.Error())
|
||||
log.V(4).Info("resource fails the match description")
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -105,13 +104,13 @@ func validateResource(ctx context.EvalInterface, policy kyverno.ClusterPolicy, r
|
|||
copyConditions := copyConditions(rule.Conditions)
|
||||
// evaluate pre-conditions
|
||||
// - handle variable subsitutions
|
||||
if !variables.EvaluateConditions(ctx, copyConditions) {
|
||||
glog.V(4).Infof("resource %s/%s does not satisfy the conditions for the rule ", resource.GetNamespace(), resource.GetName())
|
||||
if !variables.EvaluateConditions(log, ctx, copyConditions) {
|
||||
log.V(4).Info("resource fails the preconditions")
|
||||
continue
|
||||
}
|
||||
|
||||
if rule.Validation.Pattern != nil || rule.Validation.AnyPattern != nil {
|
||||
ruleResponse := validatePatterns(ctx, resource, rule)
|
||||
ruleResponse := validatePatterns(log, ctx, resource, rule)
|
||||
incrementAppliedCount(resp)
|
||||
resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, ruleResponse)
|
||||
}
|
||||
|
@ -159,14 +158,15 @@ func isSameRules(oldRules []response.RuleResponse, newRules []response.RuleRespo
|
|||
}
|
||||
|
||||
// validatePatterns validate pattern and anyPattern
|
||||
func validatePatterns(ctx context.EvalInterface, resource unstructured.Unstructured, rule kyverno.Rule) (resp response.RuleResponse) {
|
||||
func validatePatterns(log logr.Logger, ctx context.EvalInterface, resource unstructured.Unstructured, rule kyverno.Rule) (resp response.RuleResponse) {
|
||||
startTime := time.Now()
|
||||
glog.V(4).Infof("started applying validation rule %q (%v)", rule.Name, startTime)
|
||||
logger := log.WithValues("rule", rule.Name)
|
||||
logger.V(4).Info("start processing rule", "startTime", startTime)
|
||||
resp.Name = rule.Name
|
||||
resp.Type = utils.Validation.String()
|
||||
defer func() {
|
||||
resp.RuleStats.ProcessingTime = time.Since(startTime)
|
||||
glog.V(4).Infof("finished applying validation rule %q (%v)", resp.Name, resp.RuleStats.ProcessingTime)
|
||||
logger.V(4).Info("finshed processing", "processingTime", resp.RuleStats.ProcessingTime)
|
||||
}()
|
||||
// work on a copy of validation rule
|
||||
validationRule := rule.Validation.DeepCopy()
|
||||
|
@ -176,7 +176,7 @@ func validatePatterns(ctx context.EvalInterface, resource unstructured.Unstructu
|
|||
// substitute variables in the pattern
|
||||
pattern := validationRule.Pattern
|
||||
var err error
|
||||
if pattern, err = variables.SubstituteVars(ctx, pattern); err != nil {
|
||||
if pattern, err = variables.SubstituteVars(logger, ctx, pattern); err != nil {
|
||||
// variable subsitution failed
|
||||
resp.Success = false
|
||||
resp.Message = fmt.Sprintf("Validation error: %s; Validation rule '%s' failed. '%s'",
|
||||
|
@ -184,7 +184,7 @@ func validatePatterns(ctx context.EvalInterface, resource unstructured.Unstructu
|
|||
return resp
|
||||
}
|
||||
|
||||
if path, err := validate.ValidateResourceWithPattern(resource.Object, pattern); err != nil {
|
||||
if path, err := validate.ValidateResourceWithPattern(logger, resource.Object, pattern); err != nil {
|
||||
// validation failed
|
||||
resp.Success = false
|
||||
resp.Message = fmt.Sprintf("Validation error: %s; Validation rule '%s' failed at path '%s'",
|
||||
|
@ -192,7 +192,7 @@ func validatePatterns(ctx context.EvalInterface, resource unstructured.Unstructu
|
|||
return resp
|
||||
}
|
||||
// rule application successful
|
||||
glog.V(4).Infof("rule %s pattern validated successfully on resource %s/%s/%s", rule.Name, resource.GetKind(), resource.GetNamespace(), resource.GetName())
|
||||
logger.V(4).Info("successfully processed rule")
|
||||
resp.Success = true
|
||||
resp.Message = fmt.Sprintf("Validation rule '%s' succeeded.", rule.Name)
|
||||
return resp
|
||||
|
@ -203,19 +203,18 @@ func validatePatterns(ctx context.EvalInterface, resource unstructured.Unstructu
|
|||
var failedAnyPatternsErrors []error
|
||||
var err error
|
||||
for idx, pattern := range validationRule.AnyPattern {
|
||||
if pattern, err = variables.SubstituteVars(ctx, pattern); err != nil {
|
||||
if pattern, err = variables.SubstituteVars(logger, ctx, pattern); err != nil {
|
||||
// variable subsitution failed
|
||||
failedSubstitutionsErrors = append(failedSubstitutionsErrors, err)
|
||||
continue
|
||||
}
|
||||
_, err := validate.ValidateResourceWithPattern(resource.Object, pattern)
|
||||
_, err := validate.ValidateResourceWithPattern(logger, resource.Object, pattern)
|
||||
if err == nil {
|
||||
resp.Success = true
|
||||
resp.Message = fmt.Sprintf("Validation rule '%s' anyPattern[%d] succeeded.", rule.Name, idx)
|
||||
return resp
|
||||
}
|
||||
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())
|
||||
logger.V(4).Info(fmt.Sprintf("validation rule failed for anyPattern[%d]", idx), "message", rule.Validation.Message)
|
||||
patternErr := fmt.Errorf("anyPattern[%d] failed; %s", idx, err)
|
||||
failedAnyPatternsErrors = append(failedAnyPatternsErrors, patternErr)
|
||||
}
|
||||
|
@ -234,7 +233,7 @@ func validatePatterns(ctx context.EvalInterface, resource unstructured.Unstructu
|
|||
errorStr = append(errorStr, err.Error())
|
||||
}
|
||||
resp.Success = false
|
||||
glog.V(4).Infof("Validation rule '%s' failed. %s", rule.Name, errorStr)
|
||||
log.V(4).Info(fmt.Sprintf("Validation rule '%s' failed. %s", rule.Name, errorStr))
|
||||
if rule.Validation.Message == "" {
|
||||
resp.Message = fmt.Sprintf("Validation rule '%s' has failed", rule.Name)
|
||||
} else {
|
||||
|
|
|
@ -23,7 +23,8 @@ func TestGetAnchorsFromMap_ThereAreAnchors(t *testing.T) {
|
|||
}`)
|
||||
|
||||
var unmarshalled map[string]interface{}
|
||||
json.Unmarshal(rawMap, &unmarshalled)
|
||||
err := json.Unmarshal(rawMap, &unmarshalled)
|
||||
assert.NilError(t, err)
|
||||
|
||||
actualMap := utils.GetAnchorsFromMap(unmarshalled)
|
||||
assert.Equal(t, len(actualMap), 2)
|
||||
|
@ -114,7 +115,8 @@ func TestValidate_image_tag_fail(t *testing.T) {
|
|||
`)
|
||||
|
||||
var policy kyverno.ClusterPolicy
|
||||
json.Unmarshal(rawPolicy, &policy)
|
||||
err := json.Unmarshal(rawPolicy, &policy)
|
||||
assert.NilError(t, err)
|
||||
|
||||
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
|
@ -212,7 +214,8 @@ func TestValidate_image_tag_pass(t *testing.T) {
|
|||
`)
|
||||
|
||||
var policy kyverno.ClusterPolicy
|
||||
json.Unmarshal(rawPolicy, &policy)
|
||||
err := json.Unmarshal(rawPolicy, &policy)
|
||||
assert.NilError(t, err)
|
||||
|
||||
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
|
@ -289,7 +292,8 @@ func TestValidate_Fail_anyPattern(t *testing.T) {
|
|||
`)
|
||||
|
||||
var policy kyverno.ClusterPolicy
|
||||
json.Unmarshal(rawPolicy, &policy)
|
||||
err := json.Unmarshal(rawPolicy, &policy)
|
||||
assert.NilError(t, err)
|
||||
|
||||
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
|
@ -370,7 +374,8 @@ func TestValidate_host_network_port(t *testing.T) {
|
|||
`)
|
||||
|
||||
var policy kyverno.ClusterPolicy
|
||||
json.Unmarshal(rawPolicy, &policy)
|
||||
err := json.Unmarshal(rawPolicy, &policy)
|
||||
assert.NilError(t, err)
|
||||
|
||||
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
|
@ -459,7 +464,8 @@ func TestValidate_anchor_arraymap_pass(t *testing.T) {
|
|||
} `)
|
||||
|
||||
var policy kyverno.ClusterPolicy
|
||||
json.Unmarshal(rawPolicy, &policy)
|
||||
err := json.Unmarshal(rawPolicy, &policy)
|
||||
assert.NilError(t, err)
|
||||
|
||||
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
|
@ -547,8 +553,8 @@ func TestValidate_anchor_arraymap_fail(t *testing.T) {
|
|||
} `)
|
||||
|
||||
var policy kyverno.ClusterPolicy
|
||||
json.Unmarshal(rawPolicy, &policy)
|
||||
|
||||
err := json.Unmarshal(rawPolicy, &policy)
|
||||
assert.NilError(t, err)
|
||||
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
er := Validate(PolicyContext{Policy: policy, NewResource: *resourceUnstructured})
|
||||
|
@ -616,7 +622,8 @@ func TestValidate_anchor_map_notfound(t *testing.T) {
|
|||
`)
|
||||
|
||||
var policy kyverno.ClusterPolicy
|
||||
json.Unmarshal(rawPolicy, &policy)
|
||||
err := json.Unmarshal(rawPolicy, &policy)
|
||||
assert.NilError(t, err)
|
||||
|
||||
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
|
@ -688,7 +695,8 @@ func TestValidate_anchor_map_found_valid(t *testing.T) {
|
|||
`)
|
||||
|
||||
var policy kyverno.ClusterPolicy
|
||||
json.Unmarshal(rawPolicy, &policy)
|
||||
err := json.Unmarshal(rawPolicy, &policy)
|
||||
assert.NilError(t, err)
|
||||
|
||||
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
|
@ -760,7 +768,8 @@ func TestValidate_anchor_map_found_invalid(t *testing.T) {
|
|||
`)
|
||||
|
||||
var policy kyverno.ClusterPolicy
|
||||
json.Unmarshal(rawPolicy, &policy)
|
||||
err := json.Unmarshal(rawPolicy, &policy)
|
||||
assert.NilError(t, err)
|
||||
|
||||
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
|
@ -834,7 +843,8 @@ func TestValidate_AnchorList_pass(t *testing.T) {
|
|||
`)
|
||||
|
||||
var policy kyverno.ClusterPolicy
|
||||
json.Unmarshal(rawPolicy, &policy)
|
||||
err := json.Unmarshal(rawPolicy, &policy)
|
||||
assert.NilError(t, err)
|
||||
|
||||
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
|
@ -908,7 +918,8 @@ func TestValidate_AnchorList_fail(t *testing.T) {
|
|||
`)
|
||||
|
||||
var policy kyverno.ClusterPolicy
|
||||
json.Unmarshal(rawPolicy, &policy)
|
||||
err := json.Unmarshal(rawPolicy, &policy)
|
||||
assert.NilError(t, err)
|
||||
|
||||
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
|
@ -982,7 +993,8 @@ func TestValidate_existenceAnchor_fail(t *testing.T) {
|
|||
`)
|
||||
|
||||
var policy kyverno.ClusterPolicy
|
||||
json.Unmarshal(rawPolicy, &policy)
|
||||
err := json.Unmarshal(rawPolicy, &policy)
|
||||
assert.NilError(t, err)
|
||||
|
||||
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
|
@ -1057,7 +1069,8 @@ func TestValidate_existenceAnchor_pass(t *testing.T) {
|
|||
`)
|
||||
|
||||
var policy kyverno.ClusterPolicy
|
||||
json.Unmarshal(rawPolicy, &policy)
|
||||
err := json.Unmarshal(rawPolicy, &policy)
|
||||
assert.NilError(t, err)
|
||||
|
||||
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
|
@ -1144,7 +1157,8 @@ func TestValidate_negationAnchor_deny(t *testing.T) {
|
|||
} `)
|
||||
|
||||
var policy kyverno.ClusterPolicy
|
||||
json.Unmarshal(rawPolicy, &policy)
|
||||
err := json.Unmarshal(rawPolicy, &policy)
|
||||
assert.NilError(t, err)
|
||||
|
||||
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
|
@ -1230,7 +1244,8 @@ func TestValidate_negationAnchor_pass(t *testing.T) {
|
|||
`)
|
||||
|
||||
var policy kyverno.ClusterPolicy
|
||||
json.Unmarshal(rawPolicy, &policy)
|
||||
err := json.Unmarshal(rawPolicy, &policy)
|
||||
assert.NilError(t, err)
|
||||
|
||||
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
|
@ -1297,12 +1312,14 @@ func Test_VariableSubstitutionPathNotExistInPattern(t *testing.T) {
|
|||
}`)
|
||||
|
||||
var policy kyverno.ClusterPolicy
|
||||
json.Unmarshal(policyraw, &policy)
|
||||
err := json.Unmarshal(policyraw, &policy)
|
||||
assert.NilError(t, err)
|
||||
resourceUnstructured, err := utils.ConvertToUnstructured(resourceRaw)
|
||||
assert.NilError(t, err)
|
||||
|
||||
ctx := context.NewContext()
|
||||
ctx.AddResource(resourceRaw)
|
||||
err = ctx.AddResource(resourceRaw)
|
||||
assert.NilError(t, err)
|
||||
|
||||
policyContext := PolicyContext{
|
||||
Policy: policy,
|
||||
|
@ -1392,7 +1409,8 @@ func Test_VariableSubstitutionPathNotExistInAnyPattern_OnePatternStatisfies(t *t
|
|||
assert.NilError(t, err)
|
||||
|
||||
ctx := context.NewContext()
|
||||
ctx.AddResource(resourceRaw)
|
||||
err = ctx.AddResource(resourceRaw)
|
||||
assert.NilError(t, err)
|
||||
|
||||
policyContext := PolicyContext{
|
||||
Policy: policy,
|
||||
|
@ -1482,7 +1500,8 @@ func Test_VariableSubstitutionPathNotExistInAnyPattern_AllPathNotPresent(t *test
|
|||
assert.NilError(t, err)
|
||||
|
||||
ctx := context.NewContext()
|
||||
ctx.AddResource(resourceRaw)
|
||||
err = ctx.AddResource(resourceRaw)
|
||||
assert.NilError(t, err)
|
||||
|
||||
policyContext := PolicyContext{
|
||||
Policy: policy,
|
||||
|
@ -1572,7 +1591,8 @@ func Test_VariableSubstitutionPathNotExistInAnyPattern_AllPathPresent_NonePatter
|
|||
assert.NilError(t, err)
|
||||
|
||||
ctx := context.NewContext()
|
||||
ctx.AddResource(resourceRaw)
|
||||
err = ctx.AddResource(resourceRaw)
|
||||
assert.NilError(t, err)
|
||||
|
||||
policyContext := PolicyContext{
|
||||
Policy: policy,
|
||||
|
|
10
pkg/engine/variables/common.go
Normal file
10
pkg/engine/variables/common.go
Normal file
|
@ -0,0 +1,10 @@
|
|||
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
|
||||
|
||||
import (
|
||||
"github.com/golang/glog"
|
||||
"github.com/go-logr/logr"
|
||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||
"github.com/nirmata/kyverno/pkg/engine/context"
|
||||
"github.com/nirmata/kyverno/pkg/engine/variables/operator"
|
||||
)
|
||||
|
||||
//Evaluate evaluates the condition
|
||||
func Evaluate(ctx context.EvalInterface, condition kyverno.Condition) bool {
|
||||
func Evaluate(log logr.Logger, ctx context.EvalInterface, condition kyverno.Condition) bool {
|
||||
// get handler for the operator
|
||||
handle := operator.CreateOperatorHandler(ctx, condition.Operator, SubstituteVars)
|
||||
handle := operator.CreateOperatorHandler(log, ctx, condition.Operator, SubstituteVars)
|
||||
if handle == nil {
|
||||
return false
|
||||
}
|
||||
|
@ -18,11 +18,10 @@ func Evaluate(ctx context.EvalInterface, condition kyverno.Condition) bool {
|
|||
}
|
||||
|
||||
//EvaluateConditions evaluates multiple conditions
|
||||
func EvaluateConditions(ctx context.EvalInterface, conditions []kyverno.Condition) bool {
|
||||
func EvaluateConditions(log logr.Logger, ctx context.EvalInterface, conditions []kyverno.Condition) bool {
|
||||
// AND the conditions
|
||||
for _, condition := range conditions {
|
||||
if !Evaluate(ctx, condition) {
|
||||
glog.V(4).Infof("condition %v failed", condition)
|
||||
if !Evaluate(log, ctx, condition) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
|
||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||
"github.com/nirmata/kyverno/pkg/engine/context"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
)
|
||||
|
||||
// STRINGS
|
||||
|
@ -18,7 +19,7 @@ func Test_Eval_Equal_Const_String_Pass(t *testing.T) {
|
|||
Value: "name",
|
||||
}
|
||||
|
||||
if !Evaluate(ctx, condition) {
|
||||
if !Evaluate(log.Log, ctx, condition) {
|
||||
t.Error("expected to pass")
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +33,7 @@ func Test_Eval_Equal_Const_String_Fail(t *testing.T) {
|
|||
Value: "name1",
|
||||
}
|
||||
|
||||
if Evaluate(ctx, condition) {
|
||||
if Evaluate(log.Log, ctx, condition) {
|
||||
t.Error("expected to fail")
|
||||
}
|
||||
}
|
||||
|
@ -46,7 +47,7 @@ func Test_Eval_NoEqual_Const_String_Pass(t *testing.T) {
|
|||
Value: "name1",
|
||||
}
|
||||
|
||||
if !Evaluate(ctx, condition) {
|
||||
if !Evaluate(log.Log, ctx, condition) {
|
||||
t.Error("expected to pass")
|
||||
}
|
||||
}
|
||||
|
@ -60,7 +61,7 @@ func Test_Eval_NoEqual_Const_String_Fail(t *testing.T) {
|
|||
Value: "name",
|
||||
}
|
||||
|
||||
if Evaluate(ctx, condition) {
|
||||
if Evaluate(log.Log, ctx, condition) {
|
||||
t.Error("expected to fail")
|
||||
}
|
||||
}
|
||||
|
@ -76,7 +77,7 @@ func Test_Eval_Equal_Const_Bool_Pass(t *testing.T) {
|
|||
Value: true,
|
||||
}
|
||||
|
||||
if !Evaluate(ctx, condition) {
|
||||
if !Evaluate(log.Log, ctx, condition) {
|
||||
t.Error("expected to pass")
|
||||
}
|
||||
}
|
||||
|
@ -90,7 +91,7 @@ func Test_Eval_Equal_Const_Bool_Fail(t *testing.T) {
|
|||
Value: false,
|
||||
}
|
||||
|
||||
if Evaluate(ctx, condition) {
|
||||
if Evaluate(log.Log, ctx, condition) {
|
||||
t.Error("expected to fail")
|
||||
}
|
||||
}
|
||||
|
@ -104,7 +105,7 @@ func Test_Eval_NoEqual_Const_Bool_Pass(t *testing.T) {
|
|||
Value: false,
|
||||
}
|
||||
|
||||
if !Evaluate(ctx, condition) {
|
||||
if !Evaluate(log.Log, ctx, condition) {
|
||||
t.Error("expected to pass")
|
||||
}
|
||||
}
|
||||
|
@ -118,7 +119,7 @@ func Test_Eval_NoEqual_Const_Bool_Fail(t *testing.T) {
|
|||
Value: true,
|
||||
}
|
||||
|
||||
if Evaluate(ctx, condition) {
|
||||
if Evaluate(log.Log, ctx, condition) {
|
||||
t.Error("expected to fail")
|
||||
}
|
||||
}
|
||||
|
@ -133,7 +134,7 @@ func Test_Eval_Equal_Const_int_Pass(t *testing.T) {
|
|||
Value: 1,
|
||||
}
|
||||
|
||||
if !Evaluate(ctx, condition) {
|
||||
if !Evaluate(log.Log, ctx, condition) {
|
||||
t.Error("expected to pass")
|
||||
}
|
||||
}
|
||||
|
@ -147,7 +148,7 @@ func Test_Eval_Equal_Const_int_Fail(t *testing.T) {
|
|||
Value: 2,
|
||||
}
|
||||
|
||||
if Evaluate(ctx, condition) {
|
||||
if Evaluate(log.Log, ctx, condition) {
|
||||
t.Error("expected to fail")
|
||||
}
|
||||
}
|
||||
|
@ -161,7 +162,7 @@ func Test_Eval_NoEqual_Const_int_Pass(t *testing.T) {
|
|||
Value: 2,
|
||||
}
|
||||
|
||||
if !Evaluate(ctx, condition) {
|
||||
if !Evaluate(log.Log, ctx, condition) {
|
||||
t.Error("expected to pass")
|
||||
}
|
||||
}
|
||||
|
@ -175,7 +176,7 @@ func Test_Eval_NoEqual_Const_int_Fail(t *testing.T) {
|
|||
Value: 1,
|
||||
}
|
||||
|
||||
if Evaluate(ctx, condition) {
|
||||
if Evaluate(log.Log, ctx, condition) {
|
||||
t.Error("expected to fail")
|
||||
}
|
||||
}
|
||||
|
@ -190,7 +191,7 @@ func Test_Eval_Equal_Const_int64_Pass(t *testing.T) {
|
|||
Value: int64(1),
|
||||
}
|
||||
|
||||
if !Evaluate(ctx, condition) {
|
||||
if !Evaluate(log.Log, ctx, condition) {
|
||||
t.Error("expected to pass")
|
||||
}
|
||||
}
|
||||
|
@ -204,7 +205,7 @@ func Test_Eval_Equal_Const_int64_Fail(t *testing.T) {
|
|||
Value: int64(2),
|
||||
}
|
||||
|
||||
if Evaluate(ctx, condition) {
|
||||
if Evaluate(log.Log, ctx, condition) {
|
||||
t.Error("expected to fail")
|
||||
}
|
||||
}
|
||||
|
@ -218,7 +219,7 @@ func Test_Eval_NoEqual_Const_int64_Pass(t *testing.T) {
|
|||
Value: int64(2),
|
||||
}
|
||||
|
||||
if !Evaluate(ctx, condition) {
|
||||
if !Evaluate(log.Log, ctx, condition) {
|
||||
t.Error("expected to pass")
|
||||
}
|
||||
}
|
||||
|
@ -232,7 +233,7 @@ func Test_Eval_NoEqual_Const_int64_Fail(t *testing.T) {
|
|||
Value: int64(1),
|
||||
}
|
||||
|
||||
if Evaluate(ctx, condition) {
|
||||
if Evaluate(log.Log, ctx, condition) {
|
||||
t.Error("expected to fail")
|
||||
}
|
||||
}
|
||||
|
@ -248,7 +249,7 @@ func Test_Eval_Equal_Const_float64_Pass(t *testing.T) {
|
|||
Value: 1.5,
|
||||
}
|
||||
|
||||
if !Evaluate(ctx, condition) {
|
||||
if !Evaluate(log.Log, ctx, condition) {
|
||||
t.Error("expected to pass")
|
||||
}
|
||||
}
|
||||
|
@ -262,7 +263,7 @@ func Test_Eval_Equal_Const_float64_Fail(t *testing.T) {
|
|||
Value: 1.6,
|
||||
}
|
||||
|
||||
if Evaluate(ctx, condition) {
|
||||
if Evaluate(log.Log, ctx, condition) {
|
||||
t.Error("expected to fail")
|
||||
}
|
||||
}
|
||||
|
@ -276,7 +277,7 @@ func Test_Eval_NoEqual_Const_float64_Pass(t *testing.T) {
|
|||
Value: 1.6,
|
||||
}
|
||||
|
||||
if !Evaluate(ctx, condition) {
|
||||
if !Evaluate(log.Log, ctx, condition) {
|
||||
t.Error("expected to pass")
|
||||
}
|
||||
}
|
||||
|
@ -290,7 +291,7 @@ func Test_Eval_NoEqual_Const_float64_Fail(t *testing.T) {
|
|||
Value: 1.5,
|
||||
}
|
||||
|
||||
if Evaluate(ctx, condition) {
|
||||
if Evaluate(log.Log, ctx, condition) {
|
||||
t.Error("expected to fail")
|
||||
}
|
||||
}
|
||||
|
@ -320,7 +321,7 @@ func Test_Eval_Equal_Const_object_Pass(t *testing.T) {
|
|||
Value: obj2,
|
||||
}
|
||||
|
||||
if !Evaluate(ctx, condition) {
|
||||
if !Evaluate(log.Log, ctx, condition) {
|
||||
t.Error("expected to pass")
|
||||
}
|
||||
}
|
||||
|
@ -348,7 +349,7 @@ func Test_Eval_Equal_Const_object_Fail(t *testing.T) {
|
|||
Value: obj2,
|
||||
}
|
||||
|
||||
if Evaluate(ctx, condition) {
|
||||
if Evaluate(log.Log, ctx, condition) {
|
||||
t.Error("expected to fail")
|
||||
}
|
||||
}
|
||||
|
@ -376,7 +377,7 @@ func Test_Eval_NotEqual_Const_object_Pass(t *testing.T) {
|
|||
Value: obj2,
|
||||
}
|
||||
|
||||
if !Evaluate(ctx, condition) {
|
||||
if !Evaluate(log.Log, ctx, condition) {
|
||||
t.Error("expected to pass")
|
||||
}
|
||||
}
|
||||
|
@ -404,7 +405,7 @@ func Test_Eval_NotEqual_Const_object_Fail(t *testing.T) {
|
|||
Value: obj2,
|
||||
}
|
||||
|
||||
if Evaluate(ctx, condition) {
|
||||
if Evaluate(log.Log, ctx, condition) {
|
||||
t.Error("expected to fail")
|
||||
}
|
||||
}
|
||||
|
@ -434,7 +435,7 @@ func Test_Eval_Equal_Const_list_Pass(t *testing.T) {
|
|||
Value: obj2,
|
||||
}
|
||||
|
||||
if !Evaluate(ctx, condition) {
|
||||
if !Evaluate(log.Log, ctx, condition) {
|
||||
t.Error("expected to pass")
|
||||
}
|
||||
}
|
||||
|
@ -460,7 +461,7 @@ func Test_Eval_Equal_Const_list_Fail(t *testing.T) {
|
|||
Value: obj2,
|
||||
}
|
||||
|
||||
if Evaluate(ctx, condition) {
|
||||
if Evaluate(log.Log, ctx, condition) {
|
||||
t.Error("expected to fail")
|
||||
}
|
||||
}
|
||||
|
@ -486,7 +487,7 @@ func Test_Eval_NotEqual_Const_list_Pass(t *testing.T) {
|
|||
Value: obj2,
|
||||
}
|
||||
|
||||
if !Evaluate(ctx, condition) {
|
||||
if !Evaluate(log.Log, ctx, condition) {
|
||||
t.Error("expected to pass")
|
||||
}
|
||||
}
|
||||
|
@ -512,7 +513,7 @@ func Test_Eval_NotEqual_Const_list_Fail(t *testing.T) {
|
|||
Value: obj2,
|
||||
}
|
||||
|
||||
if Evaluate(ctx, condition) {
|
||||
if Evaluate(log.Log, ctx, condition) {
|
||||
t.Error("expected to fail")
|
||||
}
|
||||
}
|
||||
|
@ -545,7 +546,7 @@ func Test_Eval_Equal_Var_Pass(t *testing.T) {
|
|||
Value: "temp",
|
||||
}
|
||||
|
||||
if !Evaluate(ctx, condition) {
|
||||
if !Evaluate(log.Log, ctx, condition) {
|
||||
t.Error("expected to pass")
|
||||
}
|
||||
}
|
||||
|
@ -576,7 +577,7 @@ func Test_Eval_Equal_Var_Fail(t *testing.T) {
|
|||
Value: "temp1",
|
||||
}
|
||||
|
||||
if Evaluate(ctx, condition) {
|
||||
if Evaluate(log.Log, ctx, condition) {
|
||||
t.Error("expected to fail")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,19 +1,21 @@
|
|||
package operator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
"strconv"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/go-logr/logr"
|
||||
"github.com/nirmata/kyverno/pkg/engine/context"
|
||||
)
|
||||
|
||||
//NewEqualHandler returns handler to manage Equal operations
|
||||
func NewEqualHandler(ctx context.EvalInterface, subHandler VariableSubstitutionHandler) OperatorHandler {
|
||||
func NewEqualHandler(log logr.Logger, ctx context.EvalInterface, subHandler VariableSubstitutionHandler) OperatorHandler {
|
||||
return EqualHandler{
|
||||
ctx: ctx,
|
||||
subHandler: subHandler,
|
||||
log: log,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,6 +23,7 @@ func NewEqualHandler(ctx context.EvalInterface, subHandler VariableSubstitutionH
|
|||
type EqualHandler struct {
|
||||
ctx context.EvalInterface
|
||||
subHandler VariableSubstitutionHandler
|
||||
log logr.Logger
|
||||
}
|
||||
|
||||
//Evaluate evaluates expression with Equal Operator
|
||||
|
@ -28,14 +31,14 @@ func (eh EqualHandler) Evaluate(key, value interface{}) bool {
|
|||
var err error
|
||||
//TODO: decouple variables from evaluation
|
||||
// substitute the variables
|
||||
if key, err = eh.subHandler(eh.ctx, key); err != nil {
|
||||
if key, err = eh.subHandler(eh.log, eh.ctx, key); err != nil {
|
||||
// Failed to resolve the variable
|
||||
glog.Infof("Failed to resolve variables in key: %s: %v", key, err)
|
||||
eh.log.Error(err, "Failed to resolve variable", "variable", key)
|
||||
return false
|
||||
}
|
||||
if value, err = eh.subHandler(eh.ctx, value); err != nil {
|
||||
if value, err = eh.subHandler(eh.log, eh.ctx, value); err != nil {
|
||||
// Failed to resolve the variable
|
||||
glog.Infof("Failed to resolve variables in value: %s: %v", value, err)
|
||||
eh.log.Error(err, "Failed to resolve variable", "variable", value)
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -56,7 +59,7 @@ func (eh EqualHandler) Evaluate(key, value interface{}) bool {
|
|||
case []interface{}:
|
||||
return eh.validateValueWithSlicePattern(typedKey, value)
|
||||
default:
|
||||
glog.Errorf("Unsupported type %v", typedKey)
|
||||
eh.log.Info("Unsupported type", "value", typedKey, "type", fmt.Sprintf("%T", typedKey))
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
@ -65,7 +68,7 @@ func (eh EqualHandler) validateValueWithSlicePattern(key []interface{}, value in
|
|||
if val, ok := value.([]interface{}); ok {
|
||||
return reflect.DeepEqual(key, val)
|
||||
}
|
||||
glog.Warningf("Expected []interface{}, %v is of type %T", value, value)
|
||||
eh.log.Info("Expected type []interface{}", "value", value, "type", fmt.Sprintf("%T", value))
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -73,7 +76,7 @@ func (eh EqualHandler) validateValueWithMapPattern(key map[string]interface{}, v
|
|||
if val, ok := value.(map[string]interface{}); ok {
|
||||
return reflect.DeepEqual(key, val)
|
||||
}
|
||||
glog.Warningf("Expected map[string]interface{}, %v is of type %T", value, value)
|
||||
eh.log.Info("Expected type map[string]interface{}", "value", value, "type", fmt.Sprintf("%T", value))
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -81,7 +84,8 @@ func (eh EqualHandler) validateValuewithStringPattern(key string, value interfac
|
|||
if val, ok := value.(string); ok {
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -92,25 +96,25 @@ func (eh EqualHandler) validateValuewithFloatPattern(key float64, value interfac
|
|||
if key == math.Trunc(key) {
|
||||
return int(key) == typedValue
|
||||
}
|
||||
glog.Warningf("Expected float, found int: %d\n", typedValue)
|
||||
eh.log.Info("Expected type float, found int", "typedValue", typedValue)
|
||||
case int64:
|
||||
// check that float has not fraction
|
||||
if key == math.Trunc(key) {
|
||||
return int64(key) == typedValue
|
||||
}
|
||||
glog.Warningf("Expected float, found int: %d\n", typedValue)
|
||||
eh.log.Info("Expected type float, found int", "typedValue", typedValue)
|
||||
case float64:
|
||||
return typedValue == key
|
||||
case string:
|
||||
// extract float from string
|
||||
float64Num, err := strconv.ParseFloat(typedValue, 64)
|
||||
if err != nil {
|
||||
glog.Warningf("Failed to parse float64 from string: %v", err)
|
||||
eh.log.Error(err, "Failed to parse float64 from string")
|
||||
return false
|
||||
}
|
||||
return float64Num == key
|
||||
default:
|
||||
glog.Warningf("Expected float, found: %T\n", value)
|
||||
eh.log.Info("Expected type float", "value", value, "type", fmt.Sprintf("%T", value))
|
||||
return false
|
||||
}
|
||||
return false
|
||||
|
@ -119,7 +123,7 @@ func (eh EqualHandler) validateValuewithFloatPattern(key float64, value interfac
|
|||
func (eh EqualHandler) validateValuewithBoolPattern(key bool, value interface{}) bool {
|
||||
typedValue, ok := value.(bool)
|
||||
if !ok {
|
||||
glog.Error("Expected bool, found %V", value)
|
||||
eh.log.Info("Expected type bool", "value", value, "type", fmt.Sprintf("%T", value))
|
||||
return false
|
||||
}
|
||||
return key == typedValue
|
||||
|
@ -136,18 +140,18 @@ func (eh EqualHandler) validateValuewithIntPattern(key int64, value interface{})
|
|||
if typedValue == math.Trunc(typedValue) {
|
||||
return int64(typedValue) == key
|
||||
}
|
||||
glog.Warningf("Expected int, found float: %f", typedValue)
|
||||
eh.log.Info("Expected type int, found float", "value", typedValue, "type", fmt.Sprintf("%T", typedValue))
|
||||
return false
|
||||
case string:
|
||||
// extract in64 from string
|
||||
int64Num, err := strconv.ParseInt(typedValue, 10, 64)
|
||||
if err != nil {
|
||||
glog.Warningf("Failed to parse int64 from string: %v", err)
|
||||
eh.log.Error(err, "Failed to parse int64 from string")
|
||||
return false
|
||||
}
|
||||
return int64Num == key
|
||||
default:
|
||||
glog.Warningf("Expected int, %v is of type %T", value, value)
|
||||
eh.log.Info("Expected type int", "value", value, "type", fmt.Sprintf("%T", value))
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,19 +1,21 @@
|
|||
package operator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
"strconv"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/go-logr/logr"
|
||||
"github.com/nirmata/kyverno/pkg/engine/context"
|
||||
)
|
||||
|
||||
//NewNotEqualHandler returns handler to manage NotEqual operations
|
||||
func NewNotEqualHandler(ctx context.EvalInterface, subHandler VariableSubstitutionHandler) OperatorHandler {
|
||||
func NewNotEqualHandler(log logr.Logger, ctx context.EvalInterface, subHandler VariableSubstitutionHandler) OperatorHandler {
|
||||
return NotEqualHandler{
|
||||
ctx: ctx,
|
||||
subHandler: subHandler,
|
||||
log: log,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,6 +23,7 @@ func NewNotEqualHandler(ctx context.EvalInterface, subHandler VariableSubstituti
|
|||
type NotEqualHandler struct {
|
||||
ctx context.EvalInterface
|
||||
subHandler VariableSubstitutionHandler
|
||||
log logr.Logger
|
||||
}
|
||||
|
||||
//Evaluate evaluates expression with NotEqual Operator
|
||||
|
@ -28,14 +31,14 @@ func (neh NotEqualHandler) Evaluate(key, value interface{}) bool {
|
|||
var err error
|
||||
//TODO: decouple variables from evaluation
|
||||
// substitute the variables
|
||||
if key, err = neh.subHandler(neh.ctx, key); err != nil {
|
||||
if key, err = neh.subHandler(neh.log, neh.ctx, key); err != nil {
|
||||
// Failed to resolve the variable
|
||||
glog.Infof("Failed to resolve variables in key: %s: %v", key, err)
|
||||
neh.log.Error(err, "Failed to resolve variable", "variable", key)
|
||||
return false
|
||||
}
|
||||
if value, err = neh.subHandler(neh.ctx, value); err != nil {
|
||||
if value, err = neh.subHandler(neh.log, neh.ctx, value); err != nil {
|
||||
// Failed to resolve the variable
|
||||
glog.Infof("Failed to resolve variables in value: %s: %v", value, err)
|
||||
neh.log.Error(err, "Failed to resolve variable", "variable", value)
|
||||
return false
|
||||
}
|
||||
// key and value need to be of same type
|
||||
|
@ -55,7 +58,7 @@ func (neh NotEqualHandler) Evaluate(key, value interface{}) bool {
|
|||
case []interface{}:
|
||||
return neh.validateValueWithSlicePattern(typedKey, value)
|
||||
default:
|
||||
glog.Error("Unsupported type %V", typedKey)
|
||||
neh.log.Info("Unsupported type", "value", typedKey, "type", fmt.Sprintf("%T", typedKey))
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
@ -64,7 +67,7 @@ func (neh NotEqualHandler) validateValueWithSlicePattern(key []interface{}, valu
|
|||
if val, ok := value.([]interface{}); ok {
|
||||
return !reflect.DeepEqual(key, val)
|
||||
}
|
||||
glog.Warningf("Expected []interface{}, %v is of type %T", value, value)
|
||||
neh.log.Info("Expected type []interface{}", "value", value, "type", fmt.Sprintf("%T", value))
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -72,7 +75,7 @@ func (neh NotEqualHandler) validateValueWithMapPattern(key map[string]interface{
|
|||
if val, ok := value.(map[string]interface{}); ok {
|
||||
return !reflect.DeepEqual(key, val)
|
||||
}
|
||||
glog.Warningf("Expected map[string]interface{}, %v is of type %T", value, value)
|
||||
neh.log.Info("Expected type map[string]interface{}", "value", value, "type", fmt.Sprintf("%T", value))
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -80,7 +83,7 @@ func (neh NotEqualHandler) validateValuewithStringPattern(key string, value inte
|
|||
if val, ok := value.(string); ok {
|
||||
return key != val
|
||||
}
|
||||
glog.Warningf("Expected string, %v is of type %T", value, value)
|
||||
neh.log.Info("Expected type string", "value", value, "type", fmt.Sprintf("%T", value))
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -91,25 +94,25 @@ func (neh NotEqualHandler) validateValuewithFloatPattern(key float64, value inte
|
|||
if key == math.Trunc(key) {
|
||||
return int(key) != typedValue
|
||||
}
|
||||
glog.Warningf("Expected float, found int: %d\n", typedValue)
|
||||
neh.log.Info("Expected type float, found int", "typedValue", typedValue)
|
||||
case int64:
|
||||
// check that float has not fraction
|
||||
if key == math.Trunc(key) {
|
||||
return int64(key) != typedValue
|
||||
}
|
||||
glog.Warningf("Expected float, found int: %d\n", typedValue)
|
||||
neh.log.Info("Expected type float, found int", "typedValue", typedValue)
|
||||
case float64:
|
||||
return typedValue != key
|
||||
case string:
|
||||
// extract float from string
|
||||
float64Num, err := strconv.ParseFloat(typedValue, 64)
|
||||
if err != nil {
|
||||
glog.Warningf("Failed to parse float64 from string: %v", err)
|
||||
neh.log.Error(err, "Failed to parse float64 from string")
|
||||
return false
|
||||
}
|
||||
return float64Num != key
|
||||
default:
|
||||
glog.Warningf("Expected float, found: %T\n", value)
|
||||
neh.log.Info("Expected type float", "value", value, "type", fmt.Sprintf("%T", value))
|
||||
return false
|
||||
}
|
||||
return false
|
||||
|
@ -118,7 +121,7 @@ func (neh NotEqualHandler) validateValuewithFloatPattern(key float64, value inte
|
|||
func (neh NotEqualHandler) validateValuewithBoolPattern(key bool, value interface{}) bool {
|
||||
typedValue, ok := value.(bool)
|
||||
if !ok {
|
||||
glog.Error("Expected bool, found %V", value)
|
||||
neh.log.Info("Expected type bool", "value", value, "type", fmt.Sprintf("%T", value))
|
||||
return false
|
||||
}
|
||||
return key != typedValue
|
||||
|
@ -135,18 +138,18 @@ func (neh NotEqualHandler) validateValuewithIntPattern(key int64, value interfac
|
|||
if typedValue == math.Trunc(typedValue) {
|
||||
return int64(typedValue) != key
|
||||
}
|
||||
glog.Warningf("Expected int, found float: %f\n", typedValue)
|
||||
neh.log.Info("Expected type int, found float", "value", typedValue, "type", fmt.Sprintf("%T", typedValue))
|
||||
return false
|
||||
case string:
|
||||
// extract in64 from string
|
||||
int64Num, err := strconv.ParseInt(typedValue, 10, 64)
|
||||
if err != nil {
|
||||
glog.Warningf("Failed to parse int64 from string: %v", err)
|
||||
neh.log.Error(err, "Failed to parse int64 from string")
|
||||
return false
|
||||
}
|
||||
return int64Num != key
|
||||
default:
|
||||
glog.Warningf("Expected int, %v is of type %T", value, value)
|
||||
neh.log.Info("Expected type int", "value", value, "type", fmt.Sprintf("%T", value))
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package operator
|
||||
|
||||
import (
|
||||
"github.com/golang/glog"
|
||||
"github.com/go-logr/logr"
|
||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||
"github.com/nirmata/kyverno/pkg/engine/context"
|
||||
)
|
||||
|
@ -17,17 +17,17 @@ type OperatorHandler interface {
|
|||
}
|
||||
|
||||
//VariableSubstitutionHandler defines the handler function for variable substitution
|
||||
type VariableSubstitutionHandler = func(ctx context.EvalInterface, pattern interface{}) (interface{}, error)
|
||||
type VariableSubstitutionHandler = func(log logr.Logger, ctx context.EvalInterface, pattern interface{}) (interface{}, error)
|
||||
|
||||
//CreateOperatorHandler returns the operator handler based on the operator used in condition
|
||||
func CreateOperatorHandler(ctx context.EvalInterface, op kyverno.ConditionOperator, subHandler VariableSubstitutionHandler) OperatorHandler {
|
||||
func CreateOperatorHandler(log logr.Logger, ctx context.EvalInterface, op kyverno.ConditionOperator, subHandler VariableSubstitutionHandler) OperatorHandler {
|
||||
switch op {
|
||||
case kyverno.Equal:
|
||||
return NewEqualHandler(ctx, subHandler)
|
||||
return NewEqualHandler(log, ctx, subHandler)
|
||||
case kyverno.NotEqual:
|
||||
return NewNotEqualHandler(ctx, subHandler)
|
||||
return NewNotEqualHandler(log, ctx, subHandler)
|
||||
default:
|
||||
glog.Errorf("unsupported operator: %s", string(op))
|
||||
log.Info("operator not supported", "operator", string(op))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
|
||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||
authenticationv1 "k8s.io/api/authentication/v1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
|
||||
"github.com/nirmata/kyverno/pkg/engine/context"
|
||||
)
|
||||
|
@ -84,7 +85,7 @@ func Test_variablesub1(t *testing.T) {
|
|||
t.Error(err)
|
||||
}
|
||||
|
||||
if _, err := SubstituteVars(ctx, patternCopy); err != nil {
|
||||
if _, err := SubstituteVars(log.Log, ctx, patternCopy); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
resultRaw, err := json.Marshal(patternCopy)
|
||||
|
@ -174,7 +175,7 @@ func Test_variablesub_multiple(t *testing.T) {
|
|||
t.Error(err)
|
||||
}
|
||||
|
||||
if _, err := SubstituteVars(ctx, patternCopy); err != nil {
|
||||
if _, err := SubstituteVars(log.Log, ctx, patternCopy); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
resultRaw, err := json.Marshal(patternCopy)
|
||||
|
@ -261,7 +262,7 @@ func Test_variablesubstitution(t *testing.T) {
|
|||
t.Error(err)
|
||||
}
|
||||
|
||||
if _, err := SubstituteVars(ctx, patternCopy); err != nil {
|
||||
if _, err := SubstituteVars(log.Log, ctx, patternCopy); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
resultRaw, err := json.Marshal(patternCopy)
|
||||
|
@ -322,7 +323,7 @@ func Test_variableSubstitutionValue(t *testing.T) {
|
|||
t.Error(err)
|
||||
}
|
||||
|
||||
if _, err := SubstituteVars(ctx, patternCopy); err != nil {
|
||||
if _, err := SubstituteVars(log.Log, ctx, patternCopy); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
resultRaw, err := json.Marshal(patternCopy)
|
||||
|
@ -380,7 +381,7 @@ func Test_variableSubstitutionValueOperatorNotEqual(t *testing.T) {
|
|||
t.Error(err)
|
||||
}
|
||||
|
||||
if _, err := SubstituteVars(ctx, patternCopy); err != nil {
|
||||
if _, err := SubstituteVars(log.Log, ctx, patternCopy); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
resultRaw, err := json.Marshal(patternCopy)
|
||||
|
@ -439,7 +440,7 @@ func Test_variableSubstitutionValueFail(t *testing.T) {
|
|||
t.Error(err)
|
||||
}
|
||||
|
||||
if _, err := SubstituteVars(ctx, patternCopy); err == nil {
|
||||
if _, err := SubstituteVars(log.Log, ctx, patternCopy); err == nil {
|
||||
t.Log("expected to fails")
|
||||
t.Fail()
|
||||
}
|
||||
|
@ -497,7 +498,7 @@ func Test_variableSubstitutionObject(t *testing.T) {
|
|||
t.Error(err)
|
||||
}
|
||||
|
||||
if _, err := SubstituteVars(ctx, patternCopy); err != nil {
|
||||
if _, err := SubstituteVars(log.Log, ctx, patternCopy); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
resultRaw, err := json.Marshal(patternCopy)
|
||||
|
@ -561,7 +562,7 @@ func Test_variableSubstitutionObjectOperatorNotEqualFail(t *testing.T) {
|
|||
t.Error(err)
|
||||
}
|
||||
|
||||
if _, err := SubstituteVars(ctx, patternCopy); err == nil {
|
||||
if _, err := SubstituteVars(log.Log, ctx, patternCopy); err == nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
|
@ -620,7 +621,7 @@ func Test_variableSubstitutionMultipleObject(t *testing.T) {
|
|||
t.Error(err)
|
||||
}
|
||||
|
||||
if _, err := SubstituteVars(ctx, patternCopy); err != nil {
|
||||
if _, err := SubstituteVars(log.Log, ctx, patternCopy); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
resultRaw, err := json.Marshal(patternCopy)
|
||||
|
|
|
@ -6,7 +6,7 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/go-logr/logr"
|
||||
"github.com/nirmata/kyverno/pkg/engine/context"
|
||||
)
|
||||
|
||||
|
@ -17,9 +17,9 @@ const (
|
|||
|
||||
//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
|
||||
func SubstituteVars(ctx context.EvalInterface, pattern interface{}) (interface{}, error) {
|
||||
func SubstituteVars(log logr.Logger, ctx context.EvalInterface, pattern interface{}) (interface{}, error) {
|
||||
errs := []error{}
|
||||
pattern = subVars(ctx, pattern, "", &errs)
|
||||
pattern = subVars(log, ctx, pattern, "", &errs)
|
||||
if len(errs) == 0 {
|
||||
// no error while parsing the pattern
|
||||
return pattern, nil
|
||||
|
@ -27,40 +27,40 @@ func SubstituteVars(ctx context.EvalInterface, pattern interface{}) (interface{}
|
|||
return pattern, fmt.Errorf("%v", errs)
|
||||
}
|
||||
|
||||
func subVars(ctx context.EvalInterface, pattern interface{}, path string, errs *[]error) interface{} {
|
||||
func subVars(log logr.Logger, ctx context.EvalInterface, pattern interface{}, path string, errs *[]error) interface{} {
|
||||
switch typedPattern := pattern.(type) {
|
||||
case map[string]interface{}:
|
||||
return subMap(ctx, typedPattern, path, errs)
|
||||
return subMap(log, ctx, typedPattern, path, errs)
|
||||
case []interface{}:
|
||||
return subArray(ctx, typedPattern, path, errs)
|
||||
return subArray(log, ctx, typedPattern, path, errs)
|
||||
case string:
|
||||
return subValR(ctx, typedPattern, path, errs)
|
||||
return subValR(log, ctx, typedPattern, path, errs)
|
||||
default:
|
||||
return pattern
|
||||
}
|
||||
}
|
||||
|
||||
func subMap(ctx context.EvalInterface, patternMap map[string]interface{}, path string, errs *[]error) map[string]interface{} {
|
||||
func subMap(log logr.Logger, ctx context.EvalInterface, patternMap map[string]interface{}, path string, errs *[]error) map[string]interface{} {
|
||||
for key, patternElement := range patternMap {
|
||||
curPath := path + "/" + key
|
||||
value := subVars(ctx, patternElement, curPath, errs)
|
||||
value := subVars(log, ctx, patternElement, curPath, errs)
|
||||
patternMap[key] = value
|
||||
|
||||
}
|
||||
return patternMap
|
||||
}
|
||||
|
||||
func subArray(ctx context.EvalInterface, patternList []interface{}, path string, errs *[]error) []interface{} {
|
||||
func subArray(log logr.Logger, ctx context.EvalInterface, patternList []interface{}, path string, errs *[]error) []interface{} {
|
||||
for idx, patternElement := range patternList {
|
||||
curPath := path + "/" + strconv.Itoa(idx)
|
||||
value := subVars(ctx, patternElement, curPath, errs)
|
||||
value := subVars(log, ctx, patternElement, curPath, errs)
|
||||
patternList[idx] = value
|
||||
}
|
||||
return patternList
|
||||
}
|
||||
|
||||
// subValR resolves the variables if defined
|
||||
func subValR(ctx context.EvalInterface, valuePattern string, path string, errs *[]error) interface{} {
|
||||
func subValR(log logr.Logger, 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}}
|
||||
|
@ -73,7 +73,7 @@ func subValR(ctx context.EvalInterface, valuePattern string, path string, errs *
|
|||
// since this might be a potential place for error, required better error reporting and handling
|
||||
|
||||
// object values are only suported for single variable substitution
|
||||
if ok, retVal := processIfSingleVariable(ctx, valuePattern, path, errs); ok {
|
||||
if ok, retVal := processIfSingleVariable(log, ctx, valuePattern, path, errs); ok {
|
||||
return retVal
|
||||
}
|
||||
// var emptyInterface interface{}
|
||||
|
@ -82,7 +82,7 @@ func subValR(ctx context.EvalInterface, valuePattern string, path string, errs *
|
|||
for {
|
||||
valueStr := valuePattern
|
||||
if len(failedVars) != 0 {
|
||||
glog.Info("some failed variables short-circuiting")
|
||||
log.Info("failed to resolve variablesl short-circuiting")
|
||||
break
|
||||
}
|
||||
// get variables at this level
|
||||
|
@ -123,7 +123,7 @@ func subValR(ctx context.EvalInterface, valuePattern string, path string, errs *
|
|||
continue
|
||||
}
|
||||
// if type is not scalar then consider this as a failed variable
|
||||
glog.Infof("variable %s resolves to non-scalar value %v. Non-Scalar values are not supported for nested variables", k, v)
|
||||
log.Info("variable resolves to non-scalar value. Non-Scalar values are not supported for nested variables", "variable", k, "value", v)
|
||||
failedVars = append(failedVars, k)
|
||||
}
|
||||
valuePattern = newVal
|
||||
|
@ -143,10 +143,10 @@ func subValR(ctx context.EvalInterface, valuePattern string, path string, errs *
|
|||
// if the value can be evaluted return the value
|
||||
// -> 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
|
||||
func processIfSingleVariable(ctx context.EvalInterface, valuePattern interface{}, path string, errs *[]error) (bool, interface{}) {
|
||||
func processIfSingleVariable(log logr.Logger, ctx context.EvalInterface, valuePattern interface{}, path string, errs *[]error) (bool, interface{}) {
|
||||
valueStr, ok := valuePattern.(string)
|
||||
if !ok {
|
||||
glog.Infof("failed to convert %v to string", valuePattern)
|
||||
log.Info("failed to convert to string", "pattern", valuePattern)
|
||||
return false, nil
|
||||
}
|
||||
// get variables at this level
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
|
||||
"github.com/nirmata/kyverno/pkg/engine/context"
|
||||
"gotest.tools/assert"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
)
|
||||
|
||||
func Test_subVars_success(t *testing.T) {
|
||||
|
@ -64,7 +65,7 @@ func Test_subVars_success(t *testing.T) {
|
|||
t.Error(err)
|
||||
}
|
||||
|
||||
if _, err := SubstituteVars(ctx, pattern); err != nil {
|
||||
if _, err := SubstituteVars(log.Log, ctx, pattern); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
@ -125,7 +126,7 @@ func Test_subVars_failed(t *testing.T) {
|
|||
t.Error(err)
|
||||
}
|
||||
|
||||
if _, err := SubstituteVars(ctx, pattern); err == nil {
|
||||
if _, err := SubstituteVars(log.Log, ctx, pattern); err == nil {
|
||||
t.Error("error is expected")
|
||||
}
|
||||
}
|
||||
|
@ -152,5 +153,5 @@ func Test_SubvarRecursive(t *testing.T) {
|
|||
ctx := context.NewContext()
|
||||
assert.Assert(t, ctx.AddResource(resourceRaw))
|
||||
errs := []error{}
|
||||
subValR(ctx, string(patternRaw), "/", &errs)
|
||||
subValR(log.Log, ctx, string(patternRaw), "/", &errs)
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ package event
|
|||
import (
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/go-logr/logr"
|
||||
|
||||
"github.com/nirmata/kyverno/pkg/client/clientset/versioned/scheme"
|
||||
kyvernoinformer "github.com/nirmata/kyverno/pkg/client/informers/externalversions/kyverno/v1"
|
||||
|
@ -17,6 +17,7 @@ import (
|
|||
"k8s.io/client-go/tools/cache"
|
||||
"k8s.io/client-go/tools/record"
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
//Generator generate events
|
||||
|
@ -34,6 +35,7 @@ type Generator struct {
|
|||
admissionCtrRecorder record.EventRecorder
|
||||
// events generated at namespaced policy controller to process 'generate' rule
|
||||
genPolicyRecorder record.EventRecorder
|
||||
log logr.Logger
|
||||
}
|
||||
|
||||
//Interface to generate event
|
||||
|
@ -42,32 +44,33 @@ type Interface interface {
|
|||
}
|
||||
|
||||
//NewEventGenerator to generate a new event controller
|
||||
func NewEventGenerator(client *client.Client, pInformer kyvernoinformer.ClusterPolicyInformer) *Generator {
|
||||
func NewEventGenerator(client *client.Client, pInformer kyvernoinformer.ClusterPolicyInformer, log logr.Logger) *Generator {
|
||||
|
||||
gen := Generator{
|
||||
client: client,
|
||||
pLister: pInformer.Lister(),
|
||||
queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), eventWorkQueueName),
|
||||
pSynced: pInformer.Informer().HasSynced,
|
||||
policyCtrRecorder: initRecorder(client, PolicyController),
|
||||
admissionCtrRecorder: initRecorder(client, AdmissionController),
|
||||
genPolicyRecorder: initRecorder(client, GeneratePolicyController),
|
||||
policyCtrRecorder: initRecorder(client, PolicyController, log),
|
||||
admissionCtrRecorder: initRecorder(client, AdmissionController, log),
|
||||
genPolicyRecorder: initRecorder(client, GeneratePolicyController, log),
|
||||
log: log,
|
||||
}
|
||||
return &gen
|
||||
}
|
||||
|
||||
func initRecorder(client *client.Client, eventSource Source) record.EventRecorder {
|
||||
func initRecorder(client *client.Client, eventSource Source, log logr.Logger) record.EventRecorder {
|
||||
// Initliaze Event Broadcaster
|
||||
err := scheme.AddToScheme(scheme.Scheme)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
log.Error(err, "failed to add to scheme")
|
||||
return nil
|
||||
}
|
||||
eventBroadcaster := record.NewBroadcaster()
|
||||
eventBroadcaster.StartLogging(glog.V(4).Infof)
|
||||
eventBroadcaster.StartLogging(klog.Infof)
|
||||
eventInterface, err := client.GetEventsInterface()
|
||||
if err != nil {
|
||||
glog.Error(err) // TODO: add more specific error
|
||||
log.Error(err, "failed to get event interface for logging")
|
||||
return nil
|
||||
}
|
||||
eventBroadcaster.StartRecordingToSink(
|
||||
|
@ -81,11 +84,12 @@ func initRecorder(client *client.Client, eventSource Source) record.EventRecorde
|
|||
|
||||
//Add queues an event for generation
|
||||
func (gen *Generator) Add(infos ...Info) {
|
||||
logger := gen.log
|
||||
for _, info := range infos {
|
||||
if info.Name == "" {
|
||||
// dont create event for resources with generateName
|
||||
// as the name is not generated yet
|
||||
glog.V(4).Infof("received info %v, not creating an event as the resource has not been assigned a name yet", info)
|
||||
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)
|
||||
continue
|
||||
}
|
||||
gen.queue.Add(info)
|
||||
|
@ -94,12 +98,14 @@ func (gen *Generator) Add(infos ...Info) {
|
|||
|
||||
// Run begins generator
|
||||
func (gen *Generator) Run(workers int, stopCh <-chan struct{}) {
|
||||
logger := gen.log
|
||||
defer utilruntime.HandleCrash()
|
||||
glog.Info("Starting event generator")
|
||||
defer glog.Info("Shutting down event generator")
|
||||
|
||||
logger.Info("start")
|
||||
defer logger.Info("shutting down")
|
||||
|
||||
if !cache.WaitForCacheSync(stopCh, gen.pSynced) {
|
||||
glog.Error("event generator: failed to sync informer cache")
|
||||
logger.Info("failed to sync informer cache")
|
||||
}
|
||||
|
||||
for i := 0; i < workers; i++ {
|
||||
|
@ -114,24 +120,25 @@ func (gen *Generator) runWorker() {
|
|||
}
|
||||
|
||||
func (gen *Generator) handleErr(err error, key interface{}) {
|
||||
logger := gen.log
|
||||
if err == nil {
|
||||
gen.queue.Forget(key)
|
||||
return
|
||||
}
|
||||
// This controller retries if something goes wrong. After that, it stops trying.
|
||||
if gen.queue.NumRequeues(key) < workQueueRetryLimit {
|
||||
glog.Warningf("Error syncing events %v(re-queuing request, the resource might not have been created yet): %v", key, err)
|
||||
logger.Error(err, "Error syncing events;re-queuing request,the resource might not have been created yet", "key", key)
|
||||
// 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.
|
||||
gen.queue.AddRateLimited(key)
|
||||
return
|
||||
}
|
||||
gen.queue.Forget(key)
|
||||
glog.Error(err)
|
||||
glog.Warningf("Dropping the key out of the queue: %v", err)
|
||||
logger.Error(err, "dropping the key out of queue", "key", key)
|
||||
}
|
||||
|
||||
func (gen *Generator) processNextWorkItem() bool {
|
||||
logger := gen.log
|
||||
obj, shutdown := gen.queue.Get()
|
||||
if shutdown {
|
||||
return false
|
||||
|
@ -144,7 +151,7 @@ func (gen *Generator) processNextWorkItem() bool {
|
|||
|
||||
if key, ok = obj.(Info); !ok {
|
||||
gen.queue.Forget(obj)
|
||||
glog.Warningf("Expecting type info by got %v\n", obj)
|
||||
logger.Info("Incorrect type; expected type 'info'", "obj", obj)
|
||||
return nil
|
||||
}
|
||||
err := gen.syncHandler(key)
|
||||
|
@ -152,13 +159,14 @@ func (gen *Generator) processNextWorkItem() bool {
|
|||
return nil
|
||||
}(obj)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
logger.Error(err, "failed to process next work item")
|
||||
return true
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (gen *Generator) syncHandler(key Info) error {
|
||||
logger := gen.log
|
||||
var robj runtime.Object
|
||||
var err error
|
||||
switch key.Kind {
|
||||
|
@ -166,13 +174,13 @@ func (gen *Generator) syncHandler(key Info) error {
|
|||
//TODO: policy is clustered resource so wont need namespace
|
||||
robj, err = gen.pLister.Get(key.Name)
|
||||
if err != nil {
|
||||
glog.V(4).Infof("Error creating event: unable to get policy %s, will retry ", key.Name)
|
||||
logger.Error(err, "failed to get policy", "name", key.Name)
|
||||
return err
|
||||
}
|
||||
default:
|
||||
robj, err = gen.client.GetResource(key.Kind, key.Namespace, key.Name)
|
||||
if err != nil {
|
||||
glog.V(4).Infof("Error creating event: unable to get resource %s/%s/%s, will retry ", key.Kind, key.Namespace, key.Name)
|
||||
logger.Error(err, "failed to get resource", "kind", key.Kind, "name", key.Name, "namespace", key.Namespace)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -192,13 +200,14 @@ func (gen *Generator) syncHandler(key Info) error {
|
|||
case GeneratePolicyController:
|
||||
gen.genPolicyRecorder.Event(robj, eventType, key.Reason, key.Message)
|
||||
default:
|
||||
glog.Info("info.source not defined for the event generator request")
|
||||
logger.Info("info.source not defined for the request")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//NewEvent builds a event creation request
|
||||
func NewEvent(
|
||||
log logr.Logger,
|
||||
rkind,
|
||||
rapiVersion,
|
||||
rnamespace,
|
||||
|
@ -209,7 +218,7 @@ func NewEvent(
|
|||
args ...interface{}) Info {
|
||||
msgText, err := getEventMsg(message, args...)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
log.Error(err, "failed to get event message")
|
||||
}
|
||||
return Info{
|
||||
Kind: rkind,
|
||||
|
|
|
@ -1,19 +1,20 @@
|
|||
package cleanup
|
||||
|
||||
import (
|
||||
"github.com/golang/glog"
|
||||
"github.com/go-logr/logr"
|
||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||
dclient "github.com/nirmata/kyverno/pkg/dclient"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
)
|
||||
|
||||
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
|
||||
// then we dont delete the generated resources
|
||||
|
||||
// 2- The trigger resource is deleted, then delete the generated resources
|
||||
if !ownerResourceExists(c.client, gr) {
|
||||
if err := deleteGeneratedResources(c.client, gr); err != nil {
|
||||
if !ownerResourceExists(logger, c.client, gr) {
|
||||
if err := deleteGeneratedResources(logger, c.client, gr); err != nil {
|
||||
return err
|
||||
}
|
||||
// - trigger-resource is deleted
|
||||
|
@ -24,25 +25,25 @@ func (c *Controller) processGR(gr kyverno.GenerateRequest) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func ownerResourceExists(client *dclient.Client, gr kyverno.GenerateRequest) bool {
|
||||
func ownerResourceExists(log logr.Logger, client *dclient.Client, gr kyverno.GenerateRequest) bool {
|
||||
_, err := client.GetResource(gr.Spec.Resource.Kind, gr.Spec.Resource.Namespace, gr.Spec.Resource.Name)
|
||||
// trigger resources has been deleted
|
||||
if apierrors.IsNotFound(err) {
|
||||
return false
|
||||
}
|
||||
if err != nil {
|
||||
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)
|
||||
log.Error(err, "failed to get resource", "genKind", gr.Spec.Resource.Kind, "genNamespace", gr.Spec.Resource.Namespace, "genName", gr.Spec.Resource.Name)
|
||||
}
|
||||
// if there was an error while querying the resources we dont delete the generated resources
|
||||
// but expect the deletion in next reconciliation loop
|
||||
return true
|
||||
}
|
||||
|
||||
func deleteGeneratedResources(client *dclient.Client, gr kyverno.GenerateRequest) error {
|
||||
func deleteGeneratedResources(log logr.Logger, client *dclient.Client, gr kyverno.GenerateRequest) error {
|
||||
for _, genResource := range gr.Status.GeneratedResources {
|
||||
err := client.DeleteResource(genResource.Kind, genResource.Namespace, genResource.Name, false)
|
||||
if apierrors.IsNotFound(err) {
|
||||
glog.V(4).Infof("resource %s/%s/%s not found, will no delete", genResource.Kind, genResource.Namespace, genResource.Name)
|
||||
log.Error(err, "resource not foundl will not delete", "genKind", gr.Spec.Resource.Kind, "genNamespace", gr.Spec.Resource.Namespace, "genName", gr.Spec.Resource.Name)
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
package cleanup
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||
kyvernoclient "github.com/nirmata/kyverno/pkg/client/clientset/versioned"
|
||||
kyvernoinformer "github.com/nirmata/kyverno/pkg/client/informers/externalversions/kyverno/v1"
|
||||
|
@ -53,6 +51,7 @@ type Controller struct {
|
|||
//TODO: list of generic informers
|
||||
// only support Namespaces for deletion of resource
|
||||
nsInformer informers.GenericInformer
|
||||
log logr.Logger
|
||||
}
|
||||
|
||||
//NewController returns a new controller instance to manage generate-requests
|
||||
|
@ -62,6 +61,7 @@ func NewController(
|
|||
pInformer kyvernoinformer.ClusterPolicyInformer,
|
||||
grInformer kyvernoinformer.GenerateRequestInformer,
|
||||
dynamicInformer dynamicinformer.DynamicSharedInformerFactory,
|
||||
log logr.Logger,
|
||||
) *Controller {
|
||||
c := Controller{
|
||||
kyvernoClient: kyvernoclient,
|
||||
|
@ -70,6 +70,7 @@ func NewController(
|
|||
// as we dont want a deleted GR to be re-queue
|
||||
queue: workqueue.NewNamedRateLimitingQueue(workqueue.NewItemExponentialFailureRateLimiter(1, 30), "generate-request-cleanup"),
|
||||
dynamicInformer: dynamicInformer,
|
||||
log: log,
|
||||
}
|
||||
c.control = Control{client: kyvernoclient}
|
||||
c.enqueueGR = c.enqueue
|
||||
|
@ -102,10 +103,11 @@ func NewController(
|
|||
}
|
||||
|
||||
func (c *Controller) deleteGenericResource(obj interface{}) {
|
||||
logger := c.log
|
||||
r := obj.(*unstructured.Unstructured)
|
||||
grs, err := c.grLister.GetGenerateRequestsForResource(r.GetKind(), r.GetNamespace(), r.GetName())
|
||||
if err != nil {
|
||||
glog.Errorf("failed to Generate Requests for resource %s/%s/%s: %v", r.GetKind(), r.GetNamespace(), r.GetName(), err)
|
||||
logger.Error(err, "failed to get generate request CR for resource", "kind", r.GetKind(), "namespace", r.GetNamespace(), "name", r.GetName())
|
||||
return
|
||||
}
|
||||
// re-evaluate the GR as the resource was deleted
|
||||
|
@ -115,26 +117,27 @@ func (c *Controller) deleteGenericResource(obj interface{}) {
|
|||
}
|
||||
|
||||
func (c *Controller) deletePolicy(obj interface{}) {
|
||||
logger := c.log
|
||||
p, ok := obj.(*kyverno.ClusterPolicy)
|
||||
if !ok {
|
||||
tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
|
||||
if !ok {
|
||||
glog.Info(fmt.Errorf("Couldn't get object from tombstone %#v", obj))
|
||||
logger.Info("ouldn't get object from tombstone", "obj", obj)
|
||||
return
|
||||
}
|
||||
_, ok = tombstone.Obj.(*kyverno.ClusterPolicy)
|
||||
if !ok {
|
||||
glog.Info(fmt.Errorf("Tombstone contained object that is not a Generate Request %#v", obj))
|
||||
logger.Info("Tombstone contained object that is not a Generate Request", "obj", obj)
|
||||
return
|
||||
}
|
||||
}
|
||||
glog.V(4).Infof("Deleting Policy %s", p.Name)
|
||||
logger.V(4).Info("deleting policy", "name", p.Name)
|
||||
// clean up the GR
|
||||
// Get the corresponding GR
|
||||
// get the list of GR for the current Policy version
|
||||
grs, err := c.grLister.GetGenerateRequestsForClusterPolicy(p.Name)
|
||||
if err != nil {
|
||||
glog.Errorf("failed to Generate Requests for policy %s: %v", p.Name, err)
|
||||
logger.Error(err, "failed to generate request CR for the policy", "name", p.Name)
|
||||
return
|
||||
}
|
||||
for _, gr := range grs {
|
||||
|
@ -153,44 +156,46 @@ func (c *Controller) updateGR(old, cur interface{}) {
|
|||
}
|
||||
|
||||
func (c *Controller) deleteGR(obj interface{}) {
|
||||
logger := c.log
|
||||
gr, ok := obj.(*kyverno.GenerateRequest)
|
||||
if !ok {
|
||||
tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
|
||||
if !ok {
|
||||
glog.Info(fmt.Errorf("Couldn't get object from tombstone %#v", obj))
|
||||
logger.Info("Couldn't get object from tombstone", "obj", obj)
|
||||
return
|
||||
}
|
||||
_, ok = tombstone.Obj.(*kyverno.GenerateRequest)
|
||||
if !ok {
|
||||
glog.Info(fmt.Errorf("Tombstone contained object that is not a Generate Request %#v", obj))
|
||||
logger.Info("ombstone contained object that is not a Generate Request", "obj", obj)
|
||||
return
|
||||
}
|
||||
}
|
||||
glog.V(4).Infof("Deleting GR %s", gr.Name)
|
||||
logger.V(4).Info("deleting Generate Request CR", "name", gr.Name)
|
||||
// sync Handler will remove it from the queue
|
||||
c.enqueueGR(gr)
|
||||
}
|
||||
|
||||
func (c *Controller) enqueue(gr *kyverno.GenerateRequest) {
|
||||
logger := c.log
|
||||
key, err := cache.MetaNamespaceKeyFunc(gr)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
logger.Error(err, "failed to extract key")
|
||||
return
|
||||
}
|
||||
glog.V(4).Infof("cleanup enqueu: %v", gr.Name)
|
||||
logger.V(4).Info("eneque generate request", "name", gr.Name)
|
||||
c.queue.Add(key)
|
||||
}
|
||||
|
||||
//Run starts the generate-request re-conciliation loop
|
||||
func (c *Controller) Run(workers int, stopCh <-chan struct{}) {
|
||||
logger := c.log
|
||||
defer utilruntime.HandleCrash()
|
||||
defer c.queue.ShutDown()
|
||||
|
||||
glog.Info("Starting generate-policy-cleanup controller")
|
||||
defer glog.Info("Shutting down generate-policy-cleanup controller")
|
||||
logger.Info("starting")
|
||||
defer logger.Info("shutting down")
|
||||
|
||||
if !cache.WaitForCacheSync(stopCh, c.pSynced, c.grSynced) {
|
||||
glog.Error("generate-policy-cleanup controller: failed to sync informer cache")
|
||||
logger.Info("failed to sync informer cache")
|
||||
return
|
||||
}
|
||||
for i := 0; i < workers; i++ {
|
||||
|
@ -219,31 +224,33 @@ func (c *Controller) processNextWorkItem() bool {
|
|||
}
|
||||
|
||||
func (c *Controller) handleErr(err error, key interface{}) {
|
||||
logger := c.log
|
||||
if err == nil {
|
||||
c.queue.Forget(key)
|
||||
return
|
||||
}
|
||||
|
||||
if c.queue.NumRequeues(key) < maxRetries {
|
||||
glog.Errorf("Error syncing Generate Request %v: %v", key, err)
|
||||
logger.Error(err, "failed to sync generate request", "key", key)
|
||||
c.queue.AddRateLimited(key)
|
||||
return
|
||||
}
|
||||
utilruntime.HandleError(err)
|
||||
glog.Infof("Dropping generate request %q out of the queue: %v", key, err)
|
||||
logger.Error(err, "dropping generate request out of the queue", "key", key)
|
||||
c.queue.Forget(key)
|
||||
}
|
||||
|
||||
func (c *Controller) syncGenerateRequest(key string) error {
|
||||
logger := c.log.WithValues("key", key)
|
||||
var err error
|
||||
startTime := time.Now()
|
||||
glog.V(4).Infof("Started syncing GR %q (%v)", key, startTime)
|
||||
logger.Info("started syncing generate request", "startTime", startTime)
|
||||
defer func() {
|
||||
glog.V(4).Infof("Finished syncing GR %q (%v)", key, time.Since(startTime))
|
||||
logger.V(4).Info("finished syncying generate request", "processingTIme", time.Since(startTime))
|
||||
}()
|
||||
_, grName, err := cache.SplitMetaNamespaceKey(key)
|
||||
if errors.IsNotFound(err) {
|
||||
glog.Infof("Generate Request %s has been deleted", key)
|
||||
logger.Info("generate request has been deleted")
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
package generate
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/go-logr/logr"
|
||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||
kyvernoclient "github.com/nirmata/kyverno/pkg/client/clientset/versioned"
|
||||
kyvernoinformer "github.com/nirmata/kyverno/pkg/client/informers/externalversions/kyverno/v1"
|
||||
|
@ -57,9 +56,9 @@ type Controller struct {
|
|||
dynamicInformer dynamicinformer.DynamicSharedInformerFactory
|
||||
//TODO: list of generic informers
|
||||
// only support Namespaces for re-evalutation on resource updates
|
||||
nsInformer informers.GenericInformer
|
||||
|
||||
nsInformer informers.GenericInformer
|
||||
policyStatusListener policystatus.Listener
|
||||
log logr.Logger
|
||||
}
|
||||
|
||||
//NewController returns an instance of the Generate-Request Controller
|
||||
|
@ -72,6 +71,7 @@ func NewController(
|
|||
pvGenerator policyviolation.GeneratorInterface,
|
||||
dynamicInformer dynamicinformer.DynamicSharedInformerFactory,
|
||||
policyStatus policystatus.Listener,
|
||||
log logr.Logger,
|
||||
) *Controller {
|
||||
c := Controller{
|
||||
client: client,
|
||||
|
@ -82,6 +82,7 @@ func NewController(
|
|||
// as we dont want a deleted GR to be re-queue
|
||||
queue: workqueue.NewNamedRateLimitingQueue(workqueue.NewItemExponentialFailureRateLimiter(1, 30), "generate-request"),
|
||||
dynamicInformer: dynamicInformer,
|
||||
log: log,
|
||||
policyStatusListener: policyStatus,
|
||||
}
|
||||
c.statusControl = StatusControl{client: kyvernoclient}
|
||||
|
@ -117,11 +118,12 @@ func NewController(
|
|||
}
|
||||
|
||||
func (c *Controller) updateGenericResource(old, cur interface{}) {
|
||||
logger := c.log
|
||||
curR := cur.(*unstructured.Unstructured)
|
||||
|
||||
grs, err := c.grLister.GetGenerateRequestsForResource(curR.GetKind(), curR.GetNamespace(), curR.GetName())
|
||||
if err != nil {
|
||||
glog.Errorf("failed to Generate Requests for resource %s/%s/%s: %v", curR.GetKind(), curR.GetNamespace(), curR.GetName(), err)
|
||||
logger.Error(err, "failed to get generate request CR for the resoource", "kind", curR.GetKind(), "name", curR.GetName(), "namespace", curR.GetNamespace())
|
||||
return
|
||||
}
|
||||
// re-evaluate the GR as the resource was updated
|
||||
|
@ -134,13 +136,14 @@ func (c *Controller) updateGenericResource(old, cur interface{}) {
|
|||
func (c *Controller) enqueue(gr *kyverno.GenerateRequest) {
|
||||
key, err := cache.MetaNamespaceKeyFunc(gr)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
c.log.Error(err, "failed to extract name")
|
||||
return
|
||||
}
|
||||
c.queue.Add(key)
|
||||
}
|
||||
|
||||
func (c *Controller) updatePolicy(old, cur interface{}) {
|
||||
logger := c.log
|
||||
oldP := old.(*kyverno.ClusterPolicy)
|
||||
curP := cur.(*kyverno.ClusterPolicy)
|
||||
if oldP.ResourceVersion == curP.ResourceVersion {
|
||||
|
@ -148,11 +151,11 @@ func (c *Controller) updatePolicy(old, cur interface{}) {
|
|||
// Two different versions of the same replica set will always have different RVs.
|
||||
return
|
||||
}
|
||||
glog.V(4).Infof("Updating Policy %s", oldP.Name)
|
||||
logger.V(4).Info("updating policy", "name", oldP.Name)
|
||||
// get the list of GR for the current Policy version
|
||||
grs, err := c.grLister.GetGenerateRequestsForClusterPolicy(curP.Name)
|
||||
if err != nil {
|
||||
glog.Errorf("failed to Generate Requests for policy %s: %v", curP.Name, err)
|
||||
logger.Error(err, "failed to generate request for policy", "name", curP.Name)
|
||||
return
|
||||
}
|
||||
// re-evaluate the GR as the policy was updated
|
||||
|
@ -183,34 +186,36 @@ func (c *Controller) updateGR(old, cur interface{}) {
|
|||
}
|
||||
|
||||
func (c *Controller) deleteGR(obj interface{}) {
|
||||
logger := c.log
|
||||
gr, ok := obj.(*kyverno.GenerateRequest)
|
||||
if !ok {
|
||||
tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
|
||||
if !ok {
|
||||
glog.Info(fmt.Errorf("Couldn't get object from tombstone %#v", obj))
|
||||
logger.Info("Couldn't get object from tombstone", "obj", obj)
|
||||
return
|
||||
}
|
||||
_, ok = tombstone.Obj.(*kyverno.GenerateRequest)
|
||||
if !ok {
|
||||
glog.Info(fmt.Errorf("Tombstone contained object that is not a Generate Request %#v", obj))
|
||||
logger.Info("tombstone contained object that is not a Generate Request CR", "obj", obj)
|
||||
return
|
||||
}
|
||||
}
|
||||
glog.V(4).Infof("Deleting GR %s", gr.Name)
|
||||
logger.Info("deleting generate request", "name", gr.Name)
|
||||
// sync Handler will remove it from the queue
|
||||
c.enqueueGR(gr)
|
||||
}
|
||||
|
||||
//Run ...
|
||||
func (c *Controller) Run(workers int, stopCh <-chan struct{}) {
|
||||
logger := c.log
|
||||
defer utilruntime.HandleCrash()
|
||||
defer c.queue.ShutDown()
|
||||
|
||||
glog.Info("Starting generate-policy controller")
|
||||
defer glog.Info("Shutting down generate-policy controller")
|
||||
logger.Info("starting")
|
||||
defer logger.Info("shutting down")
|
||||
|
||||
if !cache.WaitForCacheSync(stopCh, c.pSynced, c.grSynced) {
|
||||
glog.Error("generate-policy controller: failed to sync informer cache")
|
||||
logger.Info("failed to sync informer cache")
|
||||
return
|
||||
}
|
||||
for i := 0; i < workers; i++ {
|
||||
|
@ -239,27 +244,29 @@ func (c *Controller) processNextWorkItem() bool {
|
|||
}
|
||||
|
||||
func (c *Controller) handleErr(err error, key interface{}) {
|
||||
logger := c.log
|
||||
if err == nil {
|
||||
c.queue.Forget(key)
|
||||
return
|
||||
}
|
||||
|
||||
if c.queue.NumRequeues(key) < maxRetries {
|
||||
glog.Errorf("Error syncing Generate Request %v: %v", key, err)
|
||||
logger.Error(err, "failed to sync generate request", "key", key)
|
||||
c.queue.AddRateLimited(key)
|
||||
return
|
||||
}
|
||||
utilruntime.HandleError(err)
|
||||
glog.Infof("Dropping generate request %q out of the queue: %v", key, err)
|
||||
logger.Error(err, "Dropping generate request from the queue", "key", key)
|
||||
c.queue.Forget(key)
|
||||
}
|
||||
|
||||
func (c *Controller) syncGenerateRequest(key string) error {
|
||||
logger := c.log
|
||||
var err error
|
||||
startTime := time.Now()
|
||||
glog.V(4).Infof("Started syncing GR %q (%v)", key, startTime)
|
||||
logger.Info("started sync", "key", key, "startTime", startTime)
|
||||
defer func() {
|
||||
glog.V(4).Infof("Finished syncing GR %q (%v)", key, time.Since(startTime))
|
||||
logger.V(4).Info("finished sync", "key", key, "processingTime", time.Since(startTime))
|
||||
}()
|
||||
_, grName, err := cache.SplitMetaNamespaceKey(key)
|
||||
if err != nil {
|
||||
|
@ -268,7 +275,7 @@ func (c *Controller) syncGenerateRequest(key string) error {
|
|||
|
||||
gr, err := c.grLister.Get(grName)
|
||||
if err != nil {
|
||||
glog.V(4).Info(err)
|
||||
logger.Error(err, "failed to list generate requests")
|
||||
return err
|
||||
}
|
||||
return c.processGR(gr)
|
||||
|
|
|
@ -5,7 +5,7 @@ import (
|
|||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"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"
|
||||
|
@ -17,6 +17,7 @@ import (
|
|||
)
|
||||
|
||||
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 resource *unstructured.Unstructured
|
||||
var genResources []kyverno.ResourceSpec
|
||||
|
@ -24,45 +25,46 @@ func (c *Controller) processGR(gr *kyverno.GenerateRequest) error {
|
|||
resource, err = getResource(c.client, gr.Spec.Resource)
|
||||
if err != nil {
|
||||
// Dont update status
|
||||
glog.V(4).Infof("resource does not exist or is yet to be created, requeuing: %v", err)
|
||||
logger.Error(err, "resource does not exist or is yet to be created, requeueing")
|
||||
return err
|
||||
}
|
||||
// 2 - Apply the generate policy on the resource
|
||||
genResources, err = c.applyGenerate(*resource, *gr)
|
||||
// 3 - Report Events
|
||||
reportEvents(err, c.eventGen, *gr, *resource)
|
||||
reportEvents(logger, err, c.eventGen, *gr, *resource)
|
||||
// 4 - Update Status
|
||||
return updateStatus(c.statusControl, *gr, err, genResources)
|
||||
}
|
||||
|
||||
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 policy
|
||||
policy, err := c.pLister.Get(gr.Spec.Policy)
|
||||
if err != nil {
|
||||
glog.V(4).Infof("policy %s not found: %v", gr.Spec.Policy, err)
|
||||
logger.Error(err, "policy not found")
|
||||
return nil, nil
|
||||
}
|
||||
// build context
|
||||
ctx := context.NewContext()
|
||||
resourceRaw, err := resource.MarshalJSON()
|
||||
if err != nil {
|
||||
glog.V(4).Infof("failed to marshal resource: %v", err)
|
||||
logger.Error(err, "failed to marshal resource")
|
||||
return nil, err
|
||||
}
|
||||
err = ctx.AddResource(resourceRaw)
|
||||
if err != nil {
|
||||
glog.Infof("Failed to load resource in context: %v", err)
|
||||
logger.Error(err, "failed to load resource in context")
|
||||
return nil, err
|
||||
}
|
||||
err = ctx.AddUserInfo(gr.Spec.Context.UserRequestInfo)
|
||||
if err != nil {
|
||||
glog.Infof("Failed to load userInfo in context: %v", err)
|
||||
logger.Error(err, "failed to load SA in context")
|
||||
return nil, err
|
||||
}
|
||||
err = ctx.AddSA(gr.Spec.Context.UserRequestInfo.AdmissionUserInfo.Username)
|
||||
if err != nil {
|
||||
glog.Infof("Failed to load serviceAccount in context: %v", err)
|
||||
logger.Error(err, "failed to load UserInfo in context")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -76,12 +78,12 @@ func (c *Controller) applyGenerate(resource unstructured.Unstructured, gr kyvern
|
|||
// check if the policy still applies to the resource
|
||||
engineResponse := engine.Generate(policyContext)
|
||||
if len(engineResponse.PolicyResponse.Rules) == 0 {
|
||||
glog.V(4).Infof("policy %s, dont not apply to resource %v", gr.Spec.Policy, gr.Spec.Resource)
|
||||
logger.V(4).Info("policy does not apply to 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
|
||||
return c.applyGeneratePolicy(policyContext, gr)
|
||||
return c.applyGeneratePolicy(logger, policyContext, gr)
|
||||
}
|
||||
|
||||
func updateStatus(statusControl StatusControlInterface, gr kyverno.GenerateRequest, err error, genResources []kyverno.ResourceSpec) error {
|
||||
|
@ -93,7 +95,7 @@ func updateStatus(statusControl StatusControlInterface, gr kyverno.GenerateReque
|
|||
return statusControl.Success(gr, genResources)
|
||||
}
|
||||
|
||||
func (c *Controller) applyGeneratePolicy(policyContext engine.PolicyContext, gr kyverno.GenerateRequest) ([]kyverno.ResourceSpec, error) {
|
||||
func (c *Controller) applyGeneratePolicy(log logr.Logger, policyContext engine.PolicyContext, gr kyverno.GenerateRequest) ([]kyverno.ResourceSpec, error) {
|
||||
// List of generatedResources
|
||||
var genResources []kyverno.ResourceSpec
|
||||
// Get the response as the actions to be performed on the resource
|
||||
|
@ -113,9 +115,8 @@ func (c *Controller) applyGeneratePolicy(policyContext engine.PolicyContext, gr
|
|||
if !rule.HasGenerate() {
|
||||
continue
|
||||
}
|
||||
|
||||
startTime := time.Now()
|
||||
genResource, err := applyRule(c.client, rule, resource, ctx, processExisting)
|
||||
genResource, err := applyRule(log, c.client, rule, resource, ctx, processExisting)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -172,7 +173,7 @@ func updateGenerateExecutionTime(newTime time.Duration, oldAverageTimeString str
|
|||
return time.Duration(newAverageTimeInNanoSeconds) * time.Nanosecond
|
||||
}
|
||||
|
||||
func applyRule(client *dclient.Client, rule kyverno.Rule, resource unstructured.Unstructured, ctx context.EvalInterface, processExisting bool) (kyverno.ResourceSpec, error) {
|
||||
func applyRule(log logr.Logger, client *dclient.Client, rule kyverno.Rule, resource unstructured.Unstructured, ctx context.EvalInterface, processExisting bool) (kyverno.ResourceSpec, error) {
|
||||
var rdata map[string]interface{}
|
||||
var err error
|
||||
var mode ResourceMode
|
||||
|
@ -187,7 +188,7 @@ func applyRule(client *dclient.Client, rule kyverno.Rule, resource unstructured.
|
|||
// format : {{<variable_name}}
|
||||
// - 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
|
||||
if _, err := variables.SubstituteVars(ctx, genUnst.Object); err != nil {
|
||||
if _, err := variables.SubstituteVars(log, ctx, genUnst.Object); err != nil {
|
||||
return noGenResource, err
|
||||
}
|
||||
genKind, _, err := unstructured.NestedString(genUnst.Object, "kind")
|
||||
|
@ -219,9 +220,9 @@ func applyRule(client *dclient.Client, rule kyverno.Rule, resource unstructured.
|
|||
}
|
||||
|
||||
if genData != nil {
|
||||
rdata, mode, err = manageData(genKind, genNamespace, genName, genData, client, resource)
|
||||
rdata, mode, err = manageData(log, genKind, genNamespace, genName, genData, client, resource)
|
||||
} else {
|
||||
rdata, mode, err = manageClone(genKind, genNamespace, genName, genCopy, client, resource)
|
||||
rdata, mode, err = manageClone(log, genKind, genNamespace, genName, genCopy, client, resource)
|
||||
}
|
||||
if err != nil {
|
||||
return noGenResource, err
|
||||
|
@ -248,38 +249,38 @@ func applyRule(client *dclient.Client, rule kyverno.Rule, resource unstructured.
|
|||
// - app.kubernetes.io/managed-by: kyverno
|
||||
// - kyverno.io/generated-by: kind/namespace/name (trigger resource)
|
||||
manageLabels(newResource, resource)
|
||||
|
||||
logger := log.WithValues("genKind", genKind, "genNamespace", genNamespace, "genName", genName)
|
||||
if mode == Create {
|
||||
// Reset resource version
|
||||
newResource.SetResourceVersion("")
|
||||
// Create the resource
|
||||
glog.V(4).Infof("Creating new resource %s/%s/%s", genKind, genNamespace, genName)
|
||||
logger.V(4).Info("creating new resource")
|
||||
_, err = client.CreateResource(genKind, genNamespace, newResource, false)
|
||||
if err != nil {
|
||||
// Failed to create resource
|
||||
return noGenResource, err
|
||||
}
|
||||
glog.V(4).Infof("Created new resource %s/%s/%s", genKind, genNamespace, genName)
|
||||
logger.V(4).Info("created new resource")
|
||||
|
||||
} else if mode == Update {
|
||||
glog.V(4).Infof("Updating existing resource %s/%s/%s", genKind, genNamespace, genName)
|
||||
logger.V(4).Info("updating existing resource")
|
||||
// Update the resource
|
||||
_, err := client.UpdateResource(genKind, genNamespace, newResource, false)
|
||||
if err != nil {
|
||||
// Failed to update resource
|
||||
return noGenResource, err
|
||||
}
|
||||
glog.V(4).Infof("Updated existing resource %s/%s/%s", genKind, genNamespace, genName)
|
||||
logger.V(4).Info("updated new resource")
|
||||
}
|
||||
|
||||
return newGenResource, nil
|
||||
}
|
||||
|
||||
func manageData(kind, namespace, name string, data map[string]interface{}, client *dclient.Client, resource unstructured.Unstructured) (map[string]interface{}, ResourceMode, error) {
|
||||
func manageData(log logr.Logger, 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
|
||||
obj, err := client.GetResource(kind, namespace, name)
|
||||
if apierrors.IsNotFound(err) {
|
||||
glog.V(4).Infof("Resource %s/%s/%s does not exists, will try to create", kind, namespace, name)
|
||||
log.Error(err, "resource does not exist, will try to create", "genKind", kind, "genNamespace", namespace, "genName", name)
|
||||
return data, Create, nil
|
||||
}
|
||||
if err != nil {
|
||||
|
@ -288,18 +289,17 @@ func manageData(kind, namespace, name string, data map[string]interface{}, clien
|
|||
return nil, Skip, err
|
||||
}
|
||||
// Resource exists; verfiy the content of the resource
|
||||
err = checkResource(data, obj)
|
||||
err = checkResource(log, data, obj)
|
||||
if err == nil {
|
||||
// Existing resource does contain the mentioned configuration in spec, skip processing the resource as it is already in expected state
|
||||
return nil, Skip, nil
|
||||
}
|
||||
|
||||
glog.V(4).Infof("Resource %s/%s/%s exists but missing required configuration, will try to update", kind, namespace, name)
|
||||
log.Info("to be generated resoruce already exists, but is missing the specifeid configurations, will try to update", "genKind", kind, "genNamespace", namespace, "genName", name)
|
||||
return data, Update, nil
|
||||
|
||||
}
|
||||
|
||||
func manageClone(kind, namespace, name string, clone map[string]interface{}, client *dclient.Client, resource unstructured.Unstructured) (map[string]interface{}, ResourceMode, error) {
|
||||
func manageClone(log logr.Logger, 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
|
||||
_, err := client.GetResource(kind, namespace, name)
|
||||
if err == nil {
|
||||
|
@ -308,6 +308,7 @@ func manageClone(kind, namespace, name string, clone map[string]interface{}, cli
|
|||
}
|
||||
//TODO: check this
|
||||
if !apierrors.IsNotFound(err) {
|
||||
log.Error(err, "reference/clone resource is not found", "genKind", kind, "genNamespace", namespace, "genName", name)
|
||||
//something wrong while fetching resource
|
||||
return nil, Skip, err
|
||||
}
|
||||
|
@ -325,8 +326,6 @@ func manageClone(kind, namespace, name string, clone map[string]interface{}, cli
|
|||
// attempting to clone it self, this will fail -> short-ciruit it
|
||||
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?
|
||||
obj, err := client.GetResource(kind, newRNs, newRName)
|
||||
if err != nil {
|
||||
|
@ -349,10 +348,10 @@ const (
|
|||
Update = "UPDATE"
|
||||
)
|
||||
|
||||
func checkResource(newResourceSpec interface{}, resource *unstructured.Unstructured) error {
|
||||
func checkResource(log logr.Logger, newResourceSpec interface{}, resource *unstructured.Unstructured) error {
|
||||
// check if the resource spec if a subset of the resource
|
||||
if path, err := validate.ValidateResourceWithPattern(resource.Object, newResourceSpec); err != nil {
|
||||
glog.V(4).Infof("Failed to match the resource at path %s: err %v", path, err)
|
||||
if path, err := validate.ValidateResourceWithPattern(log, resource.Object, newResourceSpec); err != nil {
|
||||
log.Error(err, "Failed to match the resource ", "path", path)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -3,8 +3,8 @@ package generate
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
)
|
||||
|
||||
func manageLabels(unstr *unstructured.Unstructured, triggerResource unstructured.Unstructured) {
|
||||
|
@ -30,7 +30,7 @@ func managedBy(labels map[string]string) {
|
|||
val, ok := labels[key]
|
||||
if ok {
|
||||
if val != value {
|
||||
glog.Infof("resource managed by %s, kyverno wont over-ride the label", val)
|
||||
log.Log.Info(fmt.Sprintf("resource managed by %s, kyverno wont over-ride the label", val))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ func generatedBy(labels map[string]string, triggerResource unstructured.Unstruct
|
|||
val, ok := labels[key]
|
||||
if ok {
|
||||
if val != value {
|
||||
glog.Infof("resource generated by %s, kyverno wont over-ride the label", val)
|
||||
log.Log.Info(fmt.Sprintf("resource generated by %s, kyverno wont over-ride the label", val))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,13 +3,13 @@ package generate
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/go-logr/logr"
|
||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||
"github.com/nirmata/kyverno/pkg/event"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
||||
func reportEvents(err error, eventGen event.Interface, gr kyverno.GenerateRequest, resource unstructured.Unstructured) {
|
||||
func reportEvents(log logr.Logger, err error, eventGen event.Interface, gr kyverno.GenerateRequest, resource unstructured.Unstructured) {
|
||||
if err == nil {
|
||||
// Success Events
|
||||
// - resource -> policy rule applied successfully
|
||||
|
@ -18,7 +18,6 @@ func reportEvents(err error, eventGen event.Interface, gr kyverno.GenerateReques
|
|||
eventGen.Add(events...)
|
||||
return
|
||||
}
|
||||
glog.V(4).Infof("reporing events for %v", err)
|
||||
events := failedEvents(err, gr, resource)
|
||||
eventGen.Add(events...)
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package generate
|
||||
|
||||
import (
|
||||
"github.com/golang/glog"
|
||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||
kyvernoclient "github.com/nirmata/kyverno/pkg/client/clientset/versioned"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
)
|
||||
|
||||
//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
|
||||
_, err := sc.client.KyvernoV1().GenerateRequests("kyverno").UpdateStatus(&gr)
|
||||
if err != nil {
|
||||
glog.V(4).Infof("FAILED: updated gr %s status to %s", gr.Name, string(kyverno.Failed))
|
||||
log.Log.Error(err, "failed to update generate request status", "name", gr.Name)
|
||||
return err
|
||||
}
|
||||
glog.V(4).Infof("updated gr %s status to %s", gr.Name, string(kyverno.Failed))
|
||||
log.Log.Info("updated generate request status", "name", gr.Name, "status", string(kyverno.Failed))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -41,9 +41,9 @@ func (sc StatusControl) Success(gr kyverno.GenerateRequest, genResources []kyver
|
|||
|
||||
_, err := sc.client.KyvernoV1().GenerateRequests("kyverno").UpdateStatus(&gr)
|
||||
if err != nil {
|
||||
glog.V(4).Infof("FAILED: updated gr %s status to %s", gr.Name, string(kyverno.Completed))
|
||||
log.Log.Error(err, "failed to update generate request status", "name", gr.Name)
|
||||
return err
|
||||
}
|
||||
glog.V(4).Infof("updated gr %s status to %s", gr.Name, string(kyverno.Completed))
|
||||
log.Log.Info("updated generate request status", "name", gr.Name, "status", string(kyverno.Completed))
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -7,12 +7,12 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/nirmata/kyverno/pkg/utils"
|
||||
|
||||
"github.com/nirmata/kyverno/pkg/kyverno/sanitizedError"
|
||||
|
||||
policy2 "github.com/nirmata/kyverno/pkg/policy"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
|
||||
"k8s.io/client-go/discovery"
|
||||
|
@ -32,6 +32,7 @@ import (
|
|||
yamlv2 "gopkg.in/yaml.v2"
|
||||
"k8s.io/cli-runtime/pkg/genericclioptions"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
log "sigs.k8s.io/controller-runtime/pkg/log"
|
||||
)
|
||||
|
||||
func Command() *cobra.Command {
|
||||
|
@ -49,7 +50,7 @@ func Command() *cobra.Command {
|
|||
defer func() {
|
||||
if err != nil {
|
||||
if !sanitizedError.IsErrorSanitized(err) {
|
||||
glog.V(4).Info(err)
|
||||
log.Log.Error(err, "failed to sanitize")
|
||||
err = fmt.Errorf("Internal error")
|
||||
}
|
||||
}
|
||||
|
@ -69,7 +70,7 @@ func Command() *cobra.Command {
|
|||
}
|
||||
|
||||
for _, policy := range policies {
|
||||
err := policy2.Validate(*policy)
|
||||
err := policy2.Validate(utils.MarshalPolicy(*policy), nil, true)
|
||||
if err != nil {
|
||||
return sanitizedError.New(fmt.Sprintf("Policy %v is not valid", policy.Name))
|
||||
}
|
||||
|
|
|
@ -9,6 +9,9 @@ import (
|
|||
"github.com/nirmata/kyverno/pkg/kyverno/apply"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
@ -19,7 +22,7 @@ func CLI() {
|
|||
Short: "kyverno manages native policies of Kubernetes",
|
||||
}
|
||||
|
||||
configureGlog(cli)
|
||||
configurelog(cli)
|
||||
|
||||
commands := []*cobra.Command{
|
||||
version.Command(),
|
||||
|
@ -36,9 +39,9 @@ func CLI() {
|
|||
}
|
||||
}
|
||||
|
||||
func configureGlog(cli *cobra.Command) {
|
||||
flag.Parse()
|
||||
_ = flag.Set("logtostderr", "true")
|
||||
func configurelog(cli *cobra.Command) {
|
||||
klog.InitFlags(nil)
|
||||
log.SetLogger(klogr.New())
|
||||
|
||||
cli.PersistentFlags().AddGoFlagSet(flag.CommandLine)
|
||||
_ = cli.PersistentFlags().MarkHidden("alsologtostderr")
|
||||
|
|
|
@ -7,15 +7,16 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/nirmata/kyverno/pkg/kyverno/sanitizedError"
|
||||
"github.com/nirmata/kyverno/pkg/utils"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/nirmata/kyverno/pkg/kyverno/sanitizedError"
|
||||
|
||||
policyvalidate "github.com/nirmata/kyverno/pkg/policy"
|
||||
|
||||
v1 "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/apimachinery/pkg/util/yaml"
|
||||
log "sigs.k8s.io/controller-runtime/pkg/log"
|
||||
)
|
||||
|
||||
func Command() *cobra.Command {
|
||||
|
@ -27,7 +28,7 @@ func Command() *cobra.Command {
|
|||
defer func() {
|
||||
if err != nil {
|
||||
if !sanitizedError.IsErrorSanitized(err) {
|
||||
glog.V(4).Info(err)
|
||||
log.Log.Error(err, "failed to sanitize")
|
||||
err = fmt.Errorf("Internal error")
|
||||
}
|
||||
}
|
||||
|
@ -43,7 +44,7 @@ func Command() *cobra.Command {
|
|||
}
|
||||
|
||||
for _, policy := range policies {
|
||||
err = policyvalidate.Validate(*policy)
|
||||
err = policyvalidate.Validate(utils.MarshalPolicy(*policy), nil, true)
|
||||
if err != nil {
|
||||
fmt.Println("Policy " + policy.Name + " is invalid")
|
||||
} else {
|
||||
|
|
|
@ -6,13 +6,12 @@ import (
|
|||
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/googleapis/gnostic/compiler"
|
||||
|
||||
openapi_v2 "github.com/googleapis/gnostic/OpenAPIv2"
|
||||
log "sigs.k8s.io/controller-runtime/pkg/log"
|
||||
|
||||
client "github.com/nirmata/kyverno/pkg/dclient"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
|
@ -44,30 +43,32 @@ func NewCRDSync(client *client.Client) *crdSync {
|
|||
func (c *crdSync) Run(workers int, stopCh <-chan struct{}) {
|
||||
newDoc, err := c.client.DiscoveryClient.OpenAPISchema()
|
||||
if err != nil {
|
||||
glog.V(4).Infof("cannot get openapi schema: %v", err)
|
||||
log.Log.Error(err, "cannot get openapi schema")
|
||||
}
|
||||
|
||||
err = useOpenApiDocument(newDoc)
|
||||
if err != nil {
|
||||
glog.V(4).Infof("Could not set custom OpenApi document: %v\n", err)
|
||||
log.Log.Error(err, "Could not set custom OpenApi document")
|
||||
}
|
||||
|
||||
// Sync CRD before kyverno starts
|
||||
c.sync()
|
||||
|
||||
for i := 0; i < workers; i++ {
|
||||
go wait.Until(c.sync, time.Second*10, stopCh)
|
||||
}
|
||||
<-stopCh
|
||||
}
|
||||
|
||||
func (c *crdSync) sync() {
|
||||
openApiGlobalState.mutex.Lock()
|
||||
defer openApiGlobalState.mutex.Unlock()
|
||||
|
||||
crds, err := c.client.ListResource("CustomResourceDefinition", "", nil)
|
||||
if err != nil {
|
||||
glog.V(4).Infof("could not fetch crd's from server: %v", err)
|
||||
log.Log.Error(err, "could not fetch crd's from server")
|
||||
return
|
||||
}
|
||||
|
||||
openApiGlobalState.mutex.Lock()
|
||||
defer openApiGlobalState.mutex.Unlock()
|
||||
|
||||
deleteCRDFromPreviousSync()
|
||||
|
||||
for _, crd := range crds.Items {
|
||||
|
@ -91,17 +92,18 @@ func parseCRD(crd unstructured.Unstructured) {
|
|||
|
||||
crdName := crdDefinition.Spec.Names.Kind
|
||||
if len(crdDefinition.Spec.Versions) < 1 {
|
||||
glog.V(4).Infof("could not parse crd schema, no versions present")
|
||||
log.Log.V(4).Info("could not parse crd schema, no versions present")
|
||||
return
|
||||
}
|
||||
|
||||
var schema yaml.MapSlice
|
||||
schemaRaw, _ := json.Marshal(crdDefinition.Spec.Versions[0].Schema.OpenAPIV3Schema)
|
||||
schemaRaw = addingDefaultFieldsToSchema(schemaRaw)
|
||||
_ = yaml.Unmarshal(schemaRaw, &schema)
|
||||
|
||||
parsedSchema, err := openapi_v2.NewSchema(schema, compiler.NewContext("schema", nil))
|
||||
if err != nil {
|
||||
glog.V(4).Infof("could not parse crd schema:%v", err)
|
||||
log.Log.Error(err, "could not parse crd schema:")
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -110,3 +112,29 @@ func parseCRD(crd unstructured.Unstructured) {
|
|||
openApiGlobalState.kindToDefinitionName[crdName] = crdName
|
||||
openApiGlobalState.definitions[crdName] = parsedSchema
|
||||
}
|
||||
|
||||
// addingDefaultFieldsToSchema will add any default missing fields like apiVersion, metadata
|
||||
func addingDefaultFieldsToSchema(schemaRaw []byte) []byte {
|
||||
var schema struct {
|
||||
Properties map[string]interface{} `json:"properties"`
|
||||
}
|
||||
_ = json.Unmarshal(schemaRaw, &schema)
|
||||
|
||||
if schema.Properties["apiVersion"] == nil {
|
||||
apiVersionDefRaw := `{"description":"APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources","type":"string"}`
|
||||
apiVersionDef := make(map[string]interface{})
|
||||
_ = json.Unmarshal([]byte(apiVersionDefRaw), &apiVersionDef)
|
||||
schema.Properties["apiVersion"] = apiVersionDef
|
||||
}
|
||||
|
||||
if schema.Properties["metadata"] == nil {
|
||||
metadataDefRaw := `{"$ref":"#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta","description":"Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata"}`
|
||||
metadataDef := make(map[string]interface{})
|
||||
_ = json.Unmarshal([]byte(metadataDefRaw), &metadataDef)
|
||||
schema.Properties["metadata"] = metadataDef
|
||||
}
|
||||
|
||||
schemaWithDefaultFields, _ := json.Marshal(schema)
|
||||
|
||||
return schemaWithDefaultFields
|
||||
}
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
package openapi
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/nirmata/kyverno/data"
|
||||
|
||||
"github.com/golang/glog"
|
||||
data "github.com/nirmata/kyverno/api"
|
||||
"github.com/nirmata/kyverno/pkg/engine/utils"
|
||||
|
||||
"github.com/nirmata/kyverno/pkg/engine"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
|
@ -19,6 +20,7 @@ import (
|
|||
"github.com/googleapis/gnostic/compiler"
|
||||
"k8s.io/kube-openapi/pkg/util/proto"
|
||||
"k8s.io/kube-openapi/pkg/util/proto/validation"
|
||||
log "sigs.k8s.io/controller-runtime/pkg/log"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
@ -44,48 +46,27 @@ func init() {
|
|||
}
|
||||
}
|
||||
|
||||
func ValidatePolicyMutation(policy v1.ClusterPolicy) error {
|
||||
func ValidatePolicyFields(policyRaw []byte) error {
|
||||
openApiGlobalState.mutex.RLock()
|
||||
defer openApiGlobalState.mutex.RUnlock()
|
||||
|
||||
var kindToRules = make(map[string][]v1.Rule)
|
||||
for _, rule := range policy.Spec.Rules {
|
||||
if rule.HasMutate() {
|
||||
rule.MatchResources = v1.MatchResources{
|
||||
UserInfo: v1.UserInfo{},
|
||||
ResourceDescription: v1.ResourceDescription{
|
||||
Kinds: rule.MatchResources.Kinds,
|
||||
},
|
||||
}
|
||||
rule.ExcludeResources = v1.ExcludeResources{}
|
||||
for _, kind := range rule.MatchResources.Kinds {
|
||||
kindToRules[kind] = append(kindToRules[kind], rule)
|
||||
}
|
||||
}
|
||||
var policy v1.ClusterPolicy
|
||||
err := json.Unmarshal(policyRaw, &policy)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for kind, rules := range kindToRules {
|
||||
newPolicy := *policy.DeepCopy()
|
||||
newPolicy.Spec.Rules = rules
|
||||
resource, _ := generateEmptyResource(openApiGlobalState.definitions[openApiGlobalState.kindToDefinitionName[kind]]).(map[string]interface{})
|
||||
if resource == nil {
|
||||
glog.V(4).Infof("Cannot Validate policy: openApi definition now found for %v", kind)
|
||||
return nil
|
||||
}
|
||||
newResource := unstructured.Unstructured{Object: resource}
|
||||
newResource.SetKind(kind)
|
||||
|
||||
patchedResource, err := engine.ForceMutate(nil, *newPolicy.DeepCopy(), newResource)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = ValidateResource(*patchedResource.DeepCopy(), kind)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
policyUnst, err := utils.ConvertToUnstructured(policyRaw)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
err = ValidateResource(*policyUnst.DeepCopy(), "ClusterPolicy")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return validatePolicyMutation(policy)
|
||||
}
|
||||
|
||||
func ValidateResource(patchedResource unstructured.Unstructured, kind string) error {
|
||||
|
@ -96,6 +77,7 @@ func ValidateResource(patchedResource unstructured.Unstructured, kind string) er
|
|||
kind = openApiGlobalState.kindToDefinitionName[kind]
|
||||
schema := openApiGlobalState.models.LookupModel(kind)
|
||||
if schema == nil {
|
||||
// Check if kind is a CRD
|
||||
schema, err = getSchemaFromDefinitions(kind)
|
||||
if err != nil || schema == nil {
|
||||
return fmt.Errorf("pre-validation: couldn't find model %s", kind)
|
||||
|
@ -121,6 +103,40 @@ func GetDefinitionNameFromKind(kind string) string {
|
|||
return openApiGlobalState.kindToDefinitionName[kind]
|
||||
}
|
||||
|
||||
func validatePolicyMutation(policy v1.ClusterPolicy) error {
|
||||
var kindToRules = make(map[string][]v1.Rule)
|
||||
for _, rule := range policy.Spec.Rules {
|
||||
if rule.HasMutate() {
|
||||
for _, kind := range rule.MatchResources.Kinds {
|
||||
kindToRules[kind] = append(kindToRules[kind], rule)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for kind, rules := range kindToRules {
|
||||
newPolicy := *policy.DeepCopy()
|
||||
newPolicy.Spec.Rules = rules
|
||||
resource, _ := generateEmptyResource(openApiGlobalState.definitions[openApiGlobalState.kindToDefinitionName[kind]]).(map[string]interface{})
|
||||
if resource == nil {
|
||||
log.Log.V(4).Info(fmt.Sprintf("Cannot Validate policy: openApi definition now found for %v", kind))
|
||||
return nil
|
||||
}
|
||||
newResource := unstructured.Unstructured{Object: resource}
|
||||
newResource.SetKind(kind)
|
||||
|
||||
patchedResource, err := engine.ForceMutate(nil, *newPolicy.DeepCopy(), newResource)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = ValidateResource(*patchedResource.DeepCopy(), kind)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func useOpenApiDocument(customDoc *openapi_v2.Document) error {
|
||||
openApiGlobalState.mutex.Lock()
|
||||
defer openApiGlobalState.mutex.Unlock()
|
||||
|
@ -156,8 +172,23 @@ func getSchemaDocument() (*openapi_v2.Document, error) {
|
|||
|
||||
// For crd, we do not store definition in document
|
||||
func getSchemaFromDefinitions(kind string) (proto.Schema, error) {
|
||||
if kind == "" {
|
||||
return nil, errors.New("invalid kind")
|
||||
}
|
||||
|
||||
path := proto.NewPath(kind)
|
||||
return (&proto.Definitions{}).ParseSchema(openApiGlobalState.definitions[kind], &path)
|
||||
definition := openApiGlobalState.definitions[kind]
|
||||
if definition == nil {
|
||||
return nil, errors.New("could not find definition")
|
||||
}
|
||||
|
||||
// This was added so crd's can access
|
||||
// normal definitions from existing schema such as
|
||||
// `metadata` - this maybe a breaking change.
|
||||
// Removing this may cause policy validate to stop working
|
||||
existingDefinitions, _ := openApiGlobalState.models.(*proto.Definitions)
|
||||
|
||||
return (existingDefinitions).ParseSchema(definition, &path)
|
||||
}
|
||||
|
||||
func generateEmptyResource(kindSchema *openapi_v2.Schema) interface{} {
|
||||
|
|
|
@ -52,7 +52,7 @@ func Test_ValidateMutationPolicy(t *testing.T) {
|
|||
_ = json.Unmarshal(tc.policy, &policy)
|
||||
|
||||
var errMessage string
|
||||
err := ValidatePolicyMutation(policy)
|
||||
err := validatePolicyMutation(policy)
|
||||
if err != nil {
|
||||
errMessage = err.Error()
|
||||
}
|
||||
|
|
61
pkg/policy/actions.go
Normal file
61
pkg/policy/actions.go
Normal file
|
@ -0,0 +1,61 @@
|
|||
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"
|
||||
|
||||
jsonpatch "github.com/evanphx/json-patch"
|
||||
"github.com/golang/glog"
|
||||
"github.com/go-logr/logr"
|
||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||
"github.com/nirmata/kyverno/pkg/engine"
|
||||
"github.com/nirmata/kyverno/pkg/engine/context"
|
||||
|
@ -19,12 +19,12 @@ import (
|
|||
|
||||
// applyPolicy applies policy on a resource
|
||||
//TODO: generation rules
|
||||
func applyPolicy(policy kyverno.ClusterPolicy, resource unstructured.Unstructured) (responses []response.EngineResponse) {
|
||||
func applyPolicy(policy kyverno.ClusterPolicy, resource unstructured.Unstructured, logger logr.Logger) (responses []response.EngineResponse) {
|
||||
startTime := time.Now()
|
||||
|
||||
glog.V(4).Infof("Started apply policy %s on resource %s/%s/%s (%v)", policy.Name, resource.GetKind(), resource.GetNamespace(), resource.GetName(), startTime)
|
||||
logger.Info("start applying policy", "startTime", startTime)
|
||||
defer func() {
|
||||
glog.V(4).Infof("Finished applying %s on resource %s/%s/%s (%v)", policy.Name, resource.GetKind(), resource.GetNamespace(), resource.GetName(), time.Since(startTime))
|
||||
logger.Info("finisnhed applying policy", "processingTime", time.Since(startTime))
|
||||
}()
|
||||
|
||||
var engineResponses []response.EngineResponse
|
||||
|
@ -32,13 +32,15 @@ func applyPolicy(policy kyverno.ClusterPolicy, resource unstructured.Unstructure
|
|||
var err error
|
||||
// build context
|
||||
ctx := context.NewContext()
|
||||
ctx.AddResource(transformResource(resource))
|
||||
|
||||
err = ctx.AddResource(transformResource(resource))
|
||||
if err != nil {
|
||||
logger.Error(err, "enable to add transform resource to ctx")
|
||||
}
|
||||
//MUTATION
|
||||
engineResponse, err = mutation(policy, resource, ctx)
|
||||
engineResponse, err = mutation(policy, resource, ctx, logger)
|
||||
engineResponses = append(engineResponses, engineResponse)
|
||||
if err != nil {
|
||||
glog.Errorf("unable to process mutation rules: %v", err)
|
||||
logger.Error(err, "failed to process mutation rule")
|
||||
}
|
||||
|
||||
//VALIDATION
|
||||
|
@ -48,52 +50,52 @@ func applyPolicy(policy kyverno.ClusterPolicy, resource unstructured.Unstructure
|
|||
//TODO: GENERATION
|
||||
return engineResponses
|
||||
}
|
||||
func mutation(policy kyverno.ClusterPolicy, resource unstructured.Unstructured, ctx context.EvalInterface) (response.EngineResponse, error) {
|
||||
func mutation(policy kyverno.ClusterPolicy, resource unstructured.Unstructured, ctx context.EvalInterface, log logr.Logger) (response.EngineResponse, error) {
|
||||
|
||||
engineResponse := engine.Mutate(engine.PolicyContext{Policy: policy, NewResource: resource, Context: ctx})
|
||||
if !engineResponse.IsSuccesful() {
|
||||
glog.V(4).Infof("mutation had errors reporting them")
|
||||
log.V(4).Info("failed to apply mutation rules; reporting them")
|
||||
return engineResponse, nil
|
||||
}
|
||||
// Verify if the JSON pathes returned by the Mutate are already applied to the resource
|
||||
if reflect.DeepEqual(resource, engineResponse.PatchedResource) {
|
||||
// resources matches
|
||||
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)
|
||||
log.V(4).Info("resource already satisfys the policy")
|
||||
return engineResponse, nil
|
||||
}
|
||||
return getFailedOverallRuleInfo(resource, engineResponse)
|
||||
return getFailedOverallRuleInfo(resource, engineResponse, log)
|
||||
}
|
||||
|
||||
// getFailedOverallRuleInfo gets detailed info for over-all mutation failure
|
||||
func getFailedOverallRuleInfo(resource unstructured.Unstructured, engineResponse response.EngineResponse) (response.EngineResponse, error) {
|
||||
func getFailedOverallRuleInfo(resource unstructured.Unstructured, engineResponse response.EngineResponse, log logr.Logger) (response.EngineResponse, error) {
|
||||
rawResource, err := resource.MarshalJSON()
|
||||
if err != nil {
|
||||
glog.V(4).Infof("unable to marshal resource: %v\n", err)
|
||||
log.Error(err, "faield to marshall resource")
|
||||
return response.EngineResponse{}, err
|
||||
}
|
||||
|
||||
// resource does not match so there was a mutation rule violated
|
||||
for index, rule := range engineResponse.PolicyResponse.Rules {
|
||||
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)
|
||||
log.V(4).Info("veriying if policy rule was applied before", "rule", rule.Name)
|
||||
if len(rule.Patches) == 0 {
|
||||
continue
|
||||
}
|
||||
patch, err := jsonpatch.DecodePatch(utils.JoinPatches(rule.Patches))
|
||||
if err != nil {
|
||||
glog.V(4).Infof("unable to decode patch %s: %v", rule.Patches, err)
|
||||
log.Error(err, "failed to decode JSON patch", "patches", rule.Patches)
|
||||
return response.EngineResponse{}, err
|
||||
}
|
||||
|
||||
// apply the patches returned by mutate to the original resource
|
||||
patchedResource, err := patch.Apply(rawResource)
|
||||
if err != nil {
|
||||
glog.V(4).Infof("unable to apply patch %s: %v", rule.Patches, err)
|
||||
log.Error(err, "failed to apply JSON patch", "patches", rule.Patches)
|
||||
return response.EngineResponse{}, err
|
||||
}
|
||||
if !jsonpatch.Equal(patchedResource, rawResource) {
|
||||
glog.V(4).Infof("policy %s rule %s condition not satisfied by existing resource", engineResponse.PolicyResponse.Policy, rule.Name)
|
||||
log.V(4).Info("policy rule conditions not satisfied by resource", "rule", rule.Name)
|
||||
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))
|
||||
engineResponse.PolicyResponse.Rules[index].Message = fmt.Sprintf("mutation json patches not found at resource path %s", extractPatchPath(rule.Patches, log))
|
||||
}
|
||||
}
|
||||
return engineResponse, nil
|
||||
|
@ -105,14 +107,14 @@ type jsonPatch struct {
|
|||
Value interface{} `json:"value"`
|
||||
}
|
||||
|
||||
func extractPatchPath(patches [][]byte) string {
|
||||
func extractPatchPath(patches [][]byte, log logr.Logger) string {
|
||||
var resultPath []string
|
||||
// extract the patch path and value
|
||||
for _, patch := range patches {
|
||||
glog.V(4).Infof("expected json patch not found in resource: %s", string(patch))
|
||||
log.V(4).Info("expected json patch not found in resource", "patch", string(patch))
|
||||
var data jsonPatch
|
||||
if err := json.Unmarshal(patch, &data); err != nil {
|
||||
glog.V(4).Infof("Failed to decode the generated patch %v: Error %v", string(patch), err)
|
||||
log.Error(err, "failed to decode the generate patch", "patch", string(patch))
|
||||
continue
|
||||
}
|
||||
resultPath = append(resultPath, data.Path)
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||
"github.com/nirmata/kyverno/pkg/engine/context"
|
||||
"github.com/nirmata/kyverno/pkg/engine/variables"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
)
|
||||
|
||||
//ContainsUserInfo returns error is userInfo is defined
|
||||
|
@ -35,23 +36,23 @@ func ContainsUserInfo(policy kyverno.ClusterPolicy) error {
|
|||
filterVars := []string{"request.userInfo*", "serviceAccountName", "serviceAccountNamespace"}
|
||||
ctx := context.NewContext(filterVars...)
|
||||
for condIdx, condition := range rule.Conditions {
|
||||
if condition.Key, err = variables.SubstituteVars(ctx, condition.Key); err != nil {
|
||||
if condition.Key, err = variables.SubstituteVars(log.Log, ctx, condition.Key); err != nil {
|
||||
return fmt.Errorf("userInfo variable used at spec/rules[%d]/condition[%d]/key", idx, condIdx)
|
||||
}
|
||||
|
||||
if condition.Value, err = variables.SubstituteVars(ctx, condition.Value); err != nil {
|
||||
if condition.Value, err = variables.SubstituteVars(log.Log, ctx, condition.Value); err != nil {
|
||||
return fmt.Errorf("userInfo variable used at spec/rules[%d]/condition[%d]/value", idx, condIdx)
|
||||
}
|
||||
}
|
||||
|
||||
if rule.Mutation.Overlay, err = variables.SubstituteVars(ctx, rule.Mutation.Overlay); err != nil {
|
||||
if rule.Mutation.Overlay, err = variables.SubstituteVars(log.Log, ctx, rule.Mutation.Overlay); err != nil {
|
||||
return fmt.Errorf("userInfo variable used at spec/rules[%d]/mutate/overlay", idx)
|
||||
}
|
||||
if rule.Validation.Pattern, err = variables.SubstituteVars(ctx, rule.Validation.Pattern); err != nil {
|
||||
if rule.Validation.Pattern, err = variables.SubstituteVars(log.Log, ctx, rule.Validation.Pattern); err != nil {
|
||||
return fmt.Errorf("userInfo variable used at spec/rules[%d]/validate/pattern", idx)
|
||||
}
|
||||
for idx2, pattern := range rule.Validation.AnyPattern {
|
||||
if rule.Validation.AnyPattern[idx2], err = variables.SubstituteVars(ctx, pattern); err != nil {
|
||||
if rule.Validation.AnyPattern[idx2], err = variables.SubstituteVars(log.Log, ctx, pattern); err != nil {
|
||||
return fmt.Errorf("userInfo variable used at spec/rules[%d]/validate/anyPattern[%d]", idx, idx2)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,57 +4,71 @@ import (
|
|||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/go-logr/logr"
|
||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||
kyvernolister "github.com/nirmata/kyverno/pkg/client/listers/kyverno/v1"
|
||||
"github.com/nirmata/kyverno/pkg/engine/response"
|
||||
"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) {
|
||||
logger := pc.log
|
||||
// - check if there is violation on resource (label:Selector)
|
||||
if pResponse.Resource.Namespace == "" {
|
||||
pv, err := getClusterPV(pc.cpvLister, pResponse.Policy, pResponse.Resource.Kind, pResponse.Resource.Name)
|
||||
pv, err := getClusterPV(pc.cpvLister, pResponse.Policy, pResponse.Resource.Kind, pResponse.Resource.Name, logger)
|
||||
if err != nil {
|
||||
glog.Errorf("failed to cleanUp violations: %v", err)
|
||||
logger.Error(err, "failed to get cluster policy violation on policy and resource", "policy", pResponse.Policy, "kind", pResponse.Resource.Kind, "name", pResponse.Resource.Name)
|
||||
return
|
||||
}
|
||||
|
||||
if reflect.DeepEqual(pv, kyverno.ClusterPolicyViolation{}) {
|
||||
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 {
|
||||
glog.Errorf("failed to delete cluster policy violation %s on %s: %v", pv.Name, pv.Spec.ResourceSpec.ToKey(), err)
|
||||
logger.Error(err, "failed to delete cluster policy violation", "name", pv.Name)
|
||||
} else {
|
||||
logger.Info("deleted cluster policy violation", "name", pv.Name)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// namespace policy violation
|
||||
nspv, err := getNamespacedPV(pc.nspvLister, pResponse.Policy, pResponse.Resource.Kind, pResponse.Resource.Namespace, pResponse.Resource.Name)
|
||||
nspv, err := getNamespacedPV(pc.nspvLister, pResponse.Policy, pResponse.Resource.Kind, pResponse.Resource.Namespace, pResponse.Resource.Name, logger)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
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)
|
||||
return
|
||||
}
|
||||
|
||||
if reflect.DeepEqual(nspv, kyverno.PolicyViolation{}) {
|
||||
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 {
|
||||
glog.Errorf("failed to delete namespaced policy violation %s on %s: %v", nspv.Name, nspv.Spec.ResourceSpec.ToKey(), err)
|
||||
logger.Error(err, "failed to delete cluster policy violation", "name", nspv.Name, "namespace", nspv.Namespace)
|
||||
} else {
|
||||
logger.Info("deleted namespaced policy violation", "name", nspv.Name, "namespace", nspv.Namespace)
|
||||
}
|
||||
}
|
||||
|
||||
// Wont do the claiming of objects, just lookup based on selectors
|
||||
func getClusterPV(pvLister kyvernolister.ClusterPolicyViolationLister, policyName, rkind, rname string) (kyverno.ClusterPolicyViolation, error) {
|
||||
func getClusterPV(pvLister kyvernolister.ClusterPolicyViolationLister, policyName, rkind, rname string, log logr.Logger) (kyverno.ClusterPolicyViolation, error) {
|
||||
var err error
|
||||
// Check Violation on resource
|
||||
pvs, err := pvLister.List(labels.Everything())
|
||||
if err != nil {
|
||||
glog.V(2).Infof("unable to list policy violations : %v", err)
|
||||
log.Error(err, "failed to list cluster policy violations")
|
||||
return kyverno.ClusterPolicyViolation{}, fmt.Errorf("failed to list cluster pv: %v", err)
|
||||
}
|
||||
|
||||
|
@ -69,10 +83,10 @@ func getClusterPV(pvLister kyvernolister.ClusterPolicyViolationLister, policyNam
|
|||
return kyverno.ClusterPolicyViolation{}, nil
|
||||
}
|
||||
|
||||
func getNamespacedPV(nspvLister kyvernolister.PolicyViolationLister, policyName, rkind, rnamespace, rname string) (kyverno.PolicyViolation, error) {
|
||||
func getNamespacedPV(nspvLister kyvernolister.PolicyViolationLister, policyName, rkind, rnamespace, rname string, log logr.Logger) (kyverno.PolicyViolation, error) {
|
||||
nspvs, err := nspvLister.PolicyViolations(rnamespace).List(labels.Everything())
|
||||
if err != nil {
|
||||
glog.V(2).Infof("failed to list namespaced pv: %v", err)
|
||||
log.Error(err, "failed to list namespaced policy violation")
|
||||
return kyverno.PolicyViolation{}, fmt.Errorf("failed to list namespaced pv: %v", err)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,15 +1,13 @@
|
|||
package policy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/golang/glog"
|
||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
func (pc *PolicyController) addClusterPolicyViolation(obj interface{}) {
|
||||
pv := obj.(*kyverno.ClusterPolicyViolation)
|
||||
logger := pc.log.WithValues("kind", pv.Kind, "namespace", pv.Namespace, "name", pv.Name)
|
||||
|
||||
if pv.DeletionTimestamp != nil {
|
||||
// On a restart of the controller manager, it's possible for an object to
|
||||
|
@ -22,15 +20,15 @@ func (pc *PolicyController) addClusterPolicyViolation(obj interface{}) {
|
|||
ps := pc.getPolicyForClusterPolicyViolation(pv)
|
||||
if len(ps) == 0 {
|
||||
// there is no cluster policy for this violation, so we can delete this cluster policy violation
|
||||
glog.V(4).Infof("Cluster Policy Violation %s does not belong to an active policy, will be cleanedup", pv.Name)
|
||||
logger.V(4).Info("Cluster Policy Violation does not belong to an active policy, will be cleanedup")
|
||||
if err := pc.pvControl.DeleteClusterPolicyViolation(pv.Name); err != nil {
|
||||
glog.Errorf("Failed to deleted cluster policy violation %s: %v", pv.Name, err)
|
||||
logger.Error(err, "failed to delete resource")
|
||||
return
|
||||
}
|
||||
glog.V(4).Infof("Cluster Policy Violation %s deleted", pv.Name)
|
||||
logger.V(4).Info("resource deleted")
|
||||
return
|
||||
}
|
||||
glog.V(4).Infof("Cluster Policy Violation %s added.", pv.Name)
|
||||
logger.V(4).Info("resource added")
|
||||
for _, p := range ps {
|
||||
pc.enqueuePolicy(p)
|
||||
}
|
||||
|
@ -44,19 +42,20 @@ func (pc *PolicyController) updateClusterPolicyViolation(old, cur interface{}) {
|
|||
// Two different versions of the same replica set will always have different RVs.
|
||||
return
|
||||
}
|
||||
logger := pc.log.WithValues("kind", curPV.Kind, "namespace", curPV.Namespace, "name", curPV.Name)
|
||||
|
||||
ps := pc.getPolicyForClusterPolicyViolation(curPV)
|
||||
if len(ps) == 0 {
|
||||
// there is no cluster policy for this violation, so we can delete this cluster policy violation
|
||||
glog.V(4).Infof("Cluster Policy Violation %s does not belong to an active policy, will be cleanedup", curPV.Name)
|
||||
logger.V(4).Info("Cluster Policy Violation does not belong to an active policy, will be cleanedup")
|
||||
if err := pc.pvControl.DeleteClusterPolicyViolation(curPV.Name); err != nil {
|
||||
glog.Errorf("Failed to deleted cluster policy violation %s: %v", curPV.Name, err)
|
||||
logger.Error(err, "failed to delete resource")
|
||||
return
|
||||
}
|
||||
glog.V(4).Infof("PolicyViolation %s deleted", curPV.Name)
|
||||
logger.V(4).Info("resource deleted")
|
||||
return
|
||||
}
|
||||
glog.V(4).Infof("Cluster PolicyViolation %s updated", curPV.Name)
|
||||
logger.V(4).Info("resource updated")
|
||||
for _, p := range ps {
|
||||
pc.enqueuePolicy(p)
|
||||
}
|
||||
|
@ -67,6 +66,7 @@ func (pc *PolicyController) updateClusterPolicyViolation(old, cur interface{}) {
|
|||
// a DeletionFinalStateUnknown marker item.
|
||||
|
||||
func (pc *PolicyController) deleteClusterPolicyViolation(obj interface{}) {
|
||||
logger := pc.log
|
||||
pv, ok := obj.(*kyverno.ClusterPolicyViolation)
|
||||
// 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
|
||||
|
@ -75,33 +75,35 @@ func (pc *PolicyController) deleteClusterPolicyViolation(obj interface{}) {
|
|||
if !ok {
|
||||
tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
|
||||
if !ok {
|
||||
glog.Info(fmt.Errorf("Couldn't get object from tombstone %#v", obj))
|
||||
logger.Info("Couldn't get object from tombstone", "obj", obj)
|
||||
return
|
||||
}
|
||||
pv, ok = tombstone.Obj.(*kyverno.ClusterPolicyViolation)
|
||||
if !ok {
|
||||
glog.Info(fmt.Errorf("Couldn't get object from tombstone %#v", obj))
|
||||
logger.Info("Couldn't get object from tombstone", "obj", obj)
|
||||
return
|
||||
}
|
||||
}
|
||||
logger = logger.WithValues("kind", pv.Kind, "namespace", pv.Namespace, "name", pv.Name)
|
||||
ps := pc.getPolicyForClusterPolicyViolation(pv)
|
||||
if len(ps) == 0 {
|
||||
// there is no cluster policy for this violation, so we can delete this cluster policy violation
|
||||
glog.V(4).Infof("Cluster Policy Violation %s does not belong to an active policy, will be cleanedup", pv.Name)
|
||||
logger.V(4).Info("Cluster Policy Violation does not belong to an active policy, will be cleanedup")
|
||||
if err := pc.pvControl.DeleteClusterPolicyViolation(pv.Name); err != nil {
|
||||
glog.Errorf("Failed to deleted cluster policy violation %s: %v", pv.Name, err)
|
||||
logger.Error(err, "failed to delete resource")
|
||||
return
|
||||
}
|
||||
glog.V(4).Infof("Cluster Policy Violation %s deleted", pv.Name)
|
||||
logger.V(4).Info("resource deleted")
|
||||
return
|
||||
}
|
||||
glog.V(4).Infof("Cluster PolicyViolation %s updated", pv.Name)
|
||||
logger.V(4).Info("resource updated")
|
||||
for _, p := range ps {
|
||||
pc.enqueuePolicy(p)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
if err != nil || len(policies) == 0 {
|
||||
return nil
|
||||
|
@ -113,8 +115,7 @@ func (pc *PolicyController) getPolicyForClusterPolicyViolation(pv *kyverno.Clust
|
|||
if len(policies) > 1 {
|
||||
// ControllerRef will ensure we don't do anything crazy, but more than one
|
||||
// item in this list nevertheless constitutes user error.
|
||||
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)
|
||||
logger.V(4).Info("user error! more than one policy is selecting policy violation", "labels", pv.Labels, "policy", policies[0].Name)
|
||||
}
|
||||
return policies
|
||||
}
|
||||
|
|
|
@ -3,10 +3,10 @@ package policy
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/golang/glog"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
)
|
||||
|
||||
func buildPolicyLabel(policyName string) (labels.Selector, error) {
|
||||
|
@ -27,7 +27,7 @@ func buildPolicyLabel(policyName string) (labels.Selector, error) {
|
|||
func transformResource(resource unstructured.Unstructured) []byte {
|
||||
data, err := resource.MarshalJSON()
|
||||
if err != nil {
|
||||
glog.Errorf("failed to marshall resource %v: %v", resource, err)
|
||||
log.Log.Error(err, "failed to marshal resource")
|
||||
return nil
|
||||
}
|
||||
return data
|
||||
|
|
85
pkg/policy/common/common.go
Normal file
85
pkg/policy/common/common.go
Normal file
|
@ -0,0 +1,85 @@
|
|||
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,10 +1,9 @@
|
|||
package policy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/go-logr/logr"
|
||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||
kyvernoclient "github.com/nirmata/kyverno/pkg/client/clientset/versioned"
|
||||
"github.com/nirmata/kyverno/pkg/client/clientset/versioned/scheme"
|
||||
|
@ -72,6 +71,7 @@ type PolicyController struct {
|
|||
pvGenerator policyviolation.GeneratorInterface
|
||||
// resourceWebhookWatcher queues the webhook creation request, creates the webhook
|
||||
resourceWebhookWatcher *webhookconfig.ResourceWebhookRegister
|
||||
log logr.Logger
|
||||
}
|
||||
|
||||
// NewPolicyController create a new PolicyController
|
||||
|
@ -84,10 +84,11 @@ func NewPolicyController(kyvernoClient *kyvernoclient.Clientset,
|
|||
eventGen event.Interface,
|
||||
pvGenerator policyviolation.GeneratorInterface,
|
||||
pMetaStore policystore.UpdateInterface,
|
||||
resourceWebhookWatcher *webhookconfig.ResourceWebhookRegister) (*PolicyController, error) {
|
||||
resourceWebhookWatcher *webhookconfig.ResourceWebhookRegister,
|
||||
log logr.Logger) (*PolicyController, error) {
|
||||
// Event broad caster
|
||||
eventBroadcaster := record.NewBroadcaster()
|
||||
eventBroadcaster.StartLogging(glog.Infof)
|
||||
eventBroadcaster.StartLogging(log.Info)
|
||||
eventInterface, err := client.GetEventsInterface()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -104,6 +105,7 @@ func NewPolicyController(kyvernoClient *kyvernoclient.Clientset,
|
|||
pMetaStore: pMetaStore,
|
||||
pvGenerator: pvGenerator,
|
||||
resourceWebhookWatcher: resourceWebhookWatcher,
|
||||
log: log,
|
||||
}
|
||||
|
||||
pc.pvControl = RealPVControl{Client: kyvernoClient, Recorder: pc.eventRecorder}
|
||||
|
@ -145,6 +147,7 @@ func NewPolicyController(kyvernoClient *kyvernoclient.Clientset,
|
|||
}
|
||||
|
||||
func (pc *PolicyController) addPolicy(obj interface{}) {
|
||||
logger := pc.log
|
||||
p := obj.(*kyverno.ClusterPolicy)
|
||||
// Only process policies that are enabled for "background" execution
|
||||
// policy.spec.background -> "True"
|
||||
|
@ -168,19 +171,19 @@ func (pc *PolicyController) addPolicy(obj interface{}) {
|
|||
return
|
||||
}
|
||||
}
|
||||
|
||||
glog.V(4).Infof("Adding Policy %s", p.Name)
|
||||
logger.V(4).Info("adding policy", "name", p.Name)
|
||||
pc.enqueuePolicy(p)
|
||||
}
|
||||
|
||||
func (pc *PolicyController) updatePolicy(old, cur interface{}) {
|
||||
logger := pc.log
|
||||
oldP := old.(*kyverno.ClusterPolicy)
|
||||
curP := cur.(*kyverno.ClusterPolicy)
|
||||
// TODO: optimize this : policy meta-store
|
||||
// Update policy-> (remove,add)
|
||||
err := pc.pMetaStore.UnRegister(*oldP)
|
||||
if err != nil {
|
||||
glog.Infof("Failed to unregister policy %s", oldP.Name)
|
||||
logger.Error(err, "failed to unregister policy", "name", oldP.Name)
|
||||
}
|
||||
pc.pMetaStore.Register(*curP)
|
||||
|
||||
|
@ -203,28 +206,29 @@ func (pc *PolicyController) updatePolicy(old, cur interface{}) {
|
|||
return
|
||||
}
|
||||
}
|
||||
glog.V(4).Infof("Updating Policy %s", oldP.Name)
|
||||
logger.V(4).Info("updating policy", "name", oldP.Name)
|
||||
pc.enqueuePolicy(curP)
|
||||
}
|
||||
|
||||
func (pc *PolicyController) deletePolicy(obj interface{}) {
|
||||
logger := pc.log
|
||||
p, ok := obj.(*kyverno.ClusterPolicy)
|
||||
if !ok {
|
||||
tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
|
||||
if !ok {
|
||||
glog.Info(fmt.Errorf("Couldn't get object from tombstone %#v", obj))
|
||||
logger.Info("couldnt get object from tomstone", "obj", obj)
|
||||
return
|
||||
}
|
||||
p, ok = tombstone.Obj.(*kyverno.ClusterPolicy)
|
||||
if !ok {
|
||||
glog.Info(fmt.Errorf("Tombstone contained object that is not a Policy %#v", obj))
|
||||
logger.Info("tombstone container object that is not a policy", "obj", obj)
|
||||
return
|
||||
}
|
||||
}
|
||||
glog.V(4).Infof("Deleting Policy %s", p.Name)
|
||||
logger.V(4).Info("deleting policy", "name", p.Name)
|
||||
// Unregister from policy meta-store
|
||||
if err := pc.pMetaStore.UnRegister(*p); err != nil {
|
||||
glog.Infof("failed to unregister policy %s", p.Name)
|
||||
logger.Error(err, "failed to unregister policy", "name", p.Name)
|
||||
}
|
||||
// we process policies that are not set of background processing as we need to perform policy violation
|
||||
// cleanup when a policy is deleted.
|
||||
|
@ -232,9 +236,10 @@ func (pc *PolicyController) deletePolicy(obj interface{}) {
|
|||
}
|
||||
|
||||
func (pc *PolicyController) enqueue(policy *kyverno.ClusterPolicy) {
|
||||
logger := pc.log
|
||||
key, err := cache.MetaNamespaceKeyFunc(policy)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
logger.Error(err, "failed to enqueu policy")
|
||||
return
|
||||
}
|
||||
pc.queue.Add(key)
|
||||
|
@ -242,15 +247,16 @@ func (pc *PolicyController) enqueue(policy *kyverno.ClusterPolicy) {
|
|||
|
||||
// Run begins watching and syncing.
|
||||
func (pc *PolicyController) Run(workers int, stopCh <-chan struct{}) {
|
||||
logger := pc.log
|
||||
|
||||
defer utilruntime.HandleCrash()
|
||||
defer pc.queue.ShutDown()
|
||||
|
||||
glog.Info("Starting policy controller")
|
||||
defer glog.Info("Shutting down policy controller")
|
||||
logger.Info("starting")
|
||||
defer logger.Info("shutting down")
|
||||
|
||||
if !cache.WaitForCacheSync(stopCh, pc.pListerSynced, pc.cpvListerSynced, pc.nspvListerSynced) {
|
||||
glog.Error("failed to sync informer cache")
|
||||
logger.Info("failed to sync informer cache")
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -285,31 +291,33 @@ func (pc *PolicyController) processNextWorkItem() bool {
|
|||
}
|
||||
|
||||
func (pc *PolicyController) handleErr(err error, key interface{}) {
|
||||
logger := pc.log
|
||||
if err == nil {
|
||||
pc.queue.Forget(key)
|
||||
return
|
||||
}
|
||||
|
||||
if pc.queue.NumRequeues(key) < maxRetries {
|
||||
glog.V(2).Infof("Error syncing Policy %v: %v", key, err)
|
||||
logger.Error(err, "failed to sync policy", "key", key)
|
||||
pc.queue.AddRateLimited(key)
|
||||
return
|
||||
}
|
||||
|
||||
utilruntime.HandleError(err)
|
||||
glog.V(2).Infof("Dropping policy %q out of the queue: %v", key, err)
|
||||
logger.V(2).Info("dropping policy out of queue", "key", key)
|
||||
pc.queue.Forget(key)
|
||||
}
|
||||
|
||||
func (pc *PolicyController) syncPolicy(key string) error {
|
||||
logger := pc.log
|
||||
startTime := time.Now()
|
||||
glog.V(4).Infof("Started syncing policy %q (%v)", key, startTime)
|
||||
logger.V(4).Info("started syncing policy", "key", key, "startTime", startTime)
|
||||
defer func() {
|
||||
glog.V(4).Infof("Finished syncing policy %q (%v)", key, time.Since(startTime))
|
||||
logger.V(4).Info("finished syncing policy", "key", key, "processingTime", time.Since(startTime))
|
||||
}()
|
||||
policy, err := pc.pLister.Get(key)
|
||||
if errors.IsNotFound(err) {
|
||||
glog.V(2).Infof("Policy %v has been deleted", key)
|
||||
logger.V(2).Info("policy deleted", "key", key)
|
||||
// delete cluster policy violation
|
||||
if err := pc.deleteClusterPolicyViolations(key); err != nil {
|
||||
return err
|
||||
|
@ -322,8 +330,7 @@ func (pc *PolicyController) syncPolicy(key string) error {
|
|||
// remove webhook configurations if there are no policies
|
||||
if err := pc.removeResourceWebhookConfiguration(); err != nil {
|
||||
// do not fail, if unable to delete resource webhook config
|
||||
glog.V(4).Infof("failed to remove resource webhook configuration: %v", err)
|
||||
glog.Errorln(err)
|
||||
logger.Error(err, "failed to remove resource webhook configurations")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/go-logr/logr"
|
||||
"github.com/minio/minio/pkg/wildcard"
|
||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||
"github.com/nirmata/kyverno/pkg/config"
|
||||
|
@ -19,27 +19,27 @@ import (
|
|||
)
|
||||
|
||||
func (pc *PolicyController) processExistingResources(policy kyverno.ClusterPolicy) []response.EngineResponse {
|
||||
logger := pc.log.WithValues("policy", policy.Name)
|
||||
// Parse through all the resources
|
||||
// drops the cache after configured rebuild time
|
||||
pc.rm.Drop()
|
||||
var engineResponses []response.EngineResponse
|
||||
// get resource that are satisfy the resource description defined in the rules
|
||||
resourceMap := listResources(pc.client, policy, pc.configHandler)
|
||||
resourceMap := listResources(pc.client, policy, pc.configHandler, logger)
|
||||
for _, resource := range resourceMap {
|
||||
// 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()) {
|
||||
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())
|
||||
logger.V(4).Info("policy and resource already processed", "policyResourceVersion", policy.ResourceVersion, "resourceResourceVersion", resource.GetResourceVersion(), "kind", resource.GetKind(), "namespace", resource.GetNamespace(), "name", resource.GetName())
|
||||
continue
|
||||
}
|
||||
|
||||
// skip reporting violation on pod which has annotation pod-policies.kyverno.io/autogen-applied
|
||||
if skipPodApplication(resource) {
|
||||
if skipPodApplication(resource, logger) {
|
||||
continue
|
||||
}
|
||||
|
||||
// apply the policy on each
|
||||
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)
|
||||
engineResponse := applyPolicy(policy, resource, logger)
|
||||
// get engine response for mutation & validation independently
|
||||
engineResponses = append(engineResponses, engineResponse...)
|
||||
// post-processing, register the resource as processed
|
||||
|
@ -48,36 +48,26 @@ func (pc *PolicyController) processExistingResources(policy kyverno.ClusterPolic
|
|||
return engineResponses
|
||||
}
|
||||
|
||||
func listResources(client *client.Client, policy kyverno.ClusterPolicy, configHandler config.Interface) map[string]unstructured.Unstructured {
|
||||
func listResources(client *client.Client, policy kyverno.ClusterPolicy, configHandler config.Interface, log logr.Logger) map[string]unstructured.Unstructured {
|
||||
// key uid
|
||||
resourceMap := map[string]unstructured.Unstructured{}
|
||||
|
||||
for _, rule := range policy.Spec.Rules {
|
||||
// resources that match
|
||||
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
|
||||
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 {
|
||||
namespaces = append(namespaces, rule.MatchResources.Namespaces...)
|
||||
glog.V(4).Infof("namespaces specified for inclusion: %v", rule.MatchResources.Namespaces)
|
||||
log.V(4).Info("namespaces included", "namespaces", rule.MatchResources.Namespaces)
|
||||
} else {
|
||||
glog.V(4).Infof("processing policy %s rule %s, namespace not defined, getting all namespaces ", policy.Name, rule.Name)
|
||||
log.V(4).Info("processing all namespaces", "rule", rule.Name)
|
||||
// get all namespaces
|
||||
namespaces = getAllNamespaces(client)
|
||||
namespaces = getAllNamespaces(client, log)
|
||||
}
|
||||
|
||||
// get resources in the namespaces
|
||||
for _, ns := range namespaces {
|
||||
rMap := getResourcesPerNamespace(k, client, ns, rule, configHandler)
|
||||
rMap := getResourcesPerNamespace(k, client, ns, rule, configHandler, log)
|
||||
mergeresources(resourceMap, rMap)
|
||||
}
|
||||
|
||||
|
@ -86,16 +76,16 @@ func listResources(client *client.Client, policy kyverno.ClusterPolicy, configHa
|
|||
return resourceMap
|
||||
}
|
||||
|
||||
func getResourcesPerNamespace(kind string, client *client.Client, namespace string, rule kyverno.Rule, configHandler config.Interface) map[string]unstructured.Unstructured {
|
||||
func getResourcesPerNamespace(kind string, client *client.Client, namespace string, rule kyverno.Rule, configHandler config.Interface, log logr.Logger) map[string]unstructured.Unstructured {
|
||||
resourceMap := map[string]unstructured.Unstructured{}
|
||||
// merge include and exclude label selector values
|
||||
ls := rule.MatchResources.Selector
|
||||
// ls := mergeLabelSectors(rule.MatchResources.Selector, rule.ExcludeResources.Selector)
|
||||
// list resources
|
||||
glog.V(4).Infof("get resources for kind %s, namespace %s, selector %v", kind, namespace, rule.MatchResources.Selector)
|
||||
log.V(4).Info("list resources to be processed")
|
||||
list, err := client.ListResource(kind, namespace, ls)
|
||||
if err != nil {
|
||||
glog.Infof("unable to get resources: err %v", err)
|
||||
log.Error(err, "failed to list resources", "kind", kind)
|
||||
return nil
|
||||
}
|
||||
// filter based on name
|
||||
|
@ -103,7 +93,6 @@ func getResourcesPerNamespace(kind string, client *client.Client, namespace stri
|
|||
// match name
|
||||
if rule.MatchResources.Name != "" {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -118,12 +107,11 @@ func getResourcesPerNamespace(kind string, client *client.Client, namespace stri
|
|||
|
||||
// exclude the resources
|
||||
// skip resources to be filtered
|
||||
excludeResources(resourceMap, rule.ExcludeResources.ResourceDescription, configHandler)
|
||||
// glog.V(4).Infof("resource map: %v", resourceMap)
|
||||
excludeResources(resourceMap, rule.ExcludeResources.ResourceDescription, configHandler, log)
|
||||
return resourceMap
|
||||
}
|
||||
|
||||
func excludeResources(included map[string]unstructured.Unstructured, exclude kyverno.ResourceDescription, configHandler config.Interface) {
|
||||
func excludeResources(included map[string]unstructured.Unstructured, exclude kyverno.ResourceDescription, configHandler config.Interface, log logr.Logger) {
|
||||
if reflect.DeepEqual(exclude, (kyverno.ResourceDescription{})) {
|
||||
return
|
||||
}
|
||||
|
@ -154,7 +142,7 @@ func excludeResources(included map[string]unstructured.Unstructured, exclude kyv
|
|||
selector, err := metav1.LabelSelectorAsSelector(exclude.Selector)
|
||||
// if the label selector is incorrect, should be fail or
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
log.Error(err, "failed to build label selector")
|
||||
return Skip
|
||||
}
|
||||
if selector.Matches(labels.Set(labelsMap)) {
|
||||
|
@ -205,8 +193,6 @@ func excludeResources(included map[string]unstructured.Unstructured, exclude kyv
|
|||
}
|
||||
// exclude the filtered resources
|
||||
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)
|
||||
continue
|
||||
}
|
||||
|
@ -244,12 +230,13 @@ func mergeresources(a, b map[string]unstructured.Unstructured) {
|
|||
}
|
||||
}
|
||||
|
||||
func getAllNamespaces(client *client.Client) []string {
|
||||
func getAllNamespaces(client *client.Client, log logr.Logger) []string {
|
||||
|
||||
var namespaces []string
|
||||
// get all namespaces
|
||||
nsList, err := client.ListResource("Namespace", "", nil)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
log.Error(err, "failed to list namespaces")
|
||||
return namespaces
|
||||
}
|
||||
for _, ns := range nsList.Items {
|
||||
|
@ -291,14 +278,11 @@ type resourceManager interface {
|
|||
//TODO: or drop based on the size
|
||||
func (rm *ResourceManager) Drop() {
|
||||
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 {
|
||||
rm.mux.Lock()
|
||||
defer rm.mux.Unlock()
|
||||
rm.data = map[string]interface{}{}
|
||||
rm.time = time.Now()
|
||||
glog.V(4).Infof("dropping cache at time %v", rm.time)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -327,14 +311,14 @@ func buildKey(policy, pv, kind, ns, name, rv string) string {
|
|||
return policy + "/" + pv + "/" + kind + "/" + ns + "/" + name + "/" + rv
|
||||
}
|
||||
|
||||
func skipPodApplication(resource unstructured.Unstructured) bool {
|
||||
func skipPodApplication(resource unstructured.Unstructured, log logr.Logger) bool {
|
||||
if resource.GetKind() != "Pod" {
|
||||
return false
|
||||
}
|
||||
|
||||
annotation := resource.GetAnnotations()
|
||||
if _, ok := annotation[engine.PodTemplateAnnotation]; ok {
|
||||
glog.V(4).Infof("Policies already processed on pod controllers, skip processing policy on Pod/%s/%s", resource.GetNamespace(), resource.GetName())
|
||||
log.V(4).Info("Policies already processed on pod controllers, skip processing policy on Pod", "kind", resource.GetKind(), "namespace", resource.GetNamespace(), "name", resource.GetName())
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
74
pkg/policy/generate/auth.go
Normal file
74
pkg/policy/generate/auth.go
Normal file
|
@ -0,0 +1,74 @@
|
|||
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
|
||||
}
|
21
pkg/policy/generate/fake.go
Normal file
21
pkg/policy/generate/fake.go
Normal file
|
@ -0,0 +1,21 @@
|
|||
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
|
||||
}
|
31
pkg/policy/generate/fake/auth.go
Normal file
31
pkg/policy/generate/fake/auth.go
Normal file
|
@ -0,0 +1,31 @@
|
|||
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
|
||||
}
|
151
pkg/policy/generate/validate.go
Normal file
151
pkg/policy/generate/validate.go
Normal file
|
@ -0,0 +1,151 @@
|
|||
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
|
||||
}
|
89
pkg/policy/generate/validate_test.go
Normal file
89
pkg/policy/generate/validate_test.go
Normal file
|
@ -0,0 +1,89 @@
|
|||
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)
|
||||
}
|
||||
}
|
63
pkg/policy/mutate/validate.go
Normal file
63
pkg/policy/mutate/validate.go
Normal file
|
@ -0,0 +1,63 @@
|
|||
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)
|
||||
}
|
151
pkg/policy/mutate/validate_test.go
Normal file
151
pkg/policy/mutate/validate_test.go
Normal file
|
@ -0,0 +1,151 @@
|
|||
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
|
||||
|
||||
import (
|
||||
"github.com/golang/glog"
|
||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||
cache "k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
func (pc *PolicyController) addNamespacedPolicyViolation(obj interface{}) {
|
||||
pv := obj.(*kyverno.PolicyViolation)
|
||||
logger := pc.log.WithValues("kind", pv.Kind, "namespace", pv.Namespace, "name", pv.Name)
|
||||
|
||||
if pv.DeletionTimestamp != nil {
|
||||
// On a restart of the controller manager, it's possible for an object to
|
||||
|
@ -20,15 +20,16 @@ func (pc *PolicyController) addNamespacedPolicyViolation(obj interface{}) {
|
|||
ps := pc.getPolicyForNamespacedPolicyViolation(pv)
|
||||
if len(ps) == 0 {
|
||||
// there is no cluster policy for this violation, so we can delete this cluster policy violation
|
||||
glog.V(4).Infof("PolicyViolation %s does not belong to an active policy, will be cleanedup", pv.Name)
|
||||
logger.V(4).Info("namepaced policy violation does not belong to an active policy, will be cleanedup")
|
||||
if err := pc.pvControl.DeleteNamespacedPolicyViolation(pv.Namespace, pv.Name); err != nil {
|
||||
glog.Errorf("Failed to deleted policy violation %s: %v", pv.Name, err)
|
||||
logger.Error(err, "failed to delete resource")
|
||||
return
|
||||
}
|
||||
glog.V(4).Infof("PolicyViolation %s deleted", pv.Name)
|
||||
logger.V(4).Info("resource deleted")
|
||||
return
|
||||
}
|
||||
glog.V(4).Infof("Orphan Policy Violation %s added.", pv.Name)
|
||||
|
||||
logger.V(4).Info("resource added")
|
||||
for _, p := range ps {
|
||||
pc.enqueuePolicy(p)
|
||||
}
|
||||
|
@ -42,19 +43,20 @@ func (pc *PolicyController) updateNamespacedPolicyViolation(old, cur interface{}
|
|||
// Two different versions of the same replica set will always have different RVs.
|
||||
return
|
||||
}
|
||||
logger := pc.log.WithValues("kind", curPV.Kind, "namespace", curPV.Namespace, "name", curPV.Name)
|
||||
|
||||
ps := pc.getPolicyForNamespacedPolicyViolation(curPV)
|
||||
if len(ps) == 0 {
|
||||
// there is no namespaced policy for this violation, so we can delete this cluster policy violation
|
||||
glog.V(4).Infof("Namespaced Policy Violation %s does not belong to an active policy, will be cleanedup", curPV.Name)
|
||||
logger.V(4).Info("nameapced policy violation does not belong to an active policy, will be cleanedup")
|
||||
if err := pc.pvControl.DeleteNamespacedPolicyViolation(curPV.Namespace, curPV.Name); err != nil {
|
||||
glog.Errorf("Failed to deleted namespaced policy violation %s: %v", curPV.Name, err)
|
||||
logger.Error(err, "failed to delete resource")
|
||||
return
|
||||
}
|
||||
glog.V(4).Infof("Namespaced Policy Violation %s deleted", curPV.Name)
|
||||
logger.V(4).Info("resource deleted")
|
||||
return
|
||||
}
|
||||
glog.V(4).Infof("Namespaced Policy sViolation %s updated", curPV.Name)
|
||||
logger.V(4).Info("resource updated")
|
||||
for _, p := range ps {
|
||||
pc.enqueuePolicy(p)
|
||||
}
|
||||
|
@ -62,6 +64,7 @@ func (pc *PolicyController) updateNamespacedPolicyViolation(old, cur interface{}
|
|||
}
|
||||
|
||||
func (pc *PolicyController) deleteNamespacedPolicyViolation(obj interface{}) {
|
||||
logger := pc.log
|
||||
pv, ok := obj.(*kyverno.PolicyViolation)
|
||||
// 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
|
||||
|
@ -70,34 +73,36 @@ func (pc *PolicyController) deleteNamespacedPolicyViolation(obj interface{}) {
|
|||
if !ok {
|
||||
tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
|
||||
if !ok {
|
||||
glog.Infof("Couldn't get object from tombstone %#v", obj)
|
||||
logger.Info("Couldn't get object from tombstone", "obj", obj)
|
||||
return
|
||||
}
|
||||
pv, ok = tombstone.Obj.(*kyverno.PolicyViolation)
|
||||
if !ok {
|
||||
glog.Infof("Couldn't get object from tombstone %#v", obj)
|
||||
logger.Info("Couldn't get object from tombstone", "obj", obj)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
logger = logger.WithValues("kind", pv.Kind, "namespace", pv.Namespace, "name", pv.Name)
|
||||
ps := pc.getPolicyForNamespacedPolicyViolation(pv)
|
||||
if len(ps) == 0 {
|
||||
// there is no cluster policy for this violation, so we can delete this cluster policy violation
|
||||
glog.V(4).Infof("Namespaced Policy Violation %s does not belong to an active policy, will be cleanedup", pv.Name)
|
||||
logger.V(4).Info("nameapced policy violation does not belong to an active policy, will be cleanedup")
|
||||
if err := pc.pvControl.DeleteNamespacedPolicyViolation(pv.Namespace, pv.Name); err != nil {
|
||||
glog.Errorf("Failed to deleted namespaced policy violation %s: %v", pv.Name, err)
|
||||
logger.Error(err, "failed to delete resource")
|
||||
return
|
||||
}
|
||||
glog.V(4).Infof("Namespaced Policy Violation %s deleted", pv.Name)
|
||||
logger.V(4).Info("resource deleted")
|
||||
return
|
||||
}
|
||||
glog.V(4).Infof("Namespaced PolicyViolation %s updated", pv.Name)
|
||||
logger.V(4).Info("resource updated")
|
||||
for _, p := range ps {
|
||||
pc.enqueuePolicy(p)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
if err != nil || len(policies) == 0 {
|
||||
return nil
|
||||
|
@ -109,8 +114,7 @@ func (pc *PolicyController) getPolicyForNamespacedPolicyViolation(pv *kyverno.Po
|
|||
if len(policies) > 1 {
|
||||
// ControllerRef will ensure we don't do anything crazy, but more than one
|
||||
// item in this list nevertheless constitutes user error.
|
||||
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)
|
||||
logger.V(4).Info("user error! more than one policy is selecting policy violation", "labels", pv.Labels, "policy", policies[0].Name)
|
||||
}
|
||||
return policies
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ package policy
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/go-logr/logr"
|
||||
"github.com/nirmata/kyverno/pkg/engine/response"
|
||||
"github.com/nirmata/kyverno/pkg/event"
|
||||
"github.com/nirmata/kyverno/pkg/policyviolation"
|
||||
|
@ -13,11 +13,12 @@ import (
|
|||
// - has violation -> report
|
||||
// - no violation -> cleanup policy violations
|
||||
func (pc *PolicyController) cleanupAndReport(engineResponses []response.EngineResponse) {
|
||||
logger := pc.log
|
||||
// generate Events
|
||||
eventInfos := generateEvents(engineResponses)
|
||||
eventInfos := generateEvents(pc.log, engineResponses)
|
||||
pc.eventGen.Add(eventInfos...)
|
||||
// create policy violation
|
||||
pvInfos := policyviolation.GeneratePVsFromEngineResponse(engineResponses)
|
||||
pvInfos := policyviolation.GeneratePVsFromEngineResponse(engineResponses, logger)
|
||||
for i := range pvInfos {
|
||||
pvInfos[i].FromSync = true
|
||||
}
|
||||
|
@ -29,39 +30,27 @@ func (pc *PolicyController) cleanupAndReport(engineResponses []response.EngineRe
|
|||
pc.cleanUp(engineResponses)
|
||||
}
|
||||
|
||||
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 {
|
||||
func generateEvents(log logr.Logger, ers []response.EngineResponse) []event.Info {
|
||||
var eventInfos []event.Info
|
||||
for _, er := range ers {
|
||||
if er.IsSuccesful() {
|
||||
continue
|
||||
}
|
||||
eventInfos = append(eventInfos, generateEventsPerEr(er)...)
|
||||
eventInfos = append(eventInfos, generateEventsPerEr(log, er)...)
|
||||
}
|
||||
return eventInfos
|
||||
}
|
||||
|
||||
func generateEventsPerEr(er response.EngineResponse) []event.Info {
|
||||
func generateEventsPerEr(log logr.Logger, 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
|
||||
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)
|
||||
logger.V(4).Info("reporting results for policy")
|
||||
for _, rule := range er.PolicyResponse.Rules {
|
||||
if rule.Success {
|
||||
continue
|
||||
}
|
||||
// generate event on resource for each failed rule
|
||||
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)
|
||||
logger.V(4).Info("generating event on resource")
|
||||
e := event.Info{}
|
||||
e.Kind = er.PolicyResponse.Resource.Kind
|
||||
e.Namespace = er.PolicyResponse.Resource.Namespace
|
||||
|
@ -76,7 +65,7 @@ func generateEventsPerEr(er response.EngineResponse) []event.Info {
|
|||
}
|
||||
|
||||
// generate a event on policy for all failed rules
|
||||
glog.V(4).Infof("generation event on policy '%s'", er.PolicyResponse.Policy)
|
||||
logger.V(4).Info("generating event on policy")
|
||||
e := event.Info{}
|
||||
e.Kind = "ClusterPolicy"
|
||||
e.Namespace = ""
|
||||
|
|
|
@ -1,17 +1,16 @@
|
|||
package policy
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/nirmata/kyverno/pkg/openapi"
|
||||
|
||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||
"github.com/nirmata/kyverno/pkg/engine/anchor"
|
||||
dclient "github.com/nirmata/kyverno/pkg/dclient"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
@ -19,7 +18,13 @@ import (
|
|||
// Validate does some initial check to verify some conditions
|
||||
// - One operation per rule
|
||||
// - ResourceDescription mandatory checks
|
||||
func Validate(p kyverno.ClusterPolicy) error {
|
||||
func Validate(policyRaw []byte, client *dclient.Client, mock bool) error {
|
||||
var p kyverno.ClusterPolicy
|
||||
err := json.Unmarshal(policyRaw, &p)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to unmarshal policy admission request err %v", err)
|
||||
}
|
||||
|
||||
if path, err := validateUniqueRuleName(p); err != nil {
|
||||
return fmt.Errorf("path: spec.%s: %v", path, err)
|
||||
}
|
||||
|
@ -52,24 +57,12 @@ func Validate(p kyverno.ClusterPolicy) error {
|
|||
// 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)
|
||||
}
|
||||
// Operation Validation
|
||||
// Mutation
|
||||
if rule.HasMutate() {
|
||||
if path, err := validateMutation(rule.Mutation); err != nil {
|
||||
return fmt.Errorf("path: spec.rules[%d].mutate.%s.: %v", i, path, 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)
|
||||
}
|
||||
// validate rule actions
|
||||
// - Mutate
|
||||
// - Validate
|
||||
// - Generate
|
||||
if err := validateActions(i, rule, client, mock); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// If a rules match block does not match any kind,
|
||||
|
@ -82,7 +75,7 @@ func Validate(p kyverno.ClusterPolicy) error {
|
|||
}
|
||||
}
|
||||
|
||||
if err := openapi.ValidatePolicyMutation(p); err != nil {
|
||||
if err := openapi.ValidatePolicyFields(policyRaw); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -268,193 +261,3 @@ func validateResourceDescription(rd kyverno.ResourceDescription) error {
|
|||
}
|
||||
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
|
||||
}
|
||||
|
|
61
pkg/policy/validate/validate.go
Normal file
61
pkg/policy/validate/validate.go
Normal file
|
@ -0,0 +1,61 @@
|
|||
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
|
||||
}
|
381
pkg/policy/validate/validate_test.go
Normal file
381
pkg/policy/validate/validate_test.go
Normal file
|
@ -0,0 +1,381 @@
|
|||
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,369 +287,6 @@ func Test_Validate_ResourceDescription_InvalidSelector(t *testing.T) {
|
|||
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) {
|
||||
rawPolicy := []byte(`
|
||||
{
|
||||
|
@ -732,227 +369,8 @@ func Test_Validate_Policy(t *testing.T) {
|
|||
}
|
||||
}`)
|
||||
|
||||
var policy kyverno.ClusterPolicy
|
||||
err := json.Unmarshal(rawPolicy, &policy)
|
||||
err := Validate(rawPolicy, nil, true)
|
||||
assert.NilError(t, err)
|
||||
|
||||
err = Validate(policy)
|
||||
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) {
|
||||
|
@ -1093,11 +511,7 @@ func Test_Validate_ErrorFormat(t *testing.T) {
|
|||
}
|
||||
`)
|
||||
|
||||
var policy kyverno.ClusterPolicy
|
||||
err := json.Unmarshal(rawPolicy, &policy)
|
||||
assert.NilError(t, err)
|
||||
|
||||
err = Validate(policy)
|
||||
err := Validate(rawPolicy, nil, true)
|
||||
assert.Assert(t, err != nil)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,25 +1,25 @@
|
|||
package policy
|
||||
|
||||
import (
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
func (pc *PolicyController) removeResourceWebhookConfiguration() error {
|
||||
logger := pc.log
|
||||
var err error
|
||||
// get all existing policies
|
||||
policies, err := pc.pLister.List(labels.NewSelector())
|
||||
if err != nil {
|
||||
glog.V(4).Infof("failed to list policies: %v", err)
|
||||
logger.Error(err, "failed to list policies")
|
||||
return err
|
||||
}
|
||||
|
||||
if len(policies) == 0 {
|
||||
glog.V(4).Info("no policies loaded, removing resource webhook configuration if one exists")
|
||||
logger.V(4).Info("no policies loaded, removing resource webhook configuration if one exists")
|
||||
return pc.resourceWebhookWatcher.RemoveResourceWebhookConfiguration()
|
||||
}
|
||||
|
||||
glog.V(4).Info("no policies with mutating or validating webhook configurations, remove resource webhook configuration if one exists")
|
||||
logger.V(4).Info("no policies with mutating or validating webhook configurations, remove resource webhook configuration if one exists")
|
||||
|
||||
return pc.resourceWebhookWatcher.RemoveResourceWebhookConfiguration()
|
||||
}
|
||||
|
|
|
@ -2,16 +2,16 @@ package policystatus
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
|
||||
"github.com/nirmata/kyverno/pkg/client/clientset/versioned"
|
||||
|
||||
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,
|
||||
|
@ -111,8 +111,7 @@ func (s *Sync) updateStatusCache(stopCh <-chan struct{}) {
|
|||
s.cache.keyToMutex.Get(statusUpdater.PolicyName()).Unlock()
|
||||
oldStatus, _ := json.Marshal(status)
|
||||
newStatus, _ := json.Marshal(updatedStatus)
|
||||
|
||||
glog.V(4).Infof("\nupdated status of policy - %v\noldStatus:\n%v\nnewStatus:\n%v\n", statusUpdater.PolicyName(), string(oldStatus), string(newStatus))
|
||||
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)))
|
||||
case <-stopCh:
|
||||
return
|
||||
}
|
||||
|
@ -140,7 +139,7 @@ func (s *Sync) updatePolicyStatus() {
|
|||
s.cache.dataMu.Lock()
|
||||
delete(s.cache.data, policyName)
|
||||
s.cache.dataMu.Unlock()
|
||||
glog.V(4).Info(err)
|
||||
log.Log.Error(err, "failed to update policy status")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,12 +3,11 @@ package policystore
|
|||
import (
|
||||
"sync"
|
||||
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/go-logr/logr"
|
||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||
kyvernoinformer "github.com/nirmata/kyverno/pkg/client/informers/externalversions/kyverno/v1"
|
||||
kyvernolister "github.com/nirmata/kyverno/pkg/client/listers/kyverno/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
|
@ -24,6 +23,7 @@ type PolicyStore struct {
|
|||
pLister kyvernolister.ClusterPolicyLister
|
||||
// returns true if the cluster policy store has been synced at least once
|
||||
pSynched cache.InformerSynced
|
||||
log logr.Logger
|
||||
}
|
||||
|
||||
//UpdateInterface provides api to update policies
|
||||
|
@ -40,25 +40,29 @@ type LookupInterface interface {
|
|||
}
|
||||
|
||||
// NewPolicyStore returns a new policy store
|
||||
func NewPolicyStore(pInformer kyvernoinformer.ClusterPolicyInformer) *PolicyStore {
|
||||
func NewPolicyStore(pInformer kyvernoinformer.ClusterPolicyInformer,
|
||||
log logr.Logger) *PolicyStore {
|
||||
ps := PolicyStore{
|
||||
data: make(kindMap),
|
||||
pLister: pInformer.Lister(),
|
||||
pSynched: pInformer.Informer().HasSynced,
|
||||
log: log,
|
||||
}
|
||||
return &ps
|
||||
}
|
||||
|
||||
//Run checks syncing
|
||||
func (ps *PolicyStore) Run(stopCh <-chan struct{}) {
|
||||
logger := ps.log
|
||||
if !cache.WaitForCacheSync(stopCh, ps.pSynched) {
|
||||
glog.Error("policy meta store: failed to sync informer cache")
|
||||
logger.Info("failed to sync informer cache")
|
||||
}
|
||||
}
|
||||
|
||||
//Register a new policy
|
||||
func (ps *PolicyStore) Register(policy kyverno.ClusterPolicy) {
|
||||
glog.V(4).Infof("adding resources %s", policy.Name)
|
||||
logger := ps.log
|
||||
logger.V(4).Info("adding policy", "name", policy.Name)
|
||||
ps.mu.Lock()
|
||||
defer ps.mu.Unlock()
|
||||
var pmap policyMap
|
||||
|
|
|
@ -3,24 +3,23 @@ package policyviolation
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/go-logr/logr"
|
||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||
"github.com/nirmata/kyverno/pkg/engine/response"
|
||||
)
|
||||
|
||||
//GeneratePVsFromEngineResponse generate Violations from engine responses
|
||||
func GeneratePVsFromEngineResponse(ers []response.EngineResponse) (pvInfos []Info) {
|
||||
func GeneratePVsFromEngineResponse(ers []response.EngineResponse, log logr.Logger) (pvInfos []Info) {
|
||||
for _, er := range ers {
|
||||
// ignore creation of PV for resources that are yet to be assigned a name
|
||||
if er.PolicyResponse.Resource.Name == "" {
|
||||
glog.V(4).Infof("resource %v, has not been assigned a name, not creating a policy violation for it", er.PolicyResponse.Resource)
|
||||
log.V(4).Info("resource does no have a name assigned yet, not creating a policy violation", "resource", er.PolicyResponse.Resource)
|
||||
continue
|
||||
}
|
||||
// skip when response succeed
|
||||
if er.IsSuccesful() {
|
||||
continue
|
||||
}
|
||||
glog.V(4).Infof("Building policy violation for engine response %v", er)
|
||||
// build policy violation info
|
||||
pvInfos = append(pvInfos, buildPVInfo(er))
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
|
||||
"github.com/nirmata/kyverno/pkg/engine/response"
|
||||
"gotest.tools/assert"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
)
|
||||
|
||||
func Test_GeneratePVsFromEngineResponse_PathNotExist(t *testing.T) {
|
||||
|
@ -52,6 +53,6 @@ func Test_GeneratePVsFromEngineResponse_PathNotExist(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
pvInfos := GeneratePVsFromEngineResponse(ers)
|
||||
pvInfos := GeneratePVsFromEngineResponse(ers, log.Log)
|
||||
assert.Assert(t, len(pvInfos) == 1)
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import (
|
|||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/go-logr/logr"
|
||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||
kyvernov1 "github.com/nirmata/kyverno/pkg/client/clientset/versioned/typed/kyverno/v1"
|
||||
kyvernolister "github.com/nirmata/kyverno/pkg/client/listers/kyverno/v1"
|
||||
|
@ -21,11 +21,13 @@ type clusterPV struct {
|
|||
cpvLister kyvernolister.ClusterPolicyViolationLister
|
||||
// policy violation interface
|
||||
kyvernoInterface kyvernov1.KyvernoV1Interface
|
||||
// logger
|
||||
log logr.Logger
|
||||
// update policy stats with violationCount
|
||||
policyStatusListener policystatus.Listener
|
||||
}
|
||||
|
||||
func newClusterPV(dclient *client.Client,
|
||||
func newClusterPV(log logr.Logger, dclient *client.Client,
|
||||
cpvLister kyvernolister.ClusterPolicyViolationLister,
|
||||
kyvernoInterface kyvernov1.KyvernoV1Interface,
|
||||
policyStatus policystatus.Listener,
|
||||
|
@ -34,6 +36,7 @@ func newClusterPV(dclient *client.Client,
|
|||
dclient: dclient,
|
||||
cpvLister: cpvLister,
|
||||
kyvernoInterface: kyvernoInterface,
|
||||
log: log,
|
||||
policyStatusListener: policyStatus,
|
||||
}
|
||||
return &cpv
|
||||
|
@ -56,6 +59,7 @@ func (cpv *clusterPV) create(pv kyverno.PolicyViolationTemplate) error {
|
|||
}
|
||||
|
||||
func (cpv *clusterPV) getExisting(newPv kyverno.ClusterPolicyViolation) (*kyverno.ClusterPolicyViolation, error) {
|
||||
logger := cpv.log.WithValues("namespace", newPv.Namespace, "name", newPv.Name)
|
||||
var err error
|
||||
// use labels
|
||||
policyLabelmap := map[string]string{"policy": newPv.Spec.Policy, "resource": newPv.Spec.ResourceSpec.ToKey()}
|
||||
|
@ -66,7 +70,7 @@ func (cpv *clusterPV) getExisting(newPv kyverno.ClusterPolicyViolation) (*kyvern
|
|||
|
||||
pvs, err := cpv.cpvLister.List(ls)
|
||||
if err != nil {
|
||||
glog.Errorf("unable to list cluster policy violations : %v", err)
|
||||
logger.Error(err, "failed to list cluster policy violations")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -83,7 +87,8 @@ func (cpv *clusterPV) getExisting(newPv kyverno.ClusterPolicyViolation) (*kyvern
|
|||
|
||||
func (cpv *clusterPV) createPV(newPv *kyverno.ClusterPolicyViolation) error {
|
||||
var err error
|
||||
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 := cpv.log.WithValues("policy", newPv.Spec.Policy, "kind", newPv.Spec.ResourceSpec.Kind, "namespace", newPv.Spec.ResourceSpec.Namespace, "name", newPv.Spec.ResourceSpec.Name)
|
||||
logger.V(4).Info("creating new policy violation")
|
||||
obj, err := retryGetResource(cpv.dclient, newPv.Spec.ResourceSpec)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to retry getting resource for policy violation %s/%s: %v", newPv.Name, newPv.Spec.Policy, err)
|
||||
|
@ -95,7 +100,7 @@ func (cpv *clusterPV) createPV(newPv *kyverno.ClusterPolicyViolation) error {
|
|||
// create resource
|
||||
_, err = cpv.kyvernoInterface.ClusterPolicyViolations().Create(newPv)
|
||||
if err != nil {
|
||||
glog.V(4).Infof("failed to create Cluster Policy Violation: %v", err)
|
||||
logger.Error(err, "failed to create cluster policy violation")
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -103,15 +108,16 @@ func (cpv *clusterPV) createPV(newPv *kyverno.ClusterPolicyViolation) error {
|
|||
cpv.policyStatusListener.Send(violationCount{policyName: newPv.Spec.Policy, violatedRules: newPv.Spec.ViolatedRules})
|
||||
}
|
||||
|
||||
glog.Infof("policy violation created for resource %v", newPv.Spec.ResourceSpec)
|
||||
logger.Info("cluster policy violation created")
|
||||
return nil
|
||||
}
|
||||
|
||||
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
|
||||
// check if there is any update
|
||||
if reflect.DeepEqual(newPv.Spec, oldPv.Spec) {
|
||||
glog.V(4).Infof("policy violation spec %v did not change so not updating it", newPv.Spec)
|
||||
logger.V(4).Info("policy violation spec did not change, not upadating the resource")
|
||||
return nil
|
||||
}
|
||||
// set name
|
||||
|
@ -123,7 +129,7 @@ func (cpv *clusterPV) updatePV(newPv, oldPv *kyverno.ClusterPolicyViolation) err
|
|||
if err != nil {
|
||||
return fmt.Errorf("failed to update cluster policy violation: %v", err)
|
||||
}
|
||||
glog.Infof("cluster policy violation updated for resource %v", newPv.Spec.ResourceSpec)
|
||||
logger.Info("cluster policy violation created")
|
||||
|
||||
if newPv.Annotations["fromSync"] != "true" {
|
||||
cpv.policyStatusListener.Send(violationCount{policyName: newPv.Spec.Policy, violatedRules: newPv.Spec.ViolatedRules})
|
||||
|
|
|
@ -5,13 +5,13 @@ import (
|
|||
"time"
|
||||
|
||||
backoff "github.com/cenkalti/backoff"
|
||||
"github.com/golang/glog"
|
||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||
v1 "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||
client "github.com/nirmata/kyverno/pkg/dclient"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
unstructured "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
)
|
||||
|
||||
func createOwnerReference(resource *unstructured.Unstructured) metav1.OwnerReference {
|
||||
|
@ -34,7 +34,7 @@ func retryGetResource(client *client.Client, rspec kyverno.ResourceSpec) (*unstr
|
|||
var err error
|
||||
getResource := func() error {
|
||||
obj, err = client.GetResource(rspec.Kind, rspec.Namespace, rspec.Name)
|
||||
glog.V(4).Infof("retry %v getting %s/%s/%s", i, 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))
|
||||
i++
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/go-logr/logr"
|
||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||
kyvernoclient "github.com/nirmata/kyverno/pkg/client/clientset/versioned"
|
||||
kyvernov1 "github.com/nirmata/kyverno/pkg/client/clientset/versioned/typed/kyverno/v1"
|
||||
|
@ -38,6 +38,7 @@ type Generator struct {
|
|||
// returns true if the cluster policy store has been synced at least once
|
||||
pvSynced cache.InformerSynced
|
||||
// returns true if the namespaced cluster policy store has been synced at at least once
|
||||
log logr.Logger
|
||||
nspvSynced cache.InformerSynced
|
||||
queue workqueue.RateLimitingInterface
|
||||
dataStore *dataStore
|
||||
|
@ -107,7 +108,8 @@ func NewPVGenerator(client *kyvernoclient.Clientset,
|
|||
dclient *dclient.Client,
|
||||
pvInformer kyvernoinformer.ClusterPolicyViolationInformer,
|
||||
nspvInformer kyvernoinformer.PolicyViolationInformer,
|
||||
policyStatus policystatus.Listener) *Generator {
|
||||
policyStatus policystatus.Listener,
|
||||
log logr.Logger) *Generator {
|
||||
gen := Generator{
|
||||
kyvernoInterface: client.KyvernoV1(),
|
||||
dclient: dclient,
|
||||
|
@ -117,6 +119,7 @@ func NewPVGenerator(client *kyvernoclient.Clientset,
|
|||
nspvSynced: nspvInformer.Informer().HasSynced,
|
||||
queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), workQueueName),
|
||||
dataStore: newDataStore(),
|
||||
log: log,
|
||||
policyStatusListener: policyStatus,
|
||||
}
|
||||
return &gen
|
||||
|
@ -135,18 +138,18 @@ func (gen *Generator) enqueue(info Info) {
|
|||
func (gen *Generator) Add(infos ...Info) {
|
||||
for _, info := range infos {
|
||||
gen.enqueue(info)
|
||||
glog.V(3).Infof("Added policy violation: %s", info.toKey())
|
||||
}
|
||||
}
|
||||
|
||||
// Run starts the workers
|
||||
func (gen *Generator) Run(workers int, stopCh <-chan struct{}) {
|
||||
logger := gen.log
|
||||
defer utilruntime.HandleCrash()
|
||||
glog.Info("Start policy violation generator")
|
||||
defer glog.Info("Shutting down policy violation generator")
|
||||
logger.Info("start")
|
||||
defer logger.Info("shutting down")
|
||||
|
||||
if !cache.WaitForCacheSync(stopCh, gen.pvSynced, gen.nspvSynced) {
|
||||
glog.Error("policy violation generator: failed to sync informer cache")
|
||||
logger.Info("failed to sync informer cache")
|
||||
}
|
||||
|
||||
for i := 0; i < workers; i++ {
|
||||
|
@ -161,6 +164,7 @@ func (gen *Generator) runWorker() {
|
|||
}
|
||||
|
||||
func (gen *Generator) handleErr(err error, key interface{}) {
|
||||
logger := gen.log
|
||||
if err == nil {
|
||||
gen.queue.Forget(key)
|
||||
return
|
||||
|
@ -168,23 +172,22 @@ func (gen *Generator) handleErr(err error, key interface{}) {
|
|||
|
||||
// retires requests if there is error
|
||||
if gen.queue.NumRequeues(key) < workQueueRetryLimit {
|
||||
glog.V(4).Infof("Error syncing policy violation %v: %v", key, err)
|
||||
logger.Error(err, "failed to sync policy violation", "key", key)
|
||||
// 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.
|
||||
gen.queue.AddRateLimited(key)
|
||||
return
|
||||
}
|
||||
gen.queue.Forget(key)
|
||||
glog.Error(err)
|
||||
// remove from data store
|
||||
if keyHash, ok := key.(string); ok {
|
||||
gen.dataStore.delete(keyHash)
|
||||
}
|
||||
|
||||
glog.Warningf("Dropping the key out of the queue: %v", err)
|
||||
logger.Error(err, "dropping key out of the queue", "key", key)
|
||||
}
|
||||
|
||||
func (gen *Generator) processNextWorkitem() bool {
|
||||
logger := gen.log
|
||||
obj, shutdown := gen.queue.Get()
|
||||
if shutdown {
|
||||
return false
|
||||
|
@ -196,7 +199,7 @@ func (gen *Generator) processNextWorkitem() bool {
|
|||
var ok bool
|
||||
if keyHash, ok = obj.(string); !ok {
|
||||
gen.queue.Forget(obj)
|
||||
glog.Warningf("Expecting type string but got %v\n", obj)
|
||||
logger.Info("incorrect type; expecting type 'string'", "obj", obj)
|
||||
return nil
|
||||
}
|
||||
// lookup data store
|
||||
|
@ -204,7 +207,7 @@ func (gen *Generator) processNextWorkitem() bool {
|
|||
if reflect.DeepEqual(info, Info{}) {
|
||||
// empty key
|
||||
gen.queue.Forget(obj)
|
||||
glog.Warningf("Got empty key %v\n", obj)
|
||||
logger.Info("empty key")
|
||||
return nil
|
||||
}
|
||||
err := gen.syncHandler(info)
|
||||
|
@ -212,22 +215,22 @@ func (gen *Generator) processNextWorkitem() bool {
|
|||
return nil
|
||||
}(obj)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
logger.Error(err, "failed to process item")
|
||||
return true
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (gen *Generator) syncHandler(info Info) error {
|
||||
glog.V(4).Infof("received info:%v", info)
|
||||
logger := gen.log
|
||||
var handler pvGenerator
|
||||
builder := newPvBuilder()
|
||||
if info.Resource.GetNamespace() == "" {
|
||||
// cluster scope resource generate a clusterpolicy violation
|
||||
handler = newClusterPV(gen.dclient, gen.cpvLister, gen.kyvernoInterface, gen.policyStatusListener)
|
||||
handler = newClusterPV(gen.log.WithName("ClusterPV"), gen.dclient, gen.cpvLister, gen.kyvernoInterface, gen.policyStatusListener)
|
||||
} else {
|
||||
// namespaced resources generated a namespaced policy violation in the namespace of the resource
|
||||
handler = newNamespacedPV(gen.dclient, gen.nspvLister, gen.kyvernoInterface, gen.policyStatusListener)
|
||||
handler = newNamespacedPV(gen.log.WithName("NamespacedPV"), gen.dclient, gen.nspvLister, gen.kyvernoInterface, gen.policyStatusListener)
|
||||
}
|
||||
|
||||
failure := false
|
||||
|
@ -240,12 +243,12 @@ func (gen *Generator) syncHandler(info Info) error {
|
|||
}
|
||||
|
||||
// Create Policy Violations
|
||||
glog.V(3).Infof("Creating policy violation: %s", info.toKey())
|
||||
logger.V(4).Info("creating policy violation", "key", info.toKey())
|
||||
if err := handler.create(pv); err != nil {
|
||||
failure = true
|
||||
glog.V(3).Infof("Failed to create policy violation: %v", err)
|
||||
logger.Error(err, "failed to create policy violation")
|
||||
} else {
|
||||
glog.V(3).Infof("Policy violation created: %s", info.toKey())
|
||||
logger.Info("created policy violation", "key", info.toKey())
|
||||
}
|
||||
|
||||
if failure {
|
||||
|
|
|
@ -4,7 +4,7 @@ import (
|
|||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/go-logr/logr"
|
||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||
kyvernov1 "github.com/nirmata/kyverno/pkg/client/clientset/versioned/typed/kyverno/v1"
|
||||
kyvernolister "github.com/nirmata/kyverno/pkg/client/listers/kyverno/v1"
|
||||
|
@ -21,11 +21,13 @@ type namespacedPV struct {
|
|||
nspvLister kyvernolister.PolicyViolationLister
|
||||
// policy violation interface
|
||||
kyvernoInterface kyvernov1.KyvernoV1Interface
|
||||
// logger
|
||||
log logr.Logger
|
||||
// update policy status with violationCount
|
||||
policyStatusListener policystatus.Listener
|
||||
}
|
||||
|
||||
func newNamespacedPV(dclient *client.Client,
|
||||
func newNamespacedPV(log logr.Logger, dclient *client.Client,
|
||||
nspvLister kyvernolister.PolicyViolationLister,
|
||||
kyvernoInterface kyvernov1.KyvernoV1Interface,
|
||||
policyStatus policystatus.Listener,
|
||||
|
@ -34,6 +36,7 @@ func newNamespacedPV(dclient *client.Client,
|
|||
dclient: dclient,
|
||||
nspvLister: nspvLister,
|
||||
kyvernoInterface: kyvernoInterface,
|
||||
log: log,
|
||||
policyStatusListener: policyStatus,
|
||||
}
|
||||
return &nspv
|
||||
|
@ -56,6 +59,7 @@ func (nspv *namespacedPV) create(pv kyverno.PolicyViolationTemplate) error {
|
|||
}
|
||||
|
||||
func (nspv *namespacedPV) getExisting(newPv kyverno.PolicyViolation) (*kyverno.PolicyViolation, error) {
|
||||
logger := nspv.log.WithValues("namespace", newPv.Namespace, "name", newPv.Name)
|
||||
var err error
|
||||
// use labels
|
||||
policyLabelmap := map[string]string{"policy": newPv.Spec.Policy, "resource": newPv.Spec.ResourceSpec.ToKey()}
|
||||
|
@ -65,7 +69,7 @@ func (nspv *namespacedPV) getExisting(newPv kyverno.PolicyViolation) (*kyverno.P
|
|||
}
|
||||
pvs, err := nspv.nspvLister.PolicyViolations(newPv.GetNamespace()).List(ls)
|
||||
if err != nil {
|
||||
glog.Errorf("unable to list namespaced policy violations : %v", err)
|
||||
logger.Error(err, "failed to list namespaced policy violations")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -82,7 +86,8 @@ func (nspv *namespacedPV) getExisting(newPv kyverno.PolicyViolation) (*kyverno.P
|
|||
|
||||
func (nspv *namespacedPV) createPV(newPv *kyverno.PolicyViolation) error {
|
||||
var err error
|
||||
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 := nspv.log.WithValues("policy", newPv.Spec.Policy, "kind", newPv.Spec.ResourceSpec.Kind, "namespace", newPv.Spec.ResourceSpec.Namespace, "name", newPv.Spec.ResourceSpec.Name)
|
||||
logger.V(4).Info("creating new policy violation")
|
||||
obj, err := retryGetResource(nspv.dclient, newPv.Spec.ResourceSpec)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to retry getting resource for policy violation %s/%s: %v", newPv.Name, newPv.Spec.Policy, err)
|
||||
|
@ -94,22 +99,23 @@ func (nspv *namespacedPV) createPV(newPv *kyverno.PolicyViolation) error {
|
|||
// create resource
|
||||
_, err = nspv.kyvernoInterface.PolicyViolations(newPv.GetNamespace()).Create(newPv)
|
||||
if err != nil {
|
||||
glog.V(4).Infof("failed to create Cluster Policy Violation: %v", err)
|
||||
logger.Error(err, "failed to create namespaced policy violation")
|
||||
return err
|
||||
}
|
||||
|
||||
if newPv.Annotations["fromSync"] != "true" {
|
||||
nspv.policyStatusListener.Send(violationCount{policyName: newPv.Spec.Policy, violatedRules: newPv.Spec.ViolatedRules})
|
||||
}
|
||||
glog.Infof("policy violation created for resource %v", newPv.Spec.ResourceSpec)
|
||||
logger.Info("namespaced policy violation created")
|
||||
return nil
|
||||
}
|
||||
|
||||
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
|
||||
// check if there is any update
|
||||
if reflect.DeepEqual(newPv.Spec, oldPv.Spec) {
|
||||
glog.V(4).Infof("policy violation spec %v did not change so not updating it", newPv.Spec)
|
||||
logger.V(4).Info("policy violation spec did not change, not upadating the resource")
|
||||
return nil
|
||||
}
|
||||
// set name
|
||||
|
@ -124,6 +130,6 @@ func (nspv *namespacedPV) updatePV(newPv, oldPv *kyverno.PolicyViolation) error
|
|||
if newPv.Annotations["fromSync"] != "true" {
|
||||
nspv.policyStatusListener.Send(violationCount{policyName: newPv.Spec.Policy, violatedRules: newPv.Spec.ViolatedRules})
|
||||
}
|
||||
glog.Infof("namespaced policy violation updated for resource %v", newPv.Spec.ResourceSpec)
|
||||
logger.Info("namespaced policy violation created")
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ package testrunner
|
|||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
ospath "path"
|
||||
|
@ -19,7 +18,6 @@ import (
|
|||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"gopkg.in/yaml.v2"
|
||||
apiyaml "k8s.io/apimachinery/pkg/util/yaml"
|
||||
)
|
||||
|
@ -308,7 +306,7 @@ func loadPolicyResource(t *testing.T, file string) *unstructured.Unstructured {
|
|||
func getClient(t *testing.T, files []string) *client.Client {
|
||||
var objects []runtime.Object
|
||||
if files != nil {
|
||||
glog.V(4).Infof("loading resources: %v", files)
|
||||
|
||||
for _, file := range files {
|
||||
objects = loadObjects(t, file)
|
||||
}
|
||||
|
@ -404,7 +402,7 @@ func loadPolicy(t *testing.T, path string) *kyverno.ClusterPolicy {
|
|||
policy := kyverno.ClusterPolicy{}
|
||||
pBytes, err := apiyaml.ToJSON(p)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -427,7 +425,8 @@ func loadPolicy(t *testing.T, path string) *kyverno.ClusterPolicy {
|
|||
}
|
||||
|
||||
func testScenario(t *testing.T, path string) {
|
||||
flag.Set("logtostderr", "true")
|
||||
|
||||
// flag.Set("logtostderr", "true")
|
||||
// flag.Set("v", "8")
|
||||
|
||||
scenario, err := loadScenario(t, path)
|
||||
|
|
|
@ -4,8 +4,8 @@ import (
|
|||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -42,7 +42,7 @@ func ConvertToUnstructured(data []byte) (*unstructured.Unstructured, error) {
|
|||
resource := &unstructured.Unstructured{}
|
||||
err := resource.UnmarshalJSON(data)
|
||||
if err != nil {
|
||||
glog.V(4).Infof("failed to unmarshall resource: %v", err)
|
||||
log.Log.Error(err, "failed to unmarshal resource")
|
||||
return nil, err
|
||||
}
|
||||
return resource, nil
|
||||
|
|
|
@ -142,5 +142,6 @@ func IsTLSPairShouldBeUpdated(tlsPair *TlsPemPair) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
// TODO : should use time.Until instead of t.Sub(time.Now()) (gosimple)
|
||||
return expirationDate.Sub(time.Now()) < timeReserveBeforeCertificateExpiration
|
||||
}
|
||||
|
|
|
@ -4,12 +4,12 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
v1beta1 "k8s.io/api/admission/v1beta1"
|
||||
authenticationv1 "k8s.io/api/authentication/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
labels "k8s.io/apimachinery/pkg/labels"
|
||||
rbaclister "k8s.io/client-go/listers/rbac/v1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -101,7 +101,7 @@ func matchSubjectsMap(subject rbacv1.Subject, userInfo authenticationv1.UserInfo
|
|||
func matchServiceAccount(subject rbacv1.Subject, userInfo authenticationv1.UserInfo) bool {
|
||||
subjectServiceAccount := subject.Namespace + ":" + subject.Name
|
||||
if userInfo.Username[len(SaPrefix):] != subjectServiceAccount {
|
||||
glog.V(3).Infof("service account not match, expect %s, got %s", subjectServiceAccount, userInfo.Username[len(SaPrefix):])
|
||||
log.Log.V(3).Info(fmt.Sprintf("service account not match, expect %s, got %s", subjectServiceAccount, userInfo.Username[len(SaPrefix):]))
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -117,6 +117,6 @@ func matchUserOrGroup(subject rbacv1.Subject, userInfo authenticationv1.UserInfo
|
|||
}
|
||||
}
|
||||
|
||||
glog.V(3).Infof("user/group '%v' info not found in request userInfo: %v", subject.Name, keys)
|
||||
log.Log.V(3).Info(fmt.Sprintf("user/group '%v' info not found in request userInfo: %v", subject.Name, keys))
|
||||
return false
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue