1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-31 03:45:17 +00:00

Revert "754 merge conflicts"

This reverts commit 39f75db435.
This commit is contained in:
shravan 2020-03-28 16:36:19 +05:30
parent 39f75db435
commit b5af456f64
126 changed files with 2111 additions and 3203 deletions

View file

@ -1,18 +0,0 @@
engines:
govet:
enabled: true
golint:
enabled: false
gofmt:
enabled: true
ratings:
paths:
- "**.go"
exclude_paths:
- documentation/
- definitions
- gh-pages
- samples
- scripts

View file

@ -1,17 +0,0 @@
linters:
enable:
- gosec
- errcheck
- gosimple
- bodyclose
- staticcheck
disable:
- ineffassign
- deadcode
- unused
- structcheck
run:
skip-files:
- ".+_test.go"
- ".+_test_.+.go"

View file

@ -2,11 +2,6 @@ language: go
go: go:
- "1.13" - "1.13"
cache:
directories:
- $HOME/.cache/go-build
- $GOPATH/pkg/mod
# safelist # safelist
branches: branches:
only: only:

View file

@ -1,7 +1 @@
# Contributing to Kyverno See: https://github.com/nirmata/kyverno#contributing
## Code Style
We follow the community provided standard [code structure](https://github.com/golang-standards/project-layout).
See : https://github.com/nirmata/kyverno#contributing

View file

@ -171,6 +171,5 @@ See [Milestones](https://github.com/nirmata/kyverno/milestones) and [Issues](htt
Thanks for your interest in contributing! Thanks for your interest in contributing!
* Please review and agree to abide with the [Code of Conduct](/CODE_OF_CONDUCT.md) before contributing. * Please review and agree to abide with the [Code of Conduct](/CODE_OF_CONDUCT.md) before contributing.
* We encourage all contributions and encourage you to read our [contribution guidelines](./CONTRIBUTING.md).
* See the [Wiki](https://github.com/nirmata/kyverno/wiki) for developer documentation. * See the [Wiki](https://github.com/nirmata/kyverno/wiki) for developer documentation.
* Browse through the [open issues](https://github.com/nirmata/kyverno/issues) * Browse through the [open issues](https://github.com/nirmata/kyverno/issues)

View file

@ -5,27 +5,23 @@ package main
import ( import (
"flag" "flag"
"fmt"
"os" "os"
"regexp" "regexp"
"strconv" "strconv"
"sync" "sync"
"time" "time"
"github.com/golang/glog"
"github.com/nirmata/kyverno/pkg/config" "github.com/nirmata/kyverno/pkg/config"
client "github.com/nirmata/kyverno/pkg/dclient" client "github.com/nirmata/kyverno/pkg/dclient"
"github.com/nirmata/kyverno/pkg/signal" "github.com/nirmata/kyverno/pkg/signal"
"k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/errors"
rest "k8s.io/client-go/rest" rest "k8s.io/client-go/rest"
clientcmd "k8s.io/client-go/tools/clientcmd" clientcmd "k8s.io/client-go/tools/clientcmd"
"k8s.io/klog"
"k8s.io/klog/klogr"
"sigs.k8s.io/controller-runtime/pkg/log"
) )
var ( var (
kubeconfig string kubeconfig string
setupLog = log.Log.WithName("setup")
) )
const ( const (
@ -34,30 +30,20 @@ const (
) )
func main() { func main() {
klog.InitFlags(nil) defer glog.Flush()
log.SetLogger(klogr.New())
// arguments
flag.StringVar(&kubeconfig, "kubeconfig", "", "Path to a kubeconfig. Only required if out-of-cluster.")
if err := flag.Set("v", "2"); err != nil {
klog.Fatalf("failed to set log level: %v", err)
}
flag.Parse()
// os signal handler // os signal handler
stopCh := signal.SetupSignalHandler() stopCh := signal.SetupSignalHandler()
// create client config // create client config
clientConfig, err := createClientConfig(kubeconfig) clientConfig, err := createClientConfig(kubeconfig)
if err != nil { if err != nil {
setupLog.Error(err, "Failed to build kubeconfig") glog.Fatalf("Error building kubeconfig: %v\n", err)
os.Exit(1)
} }
// DYNAMIC CLIENT // DYNAMIC CLIENT
// - client for all registered resources // - client for all registered resources
client, err := client.NewClient(clientConfig, 10*time.Second, stopCh, log.Log) client, err := client.NewClient(clientConfig, 10*time.Second, stopCh)
if err != nil { if err != nil {
setupLog.Error(err, "Failed to create client") glog.Fatalf("Error creating client: %v\n", err)
os.Exit(1)
} }
// Exit for unsupported version of kubernetes cluster // Exit for unsupported version of kubernetes cluster
@ -92,46 +78,53 @@ func main() {
for err := range merge(done, stopCh, p1, p2) { for err := range merge(done, stopCh, p1, p2) {
if err != nil { if err != nil {
failure = true failure = true
log.Log.Error(err, "failed to cleanup resource") glog.Errorf("failed to cleanup: %v", err)
} }
} }
// if there is any failure then we fail process // if there is any failure then we fail process
if failure { if failure {
log.Log.Info("failed to cleanup webhook configurations") glog.Errorf("failed to cleanup webhook configurations")
os.Exit(1) os.Exit(1)
} }
} }
func init() {
// arguments
flag.StringVar(&kubeconfig, "kubeconfig", "", "Path to a kubeconfig. Only required if out-of-cluster.")
flag.Set("logtostderr", "true")
flag.Set("stderrthreshold", "WARNING")
flag.Set("v", "2")
flag.Parse()
}
func removeWebhookIfExists(client *client.Client, kind string, name string) error { func removeWebhookIfExists(client *client.Client, kind string, name string) error {
logger := log.Log.WithName("removeExistingWebhook").WithValues("kind", kind, "name", name)
var err error var err error
// Get resource // Get resource
_, err = client.GetResource(kind, "", name) _, err = client.GetResource(kind, "", name)
if errors.IsNotFound(err) { if errors.IsNotFound(err) {
logger.V(4).Info("resource not found") glog.V(4).Infof("%s(%s) not found", name, kind)
return nil return nil
} }
if err != nil { if err != nil {
logger.Error(err, "failed to get resource") glog.Errorf("failed to get resource %s(%s)", name, kind)
return err return err
} }
// Delete resource // Delete resource
err = client.DeleteResource(kind, "", name, false) err = client.DeleteResource(kind, "", name, false)
if err != nil { if err != nil {
logger.Error(err, "failed to delete resource") glog.Errorf("failed to delete resource %s(%s)", name, kind)
return err return err
} }
logger.Info("removed the resource") glog.Infof("cleaned up resource %s(%s)", name, kind)
return nil return nil
} }
func createClientConfig(kubeconfig string) (*rest.Config, error) { func createClientConfig(kubeconfig string) (*rest.Config, error) {
logger := log.Log
if kubeconfig == "" { if kubeconfig == "" {
logger.Info("Using in-cluster configuration") glog.Info("Using in-cluster configuration")
return rest.InClusterConfig() return rest.InClusterConfig()
} }
logger.Info(fmt.Sprintf("Using configuration from '%s'", kubeconfig)) glog.Infof("Using configuration from '%s'", kubeconfig)
return clientcmd.BuildConfigFromFlags("", kubeconfig) return clientcmd.BuildConfigFromFlags("", kubeconfig)
} }
@ -170,7 +163,6 @@ func gen(done <-chan struct{}, stopCh <-chan struct{}, requests ...request) <-ch
// processes the requests // processes the requests
func process(client *client.Client, done <-chan struct{}, stopCh <-chan struct{}, requests <-chan request) <-chan error { func process(client *client.Client, done <-chan struct{}, stopCh <-chan struct{}, requests <-chan request) <-chan error {
logger := log.Log.WithName("process")
out := make(chan error) out := make(chan error)
go func() { go func() {
defer close(out) defer close(out)
@ -178,10 +170,10 @@ func process(client *client.Client, done <-chan struct{}, stopCh <-chan struct{}
select { select {
case out <- removeWebhookIfExists(client, req.kind, req.name): case out <- removeWebhookIfExists(client, req.kind, req.name):
case <-done: case <-done:
logger.Info("done") println("done process")
return return
case <-stopCh: case <-stopCh:
logger.Info("shutting down") println("shutting down process")
return return
} }
} }
@ -191,7 +183,6 @@ func process(client *client.Client, done <-chan struct{}, stopCh <-chan struct{}
// waits for all processes to be complete and merges result // waits for all processes to be complete and merges result
func merge(done <-chan struct{}, stopCh <-chan struct{}, processes ...<-chan error) <-chan error { func merge(done <-chan struct{}, stopCh <-chan struct{}, processes ...<-chan error) <-chan error {
logger := log.Log.WithName("merge")
var wg sync.WaitGroup var wg sync.WaitGroup
out := make(chan error) out := make(chan error)
// gets the output from each process // gets the output from each process
@ -201,10 +192,10 @@ func merge(done <-chan struct{}, stopCh <-chan struct{}, processes ...<-chan err
select { select {
case out <- err: case out <- err:
case <-done: case <-done:
logger.Info("done") println("done merge")
return return
case <-stopCh: case <-stopCh:
logger.Info("shutting down") println("shutting down merge")
return return
} }
} }
@ -224,37 +215,30 @@ func merge(done <-chan struct{}, stopCh <-chan struct{}, processes ...<-chan err
} }
func isVersionSupported(client *client.Client) { func isVersionSupported(client *client.Client) {
logger := log.Log
serverVersion, err := client.DiscoveryClient.GetServerVersion() serverVersion, err := client.DiscoveryClient.GetServerVersion()
if err != nil { if err != nil {
logger.Error(err, "Failed to get kubernetes server version") glog.Fatalf("Failed to get kubernetes server version: %v\n", err)
os.Exit(1)
} }
exp := regexp.MustCompile(`v(\d*).(\d*).(\d*)`) exp := regexp.MustCompile(`v(\d*).(\d*).(\d*)`)
groups := exp.FindAllStringSubmatch(serverVersion.String(), -1) groups := exp.FindAllStringSubmatch(serverVersion.String(), -1)
if len(groups) != 1 || len(groups[0]) != 4 { if len(groups) != 1 || len(groups[0]) != 4 {
logger.Error(err, "Failed to extract kubernetes server version", "serverVersion", serverVersion) glog.Fatalf("Failed to extract kubernetes server version: %v.err %v\n", serverVersion, err)
os.Exit(1)
} }
// convert string to int // convert string to int
// assuming the version are always intergers // assuming the version are always intergers
major, err := strconv.Atoi(groups[0][1]) major, err := strconv.Atoi(groups[0][1])
if err != nil { if err != nil {
logger.Error(err, "Failed to extract kubernetes major server version", "serverVersion", serverVersion) glog.Fatalf("Failed to extract kubernetes major server version: %v.err %v\n", serverVersion, err)
os.Exit(1)
} }
minor, err := strconv.Atoi(groups[0][2]) minor, err := strconv.Atoi(groups[0][2])
if err != nil { if err != nil {
logger.Error(err, "Failed to extract kubernetes minor server version", "serverVersion", serverVersion) glog.Fatalf("Failed to extract kubernetes minor server version: %v.err %v\n", serverVersion, err)
os.Exit(1)
} }
sub, err := strconv.Atoi(groups[0][3]) sub, err := strconv.Atoi(groups[0][3])
if err != nil { if err != nil {
logger.Error(err, "Failed to extract kubernetes sub minor server version", "serverVersion", serverVersion) glog.Fatalf("Failed to extract kubernetes sub minor server version:%v. err %v\n", serverVersion, err)
os.Exit(1)
} }
if major <= 1 && minor <= 12 && sub < 7 { if major <= 1 && minor <= 12 && sub < 7 {
logger.Info("Unsupported kubernetes server version %s. Kyverno is supported from version v1.12.7+", "serverVersion", serverVersion) glog.Fatalf("Unsupported kubernetes server version %s. Kyverno is supported from version v1.12.7+", serverVersion)
os.Exit(1)
} }
} }

View file

@ -3,12 +3,11 @@ package main
import ( import (
"context" "context"
"flag" "flag"
"fmt"
"os"
"time" "time"
"github.com/nirmata/kyverno/pkg/openapi" "github.com/nirmata/kyverno/pkg/openapi"
"github.com/golang/glog"
"github.com/nirmata/kyverno/pkg/checker" "github.com/nirmata/kyverno/pkg/checker"
kyvernoclient "github.com/nirmata/kyverno/pkg/client/clientset/versioned" kyvernoclient "github.com/nirmata/kyverno/pkg/client/clientset/versioned"
kyvernoinformer "github.com/nirmata/kyverno/pkg/client/informers/externalversions" kyvernoinformer "github.com/nirmata/kyverno/pkg/client/informers/externalversions"
@ -28,9 +27,6 @@ import (
"github.com/nirmata/kyverno/pkg/webhooks" "github.com/nirmata/kyverno/pkg/webhooks"
webhookgenerate "github.com/nirmata/kyverno/pkg/webhooks/generate" webhookgenerate "github.com/nirmata/kyverno/pkg/webhooks/generate"
kubeinformers "k8s.io/client-go/informers" kubeinformers "k8s.io/client-go/informers"
"k8s.io/klog"
"k8s.io/klog/klogr"
log "sigs.k8s.io/controller-runtime/pkg/log"
) )
var ( var (
@ -42,38 +38,20 @@ var (
// will be removed in future and the configuration will be set only via configmaps // will be removed in future and the configuration will be set only via configmaps
filterK8Resources string filterK8Resources string
// User FQDN as CSR CN // User FQDN as CSR CN
fqdncn bool fqdncn bool
setupLog = log.Log.WithName("setup")
) )
func main() { func main() {
klog.InitFlags(nil) defer glog.Flush()
log.SetLogger(klogr.New()) version.PrintVersionInfo()
flag.StringVar(&filterK8Resources, "filterK8Resources", "", "k8 resource in format [kind,namespace,name] where policy is not evaluated by the admission webhook. example --filterKind \"[Deployment, kyverno, kyverno]\" --filterKind \"[Deployment, kyverno, kyverno],[Events, *, *]\"")
flag.IntVar(&webhookTimeout, "webhooktimeout", 3, "timeout for webhook configurations")
flag.StringVar(&kubeconfig, "kubeconfig", "", "Path to a kubeconfig. Only required if out-of-cluster.")
flag.StringVar(&serverIP, "serverIP", "", "IP address where Kyverno controller runs. Only required if out-of-cluster.")
flag.StringVar(&runValidationInMutatingWebhook, "runValidationInMutatingWebhook", "", "Validation will also be done using the mutation webhook, set to 'true' to enable. Older kubernetes versions do not work properly when a validation webhook is registered.")
if err := flag.Set("v", "2"); err != nil {
setupLog.Error(err, "failed to set log level")
os.Exit(1)
}
// Generate CSR with CN as FQDN due to https://github.com/nirmata/kyverno/issues/542
flag.BoolVar(&fqdncn, "fqdn-as-cn", false, "use FQDN as Common Name in CSR")
flag.Parse()
version.PrintVersionInfo(log.Log)
// cleanUp Channel // cleanUp Channel
cleanUp := make(chan struct{}) cleanUp := make(chan struct{})
// handle os signals // handle os signals
stopCh := signal.SetupSignalHandler() stopCh := signal.SetupSignalHandler()
// CLIENT CONFIG // CLIENT CONFIG
clientConfig, err := config.CreateClientConfig(kubeconfig, log.Log) clientConfig, err := config.CreateClientConfig(kubeconfig)
if err != nil { if err != nil {
setupLog.Error(err, "Failed to build kubeconfig") glog.Fatalf("Error building kubeconfig: %v\n", err)
os.Exit(1)
} }
// KYVENO CRD CLIENT // KYVENO CRD CLIENT
@ -82,33 +60,29 @@ func main() {
// - PolicyViolation // - PolicyViolation
pclient, err := kyvernoclient.NewForConfig(clientConfig) pclient, err := kyvernoclient.NewForConfig(clientConfig)
if err != nil { if err != nil {
setupLog.Error(err, "Failed to create client") glog.Fatalf("Error creating client: %v\n", err)
os.Exit(1)
} }
// DYNAMIC CLIENT // DYNAMIC CLIENT
// - client for all registered resources // - client for all registered resources
// - invalidate local cache of registered resource every 10 seconds // - invalidate local cache of registered resource every 10 seconds
client, err := dclient.NewClient(clientConfig, 10*time.Second, stopCh, log.Log) client, err := dclient.NewClient(clientConfig, 10*time.Second, stopCh)
if err != nil { if err != nil {
setupLog.Error(err, "Failed to create client") glog.Fatalf("Error creating client: %v\n", err)
os.Exit(1)
} }
// CRD CHECK // CRD CHECK
// - verify if the CRD for Policy & PolicyViolation are available // - verify if the CRD for Policy & PolicyViolation are available
if !utils.CRDInstalled(client.DiscoveryClient, log.Log) { if !utils.CRDInstalled(client.DiscoveryClient) {
setupLog.Error(fmt.Errorf("pre-requisite CRDs not installed"), "Failed to create watch on kyverno CRDs") glog.Fatalf("Required CRDs unavailable")
os.Exit(1)
} }
// KUBERNETES CLIENT // KUBERNETES CLIENT
kubeClient, err := utils.NewKubeClient(clientConfig) kubeClient, err := utils.NewKubeClient(clientConfig)
if err != nil { if err != nil {
setupLog.Error(err, "Failed to create kubernetes client") glog.Fatalf("Error creating kubernetes client: %v\n", err)
os.Exit(1)
} }
// TODO(shuting): To be removed for v1.2.0 // TODO(shuting): To be removed for v1.2.0
utils.CleanupOldCrd(client, log.Log) utils.CleanupOldCrd(client)
// KUBERNETES RESOURCES INFORMER // KUBERNETES RESOURCES INFORMER
// watches namespace resource // watches namespace resource
@ -125,18 +99,16 @@ func main() {
clientConfig, clientConfig,
client, client,
serverIP, serverIP,
int32(webhookTimeout), int32(webhookTimeout))
log.Log)
// Resource Mutating Webhook Watcher // Resource Mutating Webhook Watcher
lastReqTime := checker.NewLastReqTime(log.Log.WithName("LastReqTime")) lastReqTime := checker.NewLastReqTime()
rWebhookWatcher := webhookconfig.NewResourceWebhookRegister( rWebhookWatcher := webhookconfig.NewResourceWebhookRegister(
lastReqTime, lastReqTime,
kubeInformer.Admissionregistration().V1beta1().MutatingWebhookConfigurations(), kubeInformer.Admissionregistration().V1beta1().MutatingWebhookConfigurations(),
kubeInformer.Admissionregistration().V1beta1().ValidatingWebhookConfigurations(), kubeInformer.Admissionregistration().V1beta1().ValidatingWebhookConfigurations(),
webhookRegistrationClient, webhookRegistrationClient,
runValidationInMutatingWebhook, runValidationInMutatingWebhook,
log.Log.WithName("ResourceWebhookRegister"),
) )
// KYVERNO CRD INFORMER // KYVERNO CRD INFORMER
@ -155,19 +127,16 @@ func main() {
configData := config.NewConfigData( configData := config.NewConfigData(
kubeClient, kubeClient,
kubeInformer.Core().V1().ConfigMaps(), kubeInformer.Core().V1().ConfigMaps(),
filterK8Resources, filterK8Resources)
log.Log.WithName("ConfigData"),
)
// Policy meta-data store // Policy meta-data store
policyMetaStore := policystore.NewPolicyStore(pInformer.Kyverno().V1().ClusterPolicies(), log.Log.WithName("PolicyStore")) policyMetaStore := policystore.NewPolicyStore(pInformer.Kyverno().V1().ClusterPolicies())
// EVENT GENERATOR // EVENT GENERATOR
// - generate event with retry mechanism // - generate event with retry mechanism
egen := event.NewEventGenerator( egen := event.NewEventGenerator(
client, client,
pInformer.Kyverno().V1().ClusterPolicies(), pInformer.Kyverno().V1().ClusterPolicies())
log.Log.WithName("EventGenerator"))
// Policy Status Handler - deals with all logic related to policy status // Policy Status Handler - deals with all logic related to policy status
statusSync := policystatus.NewSync( statusSync := policystatus.NewSync(
@ -180,9 +149,7 @@ func main() {
client, client,
pInformer.Kyverno().V1().ClusterPolicyViolations(), pInformer.Kyverno().V1().ClusterPolicyViolations(),
pInformer.Kyverno().V1().PolicyViolations(), pInformer.Kyverno().V1().PolicyViolations(),
statusSync.Listener, statusSync.Listener)
log.Log.WithName("PolicyViolationGenerator"),
)
// POLICY CONTROLLER // POLICY CONTROLLER
// - reconciliation policy and policy violation // - reconciliation policy and policy violation
@ -198,16 +165,13 @@ func main() {
egen, egen,
pvgen, pvgen,
policyMetaStore, policyMetaStore,
rWebhookWatcher, rWebhookWatcher)
log.Log.WithName("PolicyController"),
)
if err != nil { if err != nil {
setupLog.Error(err, "Failed to create policy controller") glog.Fatalf("error creating policy controller: %v\n", err)
os.Exit(1)
} }
// GENERATE REQUEST GENERATOR // GENERATE REQUEST GENERATOR
grgen := webhookgenerate.NewGenerator(pclient, stopCh, log.Log.WithName("GenerateRequestGenerator")) grgen := webhookgenerate.NewGenerator(pclient, stopCh)
// GENERATE CONTROLLER // GENERATE CONTROLLER
// - applies generate rules on resources based on generate requests created by webhook // - applies generate rules on resources based on generate requests created by webhook
@ -220,7 +184,6 @@ func main() {
pvgen, pvgen,
kubedynamicInformer, kubedynamicInformer,
statusSync.Listener, statusSync.Listener,
log.Log.WithName("GenerateController"),
) )
// GENERATE REQUEST CLEANUP // GENERATE REQUEST CLEANUP
// -- cleans up the generate requests that have not been processed(i.e. state = [Pending, Failed]) for more than defined timeout // -- cleans up the generate requests that have not been processed(i.e. state = [Pending, Failed]) for more than defined timeout
@ -230,14 +193,12 @@ func main() {
pInformer.Kyverno().V1().ClusterPolicies(), pInformer.Kyverno().V1().ClusterPolicies(),
pInformer.Kyverno().V1().GenerateRequests(), pInformer.Kyverno().V1().GenerateRequests(),
kubedynamicInformer, kubedynamicInformer,
log.Log.WithName("GenerateCleanUpController"),
) )
// CONFIGURE CERTIFICATES // CONFIGURE CERTIFICATES
tlsPair, err := client.InitTLSPemPair(clientConfig, fqdncn) tlsPair, err := client.InitTLSPemPair(clientConfig, fqdncn)
if err != nil { if err != nil {
setupLog.Error(err, "Failed to initialize TLS key/certificate pair") glog.Fatalf("Failed to initialize TLS key/certificate pair: %v\n", err)
os.Exit(1)
} }
// WEBHOOK REGISTRATION // WEBHOOK REGISTRATION
@ -246,8 +207,7 @@ func main() {
// resource webhook confgiuration is generated dynamically in the webhook server and policy controller // resource webhook confgiuration is generated dynamically in the webhook server and policy controller
// based on the policy resources created // based on the policy resources created
if err = webhookRegistrationClient.Register(); err != nil { if err = webhookRegistrationClient.Register(); err != nil {
setupLog.Error(err, "Failed to register Admission webhooks") glog.Fatalf("Failed registering Admission Webhooks: %v\n", err)
os.Exit(1)
} }
// Sync openAPI definitions of resources // Sync openAPI definitions of resources
@ -274,12 +234,9 @@ func main() {
pvgen, pvgen,
grgen, grgen,
rWebhookWatcher, rWebhookWatcher,
cleanUp, cleanUp)
log.Log.WithName("WebhookServer"),
)
if err != nil { if err != nil {
setupLog.Error(err, "Failed to create webhook server") glog.Fatalf("Unable to create webhook server: %v\n", err)
os.Exit(1)
} }
// Start the components // Start the components
pInformer.Start(stopCh) pInformer.Start(stopCh)
@ -317,5 +274,18 @@ func main() {
// resource cleanup // resource cleanup
// remove webhook configurations // remove webhook configurations
<-cleanUp <-cleanUp
setupLog.Info("Kyverno shutdown successful") glog.Info("successful shutdown of kyverno controller")
}
func init() {
flag.StringVar(&filterK8Resources, "filterK8Resources", "", "k8 resource in format [kind,namespace,name] where policy is not evaluated by the admission webhook. example --filterKind \"[Deployment, kyverno, kyverno]\" --filterKind \"[Deployment, kyverno, kyverno],[Events, *, *]\"")
flag.IntVar(&webhookTimeout, "webhooktimeout", 3, "timeout for webhook configurations")
flag.StringVar(&kubeconfig, "kubeconfig", "", "Path to a kubeconfig. Only required if out-of-cluster.")
flag.StringVar(&serverIP, "serverIP", "", "IP address where Kyverno controller runs. Only required if out-of-cluster.")
flag.StringVar(&runValidationInMutatingWebhook, "runValidationInMutatingWebhook", "", "Validation will also be done using the mutation webhook, set to 'true' to enable. Older kubernetes versions do not work properly when a validation webhook is registered.")
// Generate CSR with CN as FQDN due to https://github.com/nirmata/kyverno/issues/542
flag.BoolVar(&fqdncn, "fqdn-as-cn", false, "use FQDN as Common Name in CSR")
config.LogDefaultFlags()
flag.Parse()
} }

View file

@ -109,6 +109,8 @@ spec:
type: string type: string
exclude: exclude:
type: object type: object
required:
- resources
properties: properties:
roles: roles:
type: array type: array

View file

@ -109,6 +109,8 @@ spec:
type: string type: string
exclude: exclude:
type: object type: object
required:
- resources
properties: properties:
roles: roles:
type: array type: array

32
go.mod
View file

@ -5,37 +5,39 @@ go 1.13
require ( require (
github.com/cenkalti/backoff v2.2.1+incompatible github.com/cenkalti/backoff v2.2.1+incompatible
github.com/evanphx/json-patch v4.5.0+incompatible github.com/evanphx/json-patch v4.5.0+incompatible
github.com/go-logr/logr v0.1.0 github.com/gogo/protobuf v1.3.1 // indirect
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7 // indirect github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7 // indirect
github.com/googleapis/gnostic v0.3.1 github.com/googleapis/gnostic v0.3.1
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
github.com/hashicorp/golang-lru v0.5.3 // indirect github.com/hashicorp/golang-lru v0.5.3 // indirect
github.com/imdario/mergo v0.3.8 // indirect github.com/imdario/mergo v0.3.8 // indirect
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af
github.com/json-iterator/go v1.1.9 // indirect github.com/json-iterator/go v1.1.9 // indirect
github.com/minio/minio v0.0.0-20200114012931-30922148fbb5 github.com/minio/minio v0.0.0-20200114012931-30922148fbb5
github.com/ory/go-acc v0.1.0 // indirect
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
github.com/spf13/cobra v0.0.5 github.com/spf13/cobra v0.0.5
github.com/spf13/pflag v1.0.5 // indirect
github.com/tevino/abool v0.0.0-20170917061928-9b9efcf221b5 github.com/tevino/abool v0.0.0-20170917061928-9b9efcf221b5
golang.org/x/crypto v0.0.0-20200109152110-61a87790db17 // indirect
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 // indirect golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 // indirect
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1 // indirect golang.org/x/sys v0.0.0-20200113162924-86b910548bc1 // indirect
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect
google.golang.org/appengine v1.6.5 // indirect google.golang.org/appengine v1.6.5 // indirect
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.2.8 gopkg.in/yaml.v2 v2.2.7
gotest.tools v2.2.0+incompatible gotest.tools v2.2.0+incompatible
k8s.io/api v0.17.4 k8s.io/api v0.0.0-20190409021203-6e4e0e4f393b
k8s.io/apimachinery v0.17.4 k8s.io/apimachinery v0.0.0-20190404173353-6a84e37a896d
k8s.io/cli-runtime v0.17.4 k8s.io/cli-runtime v0.0.0-20191004110135-b9eb767d2e1a
k8s.io/client-go v0.17.4 k8s.io/client-go v11.0.1-0.20190516230509-ae8359b20417+incompatible
k8s.io/klog v1.0.0 k8s.io/klog v1.0.0 // indirect
k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a
k8s.io/utils v0.0.0-20200109141947-94aeca20bf09 // indirect k8s.io/utils v0.0.0-20200109141947-94aeca20bf09 // indirect
sigs.k8s.io/controller-runtime v0.5.0 sigs.k8s.io/kustomize v2.0.3+incompatible // indirect
) )
// Added for go1.13 migration https://github.com/golang/go/issues/32805 // Added for go1.13 migration https://github.com/golang/go/issues/32805
replace ( replace github.com/gorilla/rpc v1.2.0+incompatible => github.com/gorilla/rpc v1.2.0
github.com/gorilla/rpc v1.2.0+incompatible => github.com/gorilla/rpc v1.2.0
k8s.io/code-generator => k8s.io/code-generator v0.0.0-20200306081859-6a048a382944
k8s.io/component-base => k8s.io/component-base v0.0.0-20190612130303-4062e14deebe
)

185
go.sum
View file

@ -15,13 +15,6 @@ github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiU
github.com/Azure/azure-storage-blob-go v0.8.0/go.mod h1:lPI3aLPpuLTeUwh1sViKXFxwl2B6teiRqI0deQUvsw0= github.com/Azure/azure-storage-blob-go v0.8.0/go.mod h1:lPI3aLPpuLTeUwh1sViKXFxwl2B6teiRqI0deQUvsw0=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/Azure/go-autorest v11.7.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest v11.7.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0=
github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA=
github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc=
github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
@ -33,29 +26,21 @@ github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/PuerkitoBio/purell v1.0.0 h1:0GoNN3taZV6QI81IXgCbxMyEaJDXMSIjArYBCYzVVvs= github.com/PuerkitoBio/purell v1.0.0 h1:0GoNN3taZV6QI81IXgCbxMyEaJDXMSIjArYBCYzVVvs=
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2 h1:JCHLVE3B+kJde7bIEo5N4J+ZbLhp0J1Fs+ulyRws4gE= github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2 h1:JCHLVE3B+kJde7bIEo5N4J+ZbLhp0J1Fs+ulyRws4gE=
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/Shopify/sarama v1.24.1/go.mod h1:fGP8eQ6PugKEI0iUETYYtnP6d1pH/bdDMTel1X5ajsU= github.com/Shopify/sarama v1.24.1/go.mod h1:fGP8eQ6PugKEI0iUETYYtnP6d1pH/bdDMTel1X5ajsU=
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
github.com/ajg/form v0.0.0-20160822230020-523a5da1a92f/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/ajg/form v0.0.0-20160822230020-523a5da1a92f/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
github.com/alecthomas/participle v0.2.1/go.mod h1:SW6HZGeZgSIpcUWX3fXpfZhuaWHnmoD5KCVaqSaNTkk= github.com/alecthomas/participle v0.2.1/go.mod h1:SW6HZGeZgSIpcUWX3fXpfZhuaWHnmoD5KCVaqSaNTkk=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20190307165228-86c17b95fcd5/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20190307165228-86c17b95fcd5/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878/go.mod h1:3AMJUQhVx52RsWOnlkpikZr01T/yAVN2gn0861vByNg= github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878/go.mod h1:3AMJUQhVx52RsWOnlkpikZr01T/yAVN2gn0861vByNg=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/aws/aws-sdk-go v1.20.21/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.20.21/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.23.19/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.23.19/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-xray-sdk-go v0.9.4/go.mod h1:XtMKdBQfpVut+tJEwI7+dJFRxxRdxHDyVNp2tHXRq04= github.com/aws/aws-xray-sdk-go v0.9.4/go.mod h1:XtMKdBQfpVut+tJEwI7+dJFRxxRdxHDyVNp2tHXRq04=
@ -65,7 +50,6 @@ github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NR
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
@ -80,7 +64,6 @@ github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk= github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk=
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
github.com/codegangsta/negroni v1.0.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2iZY63YTKWo0= github.com/codegangsta/negroni v1.0.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2iZY63YTKWo0=
github.com/containerd/continuity v0.0.0-20181203112020-004b46473808/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= github.com/containerd/continuity v0.0.0-20181203112020-004b46473808/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
@ -90,16 +73,11 @@ github.com/coreos/bbolt v1.3.3/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkE
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/etcd v3.3.12+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.12+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@ -107,13 +85,9 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/djherbis/atime v1.0.0/go.mod h1:5W+KBIuTwVGcqjIfaTwt+KSYX1o6uep8dtevevQP/f8= github.com/djherbis/atime v1.0.0/go.mod h1:5W+KBIuTwVGcqjIfaTwt+KSYX1o6uep8dtevevQP/f8=
github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v0.0.0-20180713052910-9f541cc9db5d/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v0.0.0-20180713052910-9f541cc9db5d/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
@ -122,14 +96,9 @@ github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts= github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts=
github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4= github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
github.com/elazarl/goproxy v0.0.0-20181003060214-f58a169a71a5/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/elazarl/goproxy v0.0.0-20181003060214-f58a169a71a5/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633 h1:H2pdYOb3KQ1/YsqVWoWNLQO+fusocsw354rqGTZtAgw= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633 h1:H2pdYOb3KQ1/YsqVWoWNLQO+fusocsw354rqGTZtAgw=
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/emicklei/go-restful v2.9.5+incompatible h1:spTtZBk5DYEvbxMVutUuTyh1Ao2r4iyvLdACqsl/Ljk=
github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/evanphx/json-patch v0.0.0-20190203023257-5858425f7550/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/evanphx/json-patch v4.5.0+incompatible h1:ouOWdg56aJriqS0huScTkVXPC5IcNrDCXZ6OoTAWu7M= github.com/evanphx/json-patch v4.5.0+incompatible h1:ouOWdg56aJriqS0huScTkVXPC5IcNrDCXZ6OoTAWu7M=
github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
@ -144,68 +113,21 @@ github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2H
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 h1:Mn26/9ZMNWSw9C9ERFA1PUxfmGpolnw2v0bKOREu5ew= github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 h1:Mn26/9ZMNWSw9C9ERFA1PUxfmGpolnw2v0bKOREu5ew=
github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I= github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I=
github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
github.com/go-bindata/go-bindata v3.1.1+incompatible/go.mod h1:xK8Dsgwmeed+BBsSy2XTopBn/8uK2HWuGSnA11C3Joo= github.com/go-bindata/go-bindata v3.1.1+incompatible/go.mod h1:xK8Dsgwmeed+BBsSy2XTopBn/8uK2HWuGSnA11C3Joo=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc= github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logr/logr v0.1.0 h1:M1Tv3VzNlEHg6uyACnRdtrploV2P7wZqH8BoQMtz0cg=
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
github.com/go-logr/zapr v0.1.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk=
github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI=
github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk=
github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU=
github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94=
github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1 h1:wSt/4CYxs70xbATrGXhokKF1i0tZjENLOo1ioIO13zk= github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1 h1:wSt/4CYxs70xbATrGXhokKF1i0tZjENLOo1ioIO13zk=
github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0=
github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w=
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9 h1:tF+augKRWlWx0J0B7ZyyKSiTyV6E1zZe+7b3qQlcEf8= github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9 h1:tF+augKRWlWx0J0B7ZyyKSiTyV6E1zZe+7b3qQlcEf8=
github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg=
github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o=
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs=
github.com/go-openapi/loads v0.19.4/go.mod h1:zZVHonKd8DXyxyw4yfnVjPzBjIQcLt0CCsn0N0ZrQsk=
github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA=
github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64=
github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4=
github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501 h1:C1JKChikHGpXwT5UQDFaryIpDtyyGL/CR6C2kB7F1oc= github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501 h1:C1JKChikHGpXwT5UQDFaryIpDtyyGL/CR6C2kB7F1oc=
github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc=
github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY=
github.com/go-openapi/spec v0.19.3 h1:0XRyw8kguri6Yw4SxhsQA/atC88yqrk0+G4YhI2wabc=
github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY=
github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU=
github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87 h1:zP3nY8Tk2E6RTkqGYrarZXuzh+ffyLDljLxCy1iJw80= github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87 h1:zP3nY8Tk2E6RTkqGYrarZXuzh+ffyLDljLxCy1iJw80=
github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4=
github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA=
github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
@ -379,18 +301,14 @@ github.com/gobuffalo/x v0.0.0-20181003152136-452098b06085/go.mod h1:WevpGD+5YOre
github.com/gobuffalo/x v0.0.0-20181007152206-913e47c59ca7/go.mod h1:9rDPXaB3kXdKWzMc4odGQQdG2e2DIEmANy5aSJ9yesY= github.com/gobuffalo/x v0.0.0-20181007152206-913e47c59ca7/go.mod h1:9rDPXaB3kXdKWzMc4odGQQdG2e2DIEmANy5aSJ9yesY=
github.com/gofrs/uuid v3.1.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v3.1.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/protobuf v0.0.0-20171007142547-342cbe0a0415/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/golang/gddo v0.0.0-20180828051604-96d2a289f41e/go.mod h1:xEhNfoBDX1hzLm2Nf80qUvZ2sVwoMZ8d6IE2SrsQfh4= github.com/golang/gddo v0.0.0-20180828051604-96d2a289f41e/go.mod h1:xEhNfoBDX1hzLm2Nf80qUvZ2sVwoMZ8d6IE2SrsQfh4=
github.com/golang/gddo v0.0.0-20190904175337-72a348e765d2/go.mod h1:xEhNfoBDX1hzLm2Nf80qUvZ2sVwoMZ8d6IE2SrsQfh4= github.com/golang/gddo v0.0.0-20190904175337-72a348e765d2/go.mod h1:xEhNfoBDX1hzLm2Nf80qUvZ2sVwoMZ8d6IE2SrsQfh4=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20180513044358-24b0969c4cb7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7 h1:5ZkaAPbicIKTF2I64qf5Fh8Aa83Q/dnOafMYV0OMwjA= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7 h1:5ZkaAPbicIKTF2I64qf5Fh8Aa83Q/dnOafMYV0OMwjA=
@ -415,7 +333,6 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg= github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
@ -424,13 +341,11 @@ github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OI
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.0 h1:Jf4mxPC/ziBnoPIdpQdPJ9OeiomAUHLvxmPRSPH9m4s= github.com/google/uuid v1.1.0 h1:Jf4mxPC/ziBnoPIdpQdPJ9OeiomAUHLvxmPRSPH9m4s=
github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
github.com/googleapis/gnostic v0.3.1 h1:WeAefnSUHlBb0iJKwxFDZdbfGwkd7xRNuV+IpXMJhYk= github.com/googleapis/gnostic v0.3.1 h1:WeAefnSUHlBb0iJKwxFDZdbfGwkd7xRNuV+IpXMJhYk=
github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU= github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU=
github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
github.com/gopherjs/gopherjs v0.0.0-20181004151105-1babbf986f6f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20181004151105-1babbf986f6f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v0.0.0-20190328170749-bb2674552d8f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20190328170749-bb2674552d8f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
@ -443,12 +358,9 @@ github.com/gorilla/rpc v1.2.0/go.mod h1:V4h9r+4sF5HnzqbwIez0fKSpANP0zlYd3qR7p36j
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
github.com/gorilla/sessions v1.1.2/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w= github.com/gorilla/sessions v1.1.2/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w=
github.com/gorilla/sessions v1.1.3/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w= github.com/gorilla/sessions v1.1.3/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w=
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA=
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
@ -456,7 +368,6 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
@ -488,8 +399,6 @@ github.com/hashicorp/vault/sdk v0.1.13/go.mod h1:B+hVj7TpuQY1Y/GPbCpffmgd+tSEwvh
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.8 h1:CGgOkSJeqMRmt0D9XLWExdT4m4F1vd3FV3VPt+0VxkQ= github.com/imdario/mergo v0.3.8 h1:CGgOkSJeqMRmt0D9XLWExdT4m4F1vd3FV3VPt+0VxkQ=
github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf/go.mod h1:hyb9oH7vZsitZCiBt0ZvifOrB+qc8PS5IiilCIb87rg= github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf/go.mod h1:hyb9oH7vZsitZCiBt0ZvifOrB+qc8PS5IiilCIb87rg=
@ -506,10 +415,7 @@ github.com/joho/godotenv v1.2.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqx
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
@ -539,14 +445,11 @@ github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kurin/blazer v0.5.4-0.20190613185654-cf2f27cc0be3/go.mod h1:4FCXMUWo9DllR2Do4TtBd377ezyAJ51vB5uTBjt0pGU= github.com/kurin/blazer v0.5.4-0.20190613185654-cf2f27cc0be3/go.mod h1:4FCXMUWo9DllR2Do4TtBd377ezyAJ51vB5uTBjt0pGU=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
github.com/luna-duclos/instrumentedsql v1.1.2/go.mod h1:4LGbEqDnopzNAiyxPPDXhLspyunZxgPTMJBKtC6U0BQ= github.com/luna-duclos/instrumentedsql v1.1.2/go.mod h1:4LGbEqDnopzNAiyxPPDXhLspyunZxgPTMJBKtC6U0BQ=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
@ -554,12 +457,6 @@ github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czP
github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20180730094502-03f2033d19d5 h1:0x4qcEHDpruK6ML/m/YSlFUUu0UpRD3I2PHsNCuGnyA= github.com/mailru/easyjson v0.0.0-20180730094502-03f2033d19d5 h1:0x4qcEHDpruK6ML/m/YSlFUUu0UpRD3I2PHsNCuGnyA=
github.com/mailru/easyjson v0.0.0-20180730094502-03f2033d19d5/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20180730094502-03f2033d19d5/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM=
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
github.com/markbates/deplist v1.0.4/go.mod h1:gRRbPbbuA8TmMiRvaOzUlRfzfjeCCBqX2A6arxN01MM= github.com/markbates/deplist v1.0.4/go.mod h1:gRRbPbbuA8TmMiRvaOzUlRfzfjeCCBqX2A6arxN01MM=
github.com/markbates/deplist v1.0.5/go.mod h1:gRRbPbbuA8TmMiRvaOzUlRfzfjeCCBqX2A6arxN01MM= github.com/markbates/deplist v1.0.5/go.mod h1:gRRbPbbuA8TmMiRvaOzUlRfzfjeCCBqX2A6arxN01MM=
github.com/markbates/going v1.0.2/go.mod h1:UWCk3zm0UKefHZ7l8BNqi26UyiEMniznk8naLdTcy6c= github.com/markbates/going v1.0.2/go.mod h1:UWCk3zm0UKefHZ7l8BNqi26UyiEMniznk8naLdTcy6c=
@ -586,7 +483,6 @@ github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
@ -629,9 +525,7 @@ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwd
github.com/monoculum/formam v0.0.0-20180901015400-4e68be1d79ba/go.mod h1:RKgILGEJq24YyJ2ban8EO0RUVSJlF1pGsEvoLEACr/Q= github.com/monoculum/formam v0.0.0-20180901015400-4e68be1d79ba/go.mod h1:RKgILGEJq24YyJ2ban8EO0RUVSJlF1pGsEvoLEACr/Q=
github.com/moul/http2curl v0.0.0-20170919181001-9ac6cf4d929b/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= github.com/moul/http2curl v0.0.0-20170919181001-9ac6cf4d929b/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ=
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/nats-io/gnatsd v1.4.1/go.mod h1:nqco77VO78hLCJpIcVfygDP2rPGfsEHkGTUk94uh5DQ= github.com/nats-io/gnatsd v1.4.1/go.mod h1:nqco77VO78hLCJpIcVfygDP2rPGfsEHkGTUk94uh5DQ=
github.com/nats-io/go-nats v1.7.2/go.mod h1:+t7RHT5ApZebkrQdnn6AhQJmhJJiKAvJUio1PiiCtj0= github.com/nats-io/go-nats v1.7.2/go.mod h1:+t7RHT5ApZebkrQdnn6AhQJmhJJiKAvJUio1PiiCtj0=
github.com/nats-io/go-nats-streaming v0.4.4/go.mod h1:gfq4R3c9sKAINOpelo0gn/b9QDMBZnmrttcsNF+lqyo= github.com/nats-io/go-nats-streaming v0.4.4/go.mod h1:gfq4R3c9sKAINOpelo0gn/b9QDMBZnmrttcsNF+lqyo=
@ -651,21 +545,15 @@ github.com/nsqio/go-nsq v1.0.7/go.mod h1:XP5zaUs3pqf+Q71EqUJs3HYfBIqfK6G83WQMdNN
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/oleiade/reflections v1.0.0/go.mod h1:RbATFBbKYkVdqmSFtx13Bb/tVhR0lgOBXunWTZKeL4w= github.com/oleiade/reflections v1.0.0/go.mod h1:RbATFBbKYkVdqmSFtx13Bb/tVhR0lgOBXunWTZKeL4w=
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c h1:Hww8mOyEKTeON4bZn7FrlLismspbPc1teNRUVH7wLQ8= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c h1:Hww8mOyEKTeON4bZn7FrlLismspbPc1teNRUVH7wLQ8=
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c h1:eSfnfIuwhxZyULg1NNuZycJcYkjYVGYe7FczwQReM6U= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c h1:eSfnfIuwhxZyULg1NNuZycJcYkjYVGYe7FczwQReM6U=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v0.0.0-20190113212917-5533ce8a0da3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
@ -703,12 +591,10 @@ github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
@ -716,12 +602,10 @@ github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7q
github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rcrowley/go-metrics v0.0.0-20190704165056-9c2d0518ed81/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rcrowley/go-metrics v0.0.0-20190704165056-9c2d0518ed81/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
@ -782,7 +666,6 @@ github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb6
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
@ -794,7 +677,6 @@ github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DM
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
@ -808,7 +690,6 @@ github.com/tidwall/gjson v1.3.5/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJH
github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E= github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tidwall/sjson v1.0.4/go.mod h1:bURseu1nuBkFpIES5cz6zBtjmYeOQmEESshn7VpF15Y= github.com/tidwall/sjson v1.0.4/go.mod h1:bURseu1nuBkFpIES5cz6zBtjmYeOQmEESshn7VpF15Y=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
github.com/uber-go/atomic v1.3.2/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g= github.com/uber-go/atomic v1.3.2/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g=
@ -820,10 +701,8 @@ github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljT
github.com/ugorji/go/codec v1.1.5-pre/go.mod h1:tULtS6Gy1AE1yCENaw4Vb//HLH5njI2tfCQDUqRd8fI= github.com/ugorji/go/codec v1.1.5-pre/go.mod h1:tULtS6Gy1AE1yCENaw4Vb//HLH5njI2tfCQDUqRd8fI=
github.com/unrolled/secure v0.0.0-20180918153822-f340ee86eb8b/go.mod h1:mnPT77IAdsi/kV7+Es7y+pXALeV3h7G6dQF6mNYjcLA= github.com/unrolled/secure v0.0.0-20180918153822-f340ee86eb8b/go.mod h1:mnPT77IAdsi/kV7+Es7y+pXALeV3h7G6dQF6mNYjcLA=
github.com/unrolled/secure v0.0.0-20181005190816-ff9db2ff917f/go.mod h1:mnPT77IAdsi/kV7+Es7y+pXALeV3h7G6dQF6mNYjcLA= github.com/unrolled/secure v0.0.0-20181005190816-ff9db2ff917f/go.mod h1:mnPT77IAdsi/kV7+Es7y+pXALeV3h7G6dQF6mNYjcLA=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4=
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw=
github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=
github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
@ -833,10 +712,6 @@ github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c/go.mod h1:UrdRz5enIKZ63M
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA= go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA=
@ -859,22 +734,15 @@ golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85/go.mod h1:6SG95UA2DQfeDnf
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190102171810-8d7daa0c54b3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190102171810-8d7daa0c54b3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190103213133-ff983b9c42bc/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190103213133-ff983b9c42bc/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191117063200-497ca9f6d64f/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20191117063200-497ca9f6d64f/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200109152110-61a87790db17 h1:nVJ3guKA9qdkEQ3TUdXI9QSINo2CUPM/cySEvw2w8I0= golang.org/x/crypto v0.0.0-20200109152110-61a87790db17 h1:nVJ3guKA9qdkEQ3TUdXI9QSINo2CUPM/cySEvw2w8I0=
golang.org/x/crypto v0.0.0-20200109152110-61a87790db17/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200109152110-61a87790db17/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975 h1:/Tl7pH94bvbAAHBdZJT947M/+gp0+CqQXDtMRC0fseo=
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
@ -903,22 +771,16 @@ golang.org/x/net v0.0.0-20181207154023-610586996380/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190206173232-65e2d4e15006/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@ -960,11 +822,9 @@ golang.org/x/sys v0.0.0-20190102155601-82a175fd1598/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190116161447-11f53e031339/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190116161447-11f53e031339/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -972,10 +832,8 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190523142557-0e01d883c5c5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190523142557-0e01d883c5c5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191105231009-c1f44814a5cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191105231009-c1f44814a5cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1 h1:gZpLHxUX5BdYLA08Lj4YCJNN/jk7KtquiArPoeX0WvA= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1 h1:gZpLHxUX5BdYLA08Lj4YCJNN/jk7KtquiArPoeX0WvA=
@ -986,7 +844,6 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3
golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs=
@ -1018,7 +875,6 @@ golang.org/x/tools v0.0.0-20190104182027-498d95493402/go.mod h1:n7NCudcB/nEzxVGm
golang.org/x/tools v0.0.0-20190111214448-fc1d57b08d7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190111214448-fc1d57b08d7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190118193359-16909d206f00/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190118193359-16909d206f00/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
@ -1028,14 +884,9 @@ golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBn
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190624190245-7f2218787638/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190624190245-7f2218787638/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190711191110-9a621aea19f8/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= golang.org/x/tools v0.0.0-20190711191110-9a621aea19f8/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gomodules.xyz/jsonpatch/v2 v2.0.1/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.5.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.5.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
@ -1067,7 +918,6 @@ google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiq
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
@ -1075,15 +925,12 @@ gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUy
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw= gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
gopkg.in/gorp.v1 v1.7.2/go.mod h1:Wo3h+DBQZIxATwftsglhdD/62zRFPhGhTiu5jUJmCaw= gopkg.in/gorp.v1 v1.7.2/go.mod h1:Wo3h+DBQZIxATwftsglhdD/62zRFPhGhTiu5jUJmCaw=
gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
@ -1095,7 +942,6 @@ gopkg.in/jcmturner/gokrb5.v7 v7.2.3/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuv
gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLvuNnlv8= gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLvuNnlv8=
gopkg.in/ldap.v3 v3.0.3/go.mod h1:oxD7NyBuxchC+SgJDE1Q5Od05eGt29SDQVBmV+HYbzw= gopkg.in/ldap.v3 v3.0.3/go.mod h1:oxD7NyBuxchC+SgJDE1Q5Od05eGt29SDQVBmV+HYbzw=
gopkg.in/mail.v2 v2.0.0-20180731213649-a0242b2233b4/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw= gopkg.in/mail.v2 v2.0.0-20180731213649-a0242b2233b4/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw=
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
gopkg.in/olivere/elastic.v5 v5.0.80/go.mod h1:uhHoB4o3bvX5sorxBU29rPcmBQdV2Qfg0FBrx5D6pV0= gopkg.in/olivere/elastic.v5 v5.0.80/go.mod h1:uhHoB4o3bvX5sorxBU29rPcmBQdV2Qfg0FBrx5D6pV0=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/square/go-jose.v2 v2.1.9/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.1.9/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
@ -1109,8 +955,6 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo= gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
@ -1119,53 +963,24 @@ honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
k8s.io/api v0.0.0-20190409021203-6e4e0e4f393b h1:aBGgKJUM9Hk/3AE8WaZIApnTxG35kbuQba2w+SXqezo= k8s.io/api v0.0.0-20190409021203-6e4e0e4f393b h1:aBGgKJUM9Hk/3AE8WaZIApnTxG35kbuQba2w+SXqezo=
k8s.io/api v0.0.0-20190409021203-6e4e0e4f393b/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA= k8s.io/api v0.0.0-20190409021203-6e4e0e4f393b/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA=
k8s.io/api v0.17.2/go.mod h1:BS9fjjLc4CMuqfSO8vgbHPKMt5+SF0ET6u/RVDihTo4=
k8s.io/api v0.17.4 h1:HbwOhDapkguO8lTAE8OX3hdF2qp8GtpC9CW/MQATXXo=
k8s.io/api v0.17.4/go.mod h1:5qxx6vjmwUVG2nHQTKGlLts8Tbok8PzHl4vHtVFuZCA=
k8s.io/apiextensions-apiserver v0.17.2/go.mod h1:4KdMpjkEjjDI2pPfBA15OscyNldHWdBCfsWMDWAmSTs=
k8s.io/apimachinery v0.0.0-20190404173353-6a84e37a896d h1:Jmdtdt1ZnoGfWWIIik61Z7nKYgO3J+swQJtPYsP9wHA= k8s.io/apimachinery v0.0.0-20190404173353-6a84e37a896d h1:Jmdtdt1ZnoGfWWIIik61Z7nKYgO3J+swQJtPYsP9wHA=
k8s.io/apimachinery v0.0.0-20190404173353-6a84e37a896d/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0= k8s.io/apimachinery v0.0.0-20190404173353-6a84e37a896d/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0=
k8s.io/apimachinery v0.0.0-20190612125636-6a5db36e93ad/go.mod h1:I4A+glKBHiTgiEjQiCCQfCAIcIMFGt291SmsvcrFzJA=
k8s.io/apimachinery v0.17.2/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg=
k8s.io/apimachinery v0.17.4 h1:UzM+38cPUJnzqSQ+E1PY4YxMHIzQyCg29LOoGfo79Zw=
k8s.io/apimachinery v0.17.4/go.mod h1:gxLnyZcGNdZTCLnq3fgzyg2A5BVCHTNDFrw8AmuJ+0g=
k8s.io/apiserver v0.17.2/go.mod h1:lBmw/TtQdtxvrTk0e2cgtOxHizXI+d0mmGQURIHQZlo=
k8s.io/cli-runtime v0.0.0-20191004110135-b9eb767d2e1a h1:REMzGxu+NpG9dPRsE9my/fw9iYIecz1S8UFFl6hbe18= k8s.io/cli-runtime v0.0.0-20191004110135-b9eb767d2e1a h1:REMzGxu+NpG9dPRsE9my/fw9iYIecz1S8UFFl6hbe18=
k8s.io/cli-runtime v0.0.0-20191004110135-b9eb767d2e1a/go.mod h1:qWnH3/b8sp/l7EvlDh7ulDU3UWA4P4N1NFbEEP791tM= k8s.io/cli-runtime v0.0.0-20191004110135-b9eb767d2e1a/go.mod h1:qWnH3/b8sp/l7EvlDh7ulDU3UWA4P4N1NFbEEP791tM=
k8s.io/cli-runtime v0.17.4 h1:ZIJdxpBEszZqUhydrCoiI5rLXS2J/1AF5xFok2QJ9bc=
k8s.io/cli-runtime v0.17.4/go.mod h1:IVW4zrKKx/8gBgNNkhiUIc7nZbVVNhc1+HcQh+PiNHc=
k8s.io/client-go v0.17.2/go.mod h1:QAzRgsa0C2xl4/eVpeVAZMvikCn8Nm81yqVx3Kk9XYI=
k8s.io/client-go v0.17.4 h1:VVdVbpTY70jiNHS1eiFkUt7ZIJX3txd29nDxxXH4en8=
k8s.io/client-go v0.17.4/go.mod h1:ouF6o5pz3is8qU0/qYL2RnoxOPqgfuidYLowytyLJmc=
k8s.io/client-go v11.0.1-0.20190516230509-ae8359b20417+incompatible h1:bK03DJulJi9j05gwnXUufcs2j7h4M85YFvJ0dIlQ9k4= k8s.io/client-go v11.0.1-0.20190516230509-ae8359b20417+incompatible h1:bK03DJulJi9j05gwnXUufcs2j7h4M85YFvJ0dIlQ9k4=
k8s.io/client-go v11.0.1-0.20190516230509-ae8359b20417+incompatible/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s= k8s.io/client-go v11.0.1-0.20190516230509-ae8359b20417+incompatible/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s=
k8s.io/code-generator v0.0.0-20200306081859-6a048a382944/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRVkTc=
k8s.io/component-base v0.0.0-20190612130303-4062e14deebe/go.mod h1:MmIDXnint3qMN0cqXHKrSiJ2XQKo3J1BPIz7in7NvO0=
k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
k8s.io/gengo v0.0.0-20200114144118-36b2048a9120/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
k8s.io/klog v0.3.1/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
k8s.io/kube-openapi v0.0.0-20190228160746-b3a7cee44a30/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc=
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a h1:UcxjrRMyNx/i/y8G7kPvLyy7rfbeuf1PYyBf973pgyU= k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a h1:UcxjrRMyNx/i/y8G7kPvLyy7rfbeuf1PYyBf973pgyU=
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c h1:/KUFqjjqAcY4Us6luF5RDNZ16KJtb49HfR3ZHB9qYXM=
k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E=
k8s.io/utils v0.0.0-20190221042446-c2654d5206da/go.mod h1:8k8uAuAQ0rXslZKaEWd0c3oVhZz7sSzSiPnVZayjIX0=
k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
k8s.io/utils v0.0.0-20200109141947-94aeca20bf09 h1:sz6xjn8QP74104YNmJpzLbJ+a3ZtHt0tkD0g8vpdWNw= k8s.io/utils v0.0.0-20200109141947-94aeca20bf09 h1:sz6xjn8QP74104YNmJpzLbJ+a3ZtHt0tkD0g8vpdWNw=
k8s.io/utils v0.0.0-20200109141947-94aeca20bf09/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= k8s.io/utils v0.0.0-20200109141947-94aeca20bf09/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
sigs.k8s.io/controller-runtime v0.5.0 h1:CbqIy5fbUX+4E9bpnBFd204YAzRYlM9SWW77BbrcDQo=
sigs.k8s.io/controller-runtime v0.5.0/go.mod h1:REiJzC7Y00U+2YkMbT8wxgrsX5USpXKGhb2sCtAXiT8=
sigs.k8s.io/kustomize v2.0.3+incompatible h1:JUufWFNlI44MdtnjUqVnvh29rR37PQFzPbLXqhyOyX0= sigs.k8s.io/kustomize v2.0.3+incompatible h1:JUufWFNlI44MdtnjUqVnvh29rR37PQFzPbLXqhyOyX0=
sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU= sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU=
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18=
sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw=
sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=

View file

@ -74,7 +74,7 @@ func (in *ClusterPolicy) DeepCopyObject() runtime.Object {
func (in *ClusterPolicyList) DeepCopyInto(out *ClusterPolicyList) { func (in *ClusterPolicyList) DeepCopyInto(out *ClusterPolicyList) {
*out = *in *out = *in
out.TypeMeta = in.TypeMeta out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta) out.ListMeta = in.ListMeta
if in.Items != nil { if in.Items != nil {
in, out := &in.Items, &out.Items in, out := &in.Items, &out.Items
*out = make([]ClusterPolicy, len(*in)) *out = make([]ClusterPolicy, len(*in))
@ -135,7 +135,7 @@ func (in *ClusterPolicyViolation) DeepCopyObject() runtime.Object {
func (in *ClusterPolicyViolationList) DeepCopyInto(out *ClusterPolicyViolationList) { func (in *ClusterPolicyViolationList) DeepCopyInto(out *ClusterPolicyViolationList) {
*out = *in *out = *in
out.TypeMeta = in.TypeMeta out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta) out.ListMeta = in.ListMeta
if in.Items != nil { if in.Items != nil {
in, out := &in.Items, &out.Items in, out := &in.Items, &out.Items
*out = make([]ClusterPolicyViolation, len(*in)) *out = make([]ClusterPolicyViolation, len(*in))
@ -241,7 +241,7 @@ func (in *GenerateRequestContext) DeepCopy() *GenerateRequestContext {
func (in *GenerateRequestList) DeepCopyInto(out *GenerateRequestList) { func (in *GenerateRequestList) DeepCopyInto(out *GenerateRequestList) {
*out = *in *out = *in
out.TypeMeta = in.TypeMeta out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta) out.ListMeta = in.ListMeta
if in.Items != nil { if in.Items != nil {
in, out := &in.Items, &out.Items in, out := &in.Items, &out.Items
*out = make([]GenerateRequest, len(*in)) *out = make([]GenerateRequest, len(*in))
@ -420,7 +420,7 @@ func (in *PolicyViolation) DeepCopyObject() runtime.Object {
func (in *PolicyViolationList) DeepCopyInto(out *PolicyViolationList) { func (in *PolicyViolationList) DeepCopyInto(out *PolicyViolationList) {
*out = *in *out = *in
out.TypeMeta = in.TypeMeta out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta) out.ListMeta = in.ListMeta
if in.Items != nil { if in.Items != nil {
in, out := &in.Items, &out.Items in, out := &in.Items, &out.Items
*out = make([]PolicyViolation, len(*in)) *out = make([]PolicyViolation, len(*in))

View file

@ -1,108 +0,0 @@
package auth
import (
"fmt"
"reflect"
"github.com/go-logr/logr"
client "github.com/nirmata/kyverno/pkg/dclient"
authorizationv1 "k8s.io/api/authorization/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
)
//CanIOptions provides utility ti check if user has authorization for the given operation
type CanIOptions struct {
namespace string
verb string
kind string
client *client.Client
log logr.Logger
}
//NewCanI returns a new instance of operation access controler evaluator
func NewCanI(client *client.Client, kind, namespace, verb string, log logr.Logger) *CanIOptions {
o := CanIOptions{
client: client,
log: log,
}
o.namespace = namespace
o.kind = kind
o.verb = verb
return &o
}
//RunAccessCheck checks if the caller can perform the operation
// - operation is a combination of namespace, kind, verb
// - can only evaluate a single verb
// - group version resource is determined from the kind using the discovery client REST mapper
// - If disallowed, the reason and evaluationError is avialable in the logs
// - each can generates a SelfSubjectAccessReview resource and response is evaluated for permissions
func (o *CanIOptions) RunAccessCheck() (bool, error) {
// get GroupVersionResource from RESTMapper
// get GVR from kind
gvr := o.client.DiscoveryClient.GetGVRFromKind(o.kind)
if reflect.DeepEqual(gvr, schema.GroupVersionResource{}) {
// cannot find GVR
return false, fmt.Errorf("failed to get the Group Version Resource for kind %s", o.kind)
}
sar := &authorizationv1.SelfSubjectAccessReview{
Spec: authorizationv1.SelfSubjectAccessReviewSpec{
ResourceAttributes: &authorizationv1.ResourceAttributes{
Namespace: o.namespace,
Verb: o.verb,
Group: gvr.Group,
Resource: gvr.Resource,
},
},
}
// Set self subject access review
// - namespace
// - verb
// - resource
// - subresource
logger := o.log.WithValues("kind", sar.Kind, "namespace", sar.Namespace, "name", sar.Name)
// Create the Resource
resp, err := o.client.CreateResource("SelfSubjectAccessReview", "", sar, false)
if err != nil {
logger.Error(err, "failed to create resource")
return false, err
}
// status.allowed
allowed, ok, err := unstructured.NestedBool(resp.Object, "status", "allowed")
if !ok {
if err != nil {
logger.Error(err, "failed to get the field", "field", "status.allowed")
}
logger.Info("field not found", "field", "status.allowed")
}
if !allowed {
// status.reason
reason, ok, err := unstructured.NestedString(resp.Object, "status", "reason")
if !ok {
if err != nil {
logger.Error(err, "failed to get the field", "field", "status.reason")
}
logger.Info("field not found", "field", "status.reason")
}
// status.evaluationError
evaluationError, ok, err := unstructured.NestedString(resp.Object, "status", "evaludationError")
if !ok {
if err != nil {
logger.Error(err, "failed to get the field", "field", "status.evaluationError")
}
logger.Info("field not found", "field", "status.evaluationError")
}
// Reporting ? (just logs)
logger.Info("disallowed operation", "reason", reason, "evaluationError", evaluationError)
}
return allowed, nil
}

View file

@ -1,48 +0,0 @@
package auth
// import (
// "testing"
// "time"
// "github.com/golang/glog"
// "github.com/nirmata/kyverno/pkg/config"
// dclient "github.com/nirmata/kyverno/pkg/dclient"
// "github.com/nirmata/kyverno/pkg/signal"
// )
// func Test_Auth_pass(t *testing.T) {
// // needs running cluster
// var kubeconfig string
// stopCh := signal.SetupSignalHandler()
// kubeconfig = "/Users/shivd/.kube/config"
// clientConfig, err := config.CreateClientConfig(kubeconfig)
// if err != nil {
// glog.Fatalf("Error building kubeconfig: %v\n", err)
// }
// // DYNAMIC CLIENT
// // - client for all registered resources
// // - invalidate local cache of registered resource every 10 seconds
// client, err := dclient.NewClient(clientConfig, 10*time.Second, stopCh)
// if err != nil {
// glog.Fatalf("Error creating client: %v\n", err)
// }
// // Can i authenticate
// kind := "Deployment"
// namespace := "default"
// verb := "test"
// canI := NewCanI(client, kind, namespace, verb)
// ok, err := canI.RunAccessCheck()
// if err != nil {
// t.Error(err)
// }
// if ok {
// t.Log("allowed")
// } else {
// t.Log("notallowed")
// }
// t.FailNow()
// }

View file

@ -4,7 +4,7 @@ import (
"sync" "sync"
"time" "time"
"github.com/go-logr/logr" "github.com/golang/glog"
kyvernolister "github.com/nirmata/kyverno/pkg/client/listers/kyverno/v1" kyvernolister "github.com/nirmata/kyverno/pkg/client/listers/kyverno/v1"
dclient "github.com/nirmata/kyverno/pkg/dclient" dclient "github.com/nirmata/kyverno/pkg/dclient"
"github.com/nirmata/kyverno/pkg/event" "github.com/nirmata/kyverno/pkg/event"
@ -20,9 +20,8 @@ const (
// LastReqTime stores the lastrequest times for incoming api-requests // LastReqTime stores the lastrequest times for incoming api-requests
type LastReqTime struct { type LastReqTime struct {
t time.Time t time.Time
mu sync.RWMutex mu sync.RWMutex
log logr.Logger
} }
//Time returns the lastrequest time //Time returns the lastrequest time
@ -40,17 +39,16 @@ func (t *LastReqTime) SetTime(tm time.Time) {
} }
//NewLastReqTime returns a new instance of LastRequestTime store //NewLastReqTime returns a new instance of LastRequestTime store
func NewLastReqTime(log logr.Logger) *LastReqTime { func NewLastReqTime() *LastReqTime {
return &LastReqTime{ return &LastReqTime{
t: time.Now(), t: time.Now(),
log: log,
} }
} }
func checkIfPolicyWithMutateAndGenerateExists(pLister kyvernolister.ClusterPolicyLister, log logr.Logger) bool { func checkIfPolicyWithMutateAndGenerateExists(pLister kyvernolister.ClusterPolicyLister) bool {
policies, err := pLister.ListResources(labels.NewSelector()) policies, err := pLister.ListResources(labels.NewSelector())
if err != nil { if err != nil {
log.Error(err, "failed to list cluster policies") glog.Error()
} }
for _, policy := range policies { for _, policy := range policies {
if policy.HasMutateOrValidateOrGenerate() { if policy.HasMutateOrValidateOrGenerate() {
@ -64,16 +62,15 @@ func checkIfPolicyWithMutateAndGenerateExists(pLister kyvernolister.ClusterPolic
//Run runs the checker and verify the resource update //Run runs the checker and verify the resource update
func (t *LastReqTime) Run(pLister kyvernolister.ClusterPolicyLister, eventGen event.Interface, client *dclient.Client, defaultResync time.Duration, deadline time.Duration, stopCh <-chan struct{}) { func (t *LastReqTime) Run(pLister kyvernolister.ClusterPolicyLister, eventGen event.Interface, client *dclient.Client, defaultResync time.Duration, deadline time.Duration, stopCh <-chan struct{}) {
logger := t.log glog.V(2).Infof("starting default resync for webhook checker with resync time %d nanoseconds", defaultResync)
logger.V(2).Info("tarting default resync for webhook checker", "resyncTime", defaultResync)
maxDeadline := deadline * time.Duration(MaxRetryCount) maxDeadline := deadline * time.Duration(MaxRetryCount)
ticker := time.NewTicker(defaultResync) ticker := time.NewTicker(defaultResync)
/// interface to update and increment kyverno webhook status via annotations /// interface to update and increment kyverno webhook status via annotations
statuscontrol := NewVerifyControl(client, eventGen, logger.WithName("StatusControl")) statuscontrol := NewVerifyControl(client, eventGen)
// send the initial update status // send the initial update status
if checkIfPolicyWithMutateAndGenerateExists(pLister, logger) { if checkIfPolicyWithMutateAndGenerateExists(pLister) {
if err := statuscontrol.SuccessStatus(); err != nil { if err := statuscontrol.SuccessStatus(); err != nil {
logger.Error(err, "failed to set 'success' status") glog.Error(err)
} }
} }
@ -87,36 +84,36 @@ func (t *LastReqTime) Run(pLister kyvernolister.ClusterPolicyLister, eventGen ev
case <-ticker.C: case <-ticker.C:
// if there are no policies then we dont have a webhook on resource. // if there are no policies then we dont have a webhook on resource.
// we indirectly check if the resource // we indirectly check if the resource
if !checkIfPolicyWithMutateAndGenerateExists(pLister, logger) { if !checkIfPolicyWithMutateAndGenerateExists(pLister) {
continue continue
} }
// get current time // get current time
timeDiff := time.Since(t.Time()) timeDiff := time.Since(t.Time())
if timeDiff > maxDeadline { if timeDiff > maxDeadline {
logger.Info("request exceeded max deadline", "deadline", maxDeadline) glog.Infof("failed to receive any request for more than %v ", maxDeadline)
logger.Info("Admission Control failing: Webhook is not receiving requests forwarded by api-server as per webhook configurations") glog.Info("Admission Control failing: Webhook is not receiving requests forwarded by api-server as per webhook configurations")
// set the status unavailable // set the status unavailable
if err := statuscontrol.FailedStatus(); err != nil { if err := statuscontrol.FailedStatus(); err != nil {
logger.Error(err, "failed to set 'failed' status") glog.Error(err)
} }
continue continue
} }
if timeDiff > deadline { if timeDiff > deadline {
logger.Info("Admission Control failing: Webhook is not receiving requests forwarded by api-server as per webhook configurations") glog.Info("Admission Control failing: Webhook is not receiving requests forwarded by api-server as per webhook configurations")
// send request to update the kyverno deployment // send request to update the kyverno deployment
if err := statuscontrol.IncrementAnnotation(); err != nil { if err := statuscontrol.IncrementAnnotation(); err != nil {
logger.Error(err, "failed to increment annotation") glog.Error(err)
} }
continue continue
} }
// if the status was false before then we update it to true // if the status was false before then we update it to true
// send request to update the kyverno deployment // send request to update the kyverno deployment
if err := statuscontrol.SuccessStatus(); err != nil { if err := statuscontrol.SuccessStatus(); err != nil {
logger.Error(err, "failed to update success status") glog.Error(err)
} }
case <-stopCh: case <-stopCh:
// handler termination signal // handler termination signal
logger.V(2).Info("stopping default resync for webhook checker") glog.V(2).Infof("stopping default resync for webhook checker")
return return
} }
} }

View file

@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"strconv" "strconv"
"github.com/go-logr/logr" "github.com/golang/glog"
dclient "github.com/nirmata/kyverno/pkg/dclient" dclient "github.com/nirmata/kyverno/pkg/dclient"
"github.com/nirmata/kyverno/pkg/event" "github.com/nirmata/kyverno/pkg/event"
) )
@ -29,7 +29,6 @@ type StatusInterface interface {
type StatusControl struct { type StatusControl struct {
client *dclient.Client client *dclient.Client
eventGen event.Interface eventGen event.Interface
log logr.Logger
} }
//SuccessStatus ... //SuccessStatus ...
@ -43,22 +42,20 @@ func (vc StatusControl) FailedStatus() error {
} }
// NewVerifyControl ... // NewVerifyControl ...
func NewVerifyControl(client *dclient.Client, eventGen event.Interface, log logr.Logger) *StatusControl { func NewVerifyControl(client *dclient.Client, eventGen event.Interface) *StatusControl {
return &StatusControl{ return &StatusControl{
client: client, client: client,
eventGen: eventGen, eventGen: eventGen,
log: log,
} }
} }
func (vc StatusControl) setStatus(status string) error { func (vc StatusControl) setStatus(status string) error {
logger := vc.log glog.Infof("setting deployment %s in ns %s annotation %s to %s", deployName, deployNamespace, annWebhookStats, status)
logger.Info(fmt.Sprintf("setting deployment %s in ns %s annotation %s to %s", deployName, deployNamespace, annWebhookStats, status))
var ann map[string]string var ann map[string]string
var err error var err error
deploy, err := vc.client.GetResource("Deployment", deployNamespace, deployName) deploy, err := vc.client.GetResource("Deployment", deployNamespace, deployName)
if err != nil { if err != nil {
logger.Error(err, "failed to get deployment resource") glog.V(4).Infof("failed to get deployment %s in namespace %s: %v", deployName, deployNamespace, err)
return err return err
} }
ann = deploy.GetAnnotations() ann = deploy.GetAnnotations()
@ -70,7 +67,7 @@ func (vc StatusControl) setStatus(status string) error {
if ok { if ok {
// annotatiaion is present // annotatiaion is present
if webhookAction == status { if webhookAction == status {
logger.V(4).Info(fmt.Sprintf("annotation %s already set to '%s'", annWebhookStats, status)) glog.V(4).Infof("annotation %s already set to '%s'", annWebhookStats, status)
return nil return nil
} }
} }
@ -80,7 +77,7 @@ func (vc StatusControl) setStatus(status string) error {
// update counter // update counter
_, err = vc.client.UpdateResource("Deployment", deployNamespace, deploy, false) _, err = vc.client.UpdateResource("Deployment", deployNamespace, deploy, false)
if err != nil { if err != nil {
logger.Error(err, fmt.Sprintf("failed to update annotation %s for deployment %s in namespace %s", annWebhookStats, deployName, deployNamespace)) glog.V(4).Infof("failed to update annotation %s for deployment %s in namespace %s: %v", annWebhookStats, deployName, deployNamespace, err)
return err return err
} }
// create event on kyverno deployment // create event on kyverno deployment
@ -100,13 +97,12 @@ func createStatusUpdateEvent(status string, eventGen event.Interface) {
//IncrementAnnotation ... //IncrementAnnotation ...
func (vc StatusControl) IncrementAnnotation() error { func (vc StatusControl) IncrementAnnotation() error {
logger := vc.log glog.Infof("setting deployment %s in ns %s annotation %s", deployName, deployNamespace, annCounter)
logger.Info(fmt.Sprintf("setting deployment %s in ns %s annotation %s", deployName, deployNamespace, annCounter))
var ann map[string]string var ann map[string]string
var err error var err error
deploy, err := vc.client.GetResource("Deployment", deployNamespace, deployName) deploy, err := vc.client.GetResource("Deployment", deployNamespace, deployName)
if err != nil { if err != nil {
logger.Error(err, "failed to get deployment %s in namespace %s", deployName, deployNamespace) glog.V(4).Infof("failed to get deployment %s in namespace %s: %v", deployName, deployNamespace, err)
return err return err
} }
ann = deploy.GetAnnotations() ann = deploy.GetAnnotations()
@ -116,18 +112,18 @@ func (vc StatusControl) IncrementAnnotation() error {
} }
counter, err := strconv.Atoi(ann[annCounter]) counter, err := strconv.Atoi(ann[annCounter])
if err != nil { if err != nil {
logger.Error(err, "Failed to parse string") glog.V(4).Infof("failed to parse string: %v", err)
return err return err
} }
// increment counter // increment counter
counter++ counter++
ann[annCounter] = strconv.Itoa(counter) ann[annCounter] = strconv.Itoa(counter)
logger.Info("incrementing annotation", "old", annCounter, "new", counter) glog.Infof("incrementing annotation %s counter to %d", annCounter, counter)
deploy.SetAnnotations(ann) deploy.SetAnnotations(ann)
// update counter // update counter
_, err = vc.client.UpdateResource("Deployment", deployNamespace, deploy, false) _, err = vc.client.UpdateResource("Deployment", deployNamespace, deploy, false)
if err != nil { if err != nil {
logger.Error(err, fmt.Sprintf("failed to update annotation %s for deployment %s in namespace %s", annCounter, deployName, deployNamespace)) glog.V(4).Infof("failed to update annotation %s for deployment %s in namespace %s: %v", annCounter, deployName, deployNamespace, err)
return err return err
} }
return nil return nil

View file

@ -19,8 +19,6 @@ limitations under the License.
package versioned package versioned
import ( import (
"fmt"
kyvernov1 "github.com/nirmata/kyverno/pkg/client/clientset/versioned/typed/kyverno/v1" kyvernov1 "github.com/nirmata/kyverno/pkg/client/clientset/versioned/typed/kyverno/v1"
discovery "k8s.io/client-go/discovery" discovery "k8s.io/client-go/discovery"
rest "k8s.io/client-go/rest" rest "k8s.io/client-go/rest"
@ -53,14 +51,9 @@ func (c *Clientset) Discovery() discovery.DiscoveryInterface {
} }
// NewForConfig creates a new Clientset for the given config. // NewForConfig creates a new Clientset for the given config.
// If config's RateLimiter is not set and QPS and Burst are acceptable,
// NewForConfig will generate a rate-limiter in configShallowCopy.
func NewForConfig(c *rest.Config) (*Clientset, error) { func NewForConfig(c *rest.Config) (*Clientset, error) {
configShallowCopy := *c configShallowCopy := *c
if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 { if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 {
if configShallowCopy.Burst <= 0 {
return nil, fmt.Errorf("Burst is required to be greater than 0 when RateLimiter is not set and QPS is set to greater than 0")
}
configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst) configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst)
} }
var cs Clientset var cs Clientset

View file

@ -41,7 +41,7 @@ func NewSimpleClientset(objects ...runtime.Object) *Clientset {
} }
} }
cs := &Clientset{tracker: o} cs := &Clientset{}
cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake} cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake}
cs.AddReactor("*", "*", testing.ObjectReaction(o)) cs.AddReactor("*", "*", testing.ObjectReaction(o))
cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) { cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) {
@ -63,17 +63,12 @@ func NewSimpleClientset(objects ...runtime.Object) *Clientset {
type Clientset struct { type Clientset struct {
testing.Fake testing.Fake
discovery *fakediscovery.FakeDiscovery discovery *fakediscovery.FakeDiscovery
tracker testing.ObjectTracker
} }
func (c *Clientset) Discovery() discovery.DiscoveryInterface { func (c *Clientset) Discovery() discovery.DiscoveryInterface {
return c.discovery return c.discovery
} }
func (c *Clientset) Tracker() testing.ObjectTracker {
return c.tracker
}
var _ clientset.Interface = &Clientset{} var _ clientset.Interface = &Clientset{}
// KyvernoV1 retrieves the KyvernoV1Client // KyvernoV1 retrieves the KyvernoV1Client

View file

@ -29,8 +29,7 @@ import (
var scheme = runtime.NewScheme() var scheme = runtime.NewScheme()
var codecs = serializer.NewCodecFactory(scheme) var codecs = serializer.NewCodecFactory(scheme)
var parameterCodec = runtime.NewParameterCodec(scheme)
// var parameterCodec = runtime.NewParameterCodec(scheme)
var localSchemeBuilder = runtime.SchemeBuilder{ var localSchemeBuilder = runtime.SchemeBuilder{
kyvernov1.AddToScheme, kyvernov1.AddToScheme,
} }

View file

@ -21,6 +21,7 @@ package v1
import ( import (
v1 "github.com/nirmata/kyverno/pkg/api/kyverno/v1" v1 "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
"github.com/nirmata/kyverno/pkg/client/clientset/versioned/scheme" "github.com/nirmata/kyverno/pkg/client/clientset/versioned/scheme"
serializer "k8s.io/apimachinery/pkg/runtime/serializer"
rest "k8s.io/client-go/rest" rest "k8s.io/client-go/rest"
) )
@ -85,7 +86,7 @@ func setConfigDefaults(config *rest.Config) error {
gv := v1.SchemeGroupVersion gv := v1.SchemeGroupVersion
config.GroupVersion = &gv config.GroupVersion = &gv
config.APIPath = "/apis" config.APIPath = "/apis"
config.NegotiatedSerializer = scheme.Codecs.WithoutConversion() config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: scheme.Codecs}
if config.UserAgent == "" { if config.UserAgent == "" {
config.UserAgent = rest.DefaultKubernetesUserAgent() config.UserAgent = rest.DefaultKubernetesUserAgent()

View file

@ -1,7 +1,9 @@
package config package config
import ( import (
"github.com/go-logr/logr" "flag"
"github.com/golang/glog"
rest "k8s.io/client-go/rest" rest "k8s.io/client-go/rest"
clientcmd "k8s.io/client-go/tools/clientcmd" clientcmd "k8s.io/client-go/tools/clientcmd"
) )
@ -72,13 +74,29 @@ var (
VerifyMutatingWebhookServicePath = "/verifymutate" VerifyMutatingWebhookServicePath = "/verifymutate"
) )
//LogDefaultFlags sets default glog flags
func LogDefaultFlags() {
var err error
err = flag.Set("logtostderr", "true")
if err != nil {
glog.Fatalf("failed to set flag 'logtostderr' to 'true':%v", err)
}
err = flag.Set("stderrthreshold", "WARNING")
if err != nil {
glog.Fatalf("failed to set flag 'stderrthreshold' to 'WARNING':%v", err)
}
flag.Set("v", "2")
if err != nil {
glog.Fatalf("failed to set flag 'v' to '2':%v", err)
}
}
//CreateClientConfig creates client config //CreateClientConfig creates client config
func CreateClientConfig(kubeconfig string, log logr.Logger) (*rest.Config, error) { func CreateClientConfig(kubeconfig string) (*rest.Config, error) {
logger := log.WithName("CreateClientConfig")
if kubeconfig == "" { if kubeconfig == "" {
logger.Info("Using in-cluster configuration") glog.Info("Using in-cluster configuration")
return rest.InClusterConfig() return rest.InClusterConfig()
} }
logger.V(4).Info("Using specified kubeconfig", "kubeconfig", kubeconfig) glog.V(4).Infof("Using configuration from '%s'", kubeconfig)
return clientcmd.BuildConfigFromFlags("", kubeconfig) return clientcmd.BuildConfigFromFlags("", kubeconfig)
} }

View file

@ -1,13 +1,14 @@
package config package config
import ( import (
"fmt"
"os" "os"
"reflect" "reflect"
"regexp" "regexp"
"strings" "strings"
"sync" "sync"
"github.com/go-logr/logr" "github.com/golang/glog"
"github.com/minio/minio/pkg/wildcard" "github.com/minio/minio/pkg/wildcard"
v1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
informers "k8s.io/client-go/informers/core/v1" informers "k8s.io/client-go/informers/core/v1"
@ -30,7 +31,6 @@ type ConfigData struct {
filters []k8Resource filters []k8Resource
// hasynced // hasynced
cmSycned cache.InformerSynced cmSycned cache.InformerSynced
log logr.Logger
} }
// ToFilter checks if the given resource is set to be filtered in the configuration // ToFilter checks if the given resource is set to be filtered in the configuration
@ -51,21 +51,20 @@ type Interface interface {
} }
// NewConfigData ... // NewConfigData ...
func NewConfigData(rclient kubernetes.Interface, cmInformer informers.ConfigMapInformer, filterK8Resources string, log logr.Logger) *ConfigData { func NewConfigData(rclient kubernetes.Interface, cmInformer informers.ConfigMapInformer, filterK8Resources string) *ConfigData {
// environment var is read at start only // environment var is read at start only
if cmNameEnv == "" { if cmNameEnv == "" {
log.Info("ConfigMap name not defined in env:INIT_CONFIG: loading no default configuration") glog.Info("ConfigMap name not defined in env:INIT_CONFIG: loading no default configuration")
} }
cd := ConfigData{ cd := ConfigData{
client: rclient, client: rclient,
cmName: os.Getenv(cmNameEnv), cmName: os.Getenv(cmNameEnv),
cmSycned: cmInformer.Informer().HasSynced, cmSycned: cmInformer.Informer().HasSynced,
log: log,
} }
//TODO: this has been added to backward support command line arguments //TODO: this has been added to backward support command line arguments
// will be removed in future and the configuration will be set only via configmaps // will be removed in future and the configuration will be set only via configmaps
if filterK8Resources != "" { if filterK8Resources != "" {
cd.log.Info("init configuration from commandline arguments") glog.Info("Init configuration from commandline arguments")
cd.initFilters(filterK8Resources) cd.initFilters(filterK8Resources)
} }
@ -79,10 +78,9 @@ func NewConfigData(rclient kubernetes.Interface, cmInformer informers.ConfigMapI
//Run checks syncing //Run checks syncing
func (cd *ConfigData) Run(stopCh <-chan struct{}) { func (cd *ConfigData) Run(stopCh <-chan struct{}) {
logger := cd.log
// wait for cache to populate first time // wait for cache to populate first time
if !cache.WaitForCacheSync(stopCh, cd.cmSycned) { if !cache.WaitForCacheSync(stopCh, cd.cmSycned) {
logger.Info("configuration: failed to sync informer cache") glog.Error("configuration: failed to sync informer cache")
} }
} }
@ -105,17 +103,16 @@ func (cd *ConfigData) updateCM(old, cur interface{}) {
} }
func (cd *ConfigData) deleteCM(obj interface{}) { func (cd *ConfigData) deleteCM(obj interface{}) {
logger := cd.log
cm, ok := obj.(*v1.ConfigMap) cm, ok := obj.(*v1.ConfigMap)
if !ok { if !ok {
tombstone, ok := obj.(cache.DeletedFinalStateUnknown) tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
if !ok { if !ok {
logger.Info("failed to get object from tombstone") glog.Info(fmt.Errorf("Couldn't get object from tombstone %#v", obj))
return return
} }
_, ok = tombstone.Obj.(*v1.ConfigMap) _, ok = tombstone.Obj.(*v1.ConfigMap)
if !ok { if !ok {
logger.Info("Tombstone contained object that is not a ConfigMap", "object", obj) glog.Info(fmt.Errorf("Tombstone contained object that is not a ConfigMap %#v", obj))
return return
} }
} }
@ -128,20 +125,19 @@ func (cd *ConfigData) deleteCM(obj interface{}) {
} }
func (cd *ConfigData) load(cm v1.ConfigMap) { func (cd *ConfigData) load(cm v1.ConfigMap) {
logger := cd.log.WithValues("name", cm.Name, "namespace", cm.Namespace)
if cm.Data == nil { if cm.Data == nil {
logger.V(4).Info("configuration: No data defined in ConfigMap") glog.V(4).Infof("Configuration: No data defined in ConfigMap %s", cm.Name)
return return
} }
// get resource filters // get resource filters
filters, ok := cm.Data["resourceFilters"] filters, ok := cm.Data["resourceFilters"]
if !ok { if !ok {
logger.V(4).Info("configuration: No resourceFilters defined in ConfigMap") glog.V(4).Infof("Configuration: No resourceFilters defined in ConfigMap %s", cm.Name)
return return
} }
// filters is a string // filters is a string
if filters == "" { if filters == "" {
logger.V(4).Info("configuration: resourceFilters is empty in ConfigMap") glog.V(4).Infof("Configuration: resourceFilters is empty in ConfigMap %s", cm.Name)
return return
} }
// parse and load the configuration // parse and load the configuration
@ -150,10 +146,11 @@ func (cd *ConfigData) load(cm v1.ConfigMap) {
newFilters := parseKinds(filters) newFilters := parseKinds(filters)
if reflect.DeepEqual(newFilters, cd.filters) { if reflect.DeepEqual(newFilters, cd.filters) {
logger.V(4).Info("resourceFilters did not change") glog.V(4).Infof("Configuration: resourceFilters did not change in ConfigMap %s", cm.Name)
return return
} }
logger.V(4).Info(" Updated resource filters", "oldFilters", cd.filters, "newFilters", newFilters) glog.V(4).Infof("Configuration: Old resource filters %v", cd.filters)
glog.Infof("Configuration: New resource filters to %v", newFilters)
// update filters // update filters
cd.filters = newFilters cd.filters = newFilters
} }
@ -161,20 +158,20 @@ func (cd *ConfigData) load(cm v1.ConfigMap) {
//TODO: this has been added to backward support command line arguments //TODO: this has been added to backward support command line arguments
// will be removed in future and the configuration will be set only via configmaps // will be removed in future and the configuration will be set only via configmaps
func (cd *ConfigData) initFilters(filters string) { func (cd *ConfigData) initFilters(filters string) {
logger := cd.log
// parse and load the configuration // parse and load the configuration
cd.mux.Lock() cd.mux.Lock()
defer cd.mux.Unlock() defer cd.mux.Unlock()
newFilters := parseKinds(filters) newFilters := parseKinds(filters)
logger.Info("Init resource filters", "filters", newFilters) glog.Infof("Configuration: Init resource filters to %v", newFilters)
// update filters // update filters
cd.filters = newFilters cd.filters = newFilters
} }
func (cd *ConfigData) unload(cm v1.ConfigMap) { func (cd *ConfigData) unload(cm v1.ConfigMap) {
logger := cd.log // TODO pick one msg
logger.Info("ConfigMap deleted, removing configuration filters", "name", cm.Name, "namespace", cm.Namespace) glog.Infof("Configuration: ConfigMap %s deleted, removing configuration filters", cm.Name)
glog.Infof("Configuration: Removing all resource filters as ConfigMap %s deleted", cm.Name)
cd.mux.Lock() cd.mux.Lock()
defer cd.mux.Unlock() defer cd.mux.Unlock()
cd.filters = []k8Resource{} cd.filters = []k8Resource{}

View file

@ -6,6 +6,7 @@ import (
"net/url" "net/url"
"time" "time"
"github.com/golang/glog"
"github.com/nirmata/kyverno/pkg/config" "github.com/nirmata/kyverno/pkg/config"
tls "github.com/nirmata/kyverno/pkg/tls" tls "github.com/nirmata/kyverno/pkg/tls"
certificates "k8s.io/api/certificates/v1beta1" certificates "k8s.io/api/certificates/v1beta1"
@ -18,14 +19,13 @@ import (
// Created pair is stored in cluster's secret. // Created pair is stored in cluster's secret.
// Returns struct with key/certificate pair. // Returns struct with key/certificate pair.
func (c *Client) InitTLSPemPair(configuration *rest.Config, fqdncn bool) (*tls.TlsPemPair, error) { func (c *Client) InitTLSPemPair(configuration *rest.Config, fqdncn bool) (*tls.TlsPemPair, error) {
logger := c.log
certProps, err := c.GetTLSCertProps(configuration) certProps, err := c.GetTLSCertProps(configuration)
if err != nil { if err != nil {
return nil, err return nil, err
} }
tlsPair := c.ReadTlsPair(certProps) tlsPair := c.ReadTlsPair(certProps)
if tls.IsTLSPairShouldBeUpdated(tlsPair) { if tls.IsTLSPairShouldBeUpdated(tlsPair) {
logger.Info("Generating new key/certificate pair for TLS") glog.Info("Generating new key/certificate pair for TLS")
tlsPair, err = c.generateTLSPemPair(certProps, fqdncn) tlsPair, err = c.generateTLSPemPair(certProps, fqdncn)
if err != nil { if err != nil {
return nil, err return nil, err
@ -35,7 +35,8 @@ func (c *Client) InitTLSPemPair(configuration *rest.Config, fqdncn bool) (*tls.T
} }
return tlsPair, nil return tlsPair, nil
} }
logger.Info("Using existing TLS key/certificate pair")
glog.Infoln("Using existing TLS key/certificate pair")
return tlsPair, nil return tlsPair, nil
} }
@ -70,7 +71,6 @@ func (c *Client) generateTLSPemPair(props tls.TlsCertificateProps, fqdncn bool)
// Submits and approves certificate request, returns request which need to be fetched // Submits and approves certificate request, returns request which need to be fetched
func (c *Client) submitAndApproveCertificateRequest(req *certificates.CertificateSigningRequest) (*certificates.CertificateSigningRequest, error) { func (c *Client) submitAndApproveCertificateRequest(req *certificates.CertificateSigningRequest) (*certificates.CertificateSigningRequest, error) {
logger := c.log.WithName("submitAndApproveCertificateRequest")
certClient, err := c.GetCSRInterface() certClient, err := c.GetCSRInterface()
if err != nil { if err != nil {
return nil, err return nil, err
@ -86,7 +86,7 @@ func (c *Client) submitAndApproveCertificateRequest(req *certificates.Certificat
if err != nil { if err != nil {
return nil, fmt.Errorf("Unable to delete existing certificate request: %v", err) return nil, fmt.Errorf("Unable to delete existing certificate request: %v", err)
} }
logger.Info("Old certificate request is deleted") glog.Info("Old certificate request is deleted")
break break
} }
} }
@ -95,7 +95,7 @@ func (c *Client) submitAndApproveCertificateRequest(req *certificates.Certificat
if err != nil { if err != nil {
return nil, err return nil, err
} }
logger.Info("Certificate request created", "name", unstrRes.GetName()) glog.Infof("Certificate request %s is created", unstrRes.GetName())
res, err := convertToCSR(unstrRes) res, err := convertToCSR(unstrRes)
if err != nil { if err != nil {
@ -110,7 +110,7 @@ func (c *Client) submitAndApproveCertificateRequest(req *certificates.Certificat
if err != nil { if err != nil {
return nil, fmt.Errorf("Unable to approve certificate request: %v", err) return nil, fmt.Errorf("Unable to approve certificate request: %v", err)
} }
logger.Info("Certificate request is approved", "name", res.ObjectMeta.Name) glog.Infof("Certificate request %s is approved", res.ObjectMeta.Name)
return res, nil return res, nil
} }
@ -144,10 +144,9 @@ func (c *Client) fetchCertificateFromRequest(req *certificates.CertificateSignin
//ReadRootCASecret returns the RootCA from the pre-defined secret //ReadRootCASecret returns the RootCA from the pre-defined secret
func (c *Client) ReadRootCASecret() (result []byte) { func (c *Client) ReadRootCASecret() (result []byte) {
logger := c.log.WithName("ReadRootCASecret")
certProps, err := c.GetTLSCertProps(c.clientConfig) certProps, err := c.GetTLSCertProps(c.clientConfig)
if err != nil { if err != nil {
logger.Error(err, "failed to get TLS Cert Properties") glog.Error(err)
return result return result
} }
sname := generateRootCASecretName(certProps) sname := generateRootCASecretName(certProps)
@ -157,16 +156,16 @@ func (c *Client) ReadRootCASecret() (result []byte) {
} }
tlsca, err := convertToSecret(stlsca) tlsca, err := convertToSecret(stlsca)
if err != nil { if err != nil {
logger.Error(err, "failed to convert secret", "name", sname, "namespace", certProps.Namespace) glog.Error(err)
return result return result
} }
result = tlsca.Data[rootCAKey] result = tlsca.Data[rootCAKey]
if len(result) == 0 { if len(result) == 0 {
logger.Info("root CA certificate not found in secret", "name", tlsca.Name, "namespace", certProps.Namespace) glog.Warningf("root CA certificate not found in secret %s/%s", certProps.Namespace, tlsca.Name)
return result return result
} }
logger.V(4).Info("using CA bundle defined in secret to validate the webhook's server certificate", "name", tlsca.Name, "namespace", certProps.Namespace) glog.V(4).Infof("using CA bundle defined in secret %s/%s to validate the webhook's server certificate", certProps.Namespace, tlsca.Name)
return result return result
} }
@ -175,11 +174,10 @@ const rootCAKey string = "rootCA.crt"
//ReadTlsPair Reads the pair of TLS certificate and key from the specified secret. //ReadTlsPair Reads the pair of TLS certificate and key from the specified secret.
func (c *Client) ReadTlsPair(props tls.TlsCertificateProps) *tls.TlsPemPair { func (c *Client) ReadTlsPair(props tls.TlsCertificateProps) *tls.TlsPemPair {
logger := c.log.WithName("ReadTlsPair")
sname := generateTLSPairSecretName(props) sname := generateTLSPairSecretName(props)
unstrSecret, err := c.GetResource(Secrets, props.Namespace, sname) unstrSecret, err := c.GetResource(Secrets, props.Namespace, sname)
if err != nil { if err != nil {
logger.Error(err, "Failed to get secret", "name", sname, "namespace", props.Namespace) glog.Warningf("Unable to get secret %s/%s: %s", props.Namespace, sname, err)
return nil return nil
} }
@ -190,7 +188,7 @@ func (c *Client) ReadTlsPair(props tls.TlsCertificateProps) *tls.TlsPemPair {
sname := generateRootCASecretName(props) sname := generateRootCASecretName(props)
_, err := c.GetResource(Secrets, props.Namespace, sname) _, err := c.GetResource(Secrets, props.Namespace, sname)
if err != nil { if err != nil {
logger.Error(err, "Root CA secret is required while using self-signed certificates TLS pair, defaulting to generating new TLS pair", "name", sname, "namespace", props.Namespace) glog.Errorf("Root CA secret %s/%s is required while using self-signed certificates TLS pair, defaulting to generating new TLS pair", props.Namespace, sname)
return nil return nil
} }
} }
@ -203,11 +201,11 @@ func (c *Client) ReadTlsPair(props tls.TlsCertificateProps) *tls.TlsPemPair {
PrivateKey: secret.Data[v1.TLSPrivateKeyKey], PrivateKey: secret.Data[v1.TLSPrivateKeyKey],
} }
if len(pemPair.Certificate) == 0 { if len(pemPair.Certificate) == 0 {
logger.Info("TLS Certificate not found in secret", "name", sname, "namespace", props.Namespace) glog.Warningf("TLS Certificate not found in secret %s/%s", props.Namespace, sname)
return nil return nil
} }
if len(pemPair.PrivateKey) == 0 { if len(pemPair.PrivateKey) == 0 {
logger.Info("TLS PrivateKey not found in secret", "name", sname, "namespace", props.Namespace) glog.Warningf("TLS PrivateKey not found in secret %s/%s", props.Namespace, sname)
return nil return nil
} }
return &pemPair return &pemPair
@ -216,7 +214,6 @@ func (c *Client) ReadTlsPair(props tls.TlsCertificateProps) *tls.TlsPemPair {
//WriteTlsPair Writes the pair of TLS certificate and key to the specified secret. //WriteTlsPair Writes the pair of TLS certificate and key to the specified secret.
// Updates existing secret or creates new one. // Updates existing secret or creates new one.
func (c *Client) WriteTlsPair(props tls.TlsCertificateProps, pemPair *tls.TlsPemPair) error { func (c *Client) WriteTlsPair(props tls.TlsCertificateProps, pemPair *tls.TlsPemPair) error {
logger := c.log.WithName("WriteTlsPair")
name := generateTLSPairSecretName(props) name := generateTLSPairSecretName(props)
_, err := c.GetResource(Secrets, props.Namespace, name) _, err := c.GetResource(Secrets, props.Namespace, name)
if err != nil { if err != nil {
@ -238,7 +235,7 @@ func (c *Client) WriteTlsPair(props tls.TlsCertificateProps, pemPair *tls.TlsPem
_, err := c.CreateResource(Secrets, props.Namespace, secret, false) _, err := c.CreateResource(Secrets, props.Namespace, secret, false)
if err == nil { if err == nil {
logger.Info("secret created", "name", name, "namespace", props.Namespace) glog.Infof("Secret %s is created", name)
} }
return err return err
} }
@ -254,7 +251,7 @@ func (c *Client) WriteTlsPair(props tls.TlsCertificateProps, pemPair *tls.TlsPem
if err != nil { if err != nil {
return err return err
} }
logger.Info("secret updated", "name", name, "namespace", props.Namespace) glog.Infof("Secret %s is updated", name)
return nil return nil
} }

View file

@ -5,8 +5,9 @@ import (
"strings" "strings"
"time" "time"
"github.com/go-logr/logr"
openapi_v2 "github.com/googleapis/gnostic/OpenAPIv2" openapi_v2 "github.com/googleapis/gnostic/OpenAPIv2"
"github.com/golang/glog"
"github.com/nirmata/kyverno/pkg/config" "github.com/nirmata/kyverno/pkg/config"
apps "k8s.io/api/apps/v1" apps "k8s.io/api/apps/v1"
certificates "k8s.io/api/certificates/v1beta1" certificates "k8s.io/api/certificates/v1beta1"
@ -31,15 +32,13 @@ import (
//Client enables interaction with k8 resource //Client enables interaction with k8 resource
type Client struct { type Client struct {
client dynamic.Interface client dynamic.Interface
log logr.Logger
clientConfig *rest.Config clientConfig *rest.Config
kclient kubernetes.Interface kclient kubernetes.Interface
DiscoveryClient IDiscovery DiscoveryClient IDiscovery
} }
//NewClient creates new instance of client //NewClient creates new instance of client
func NewClient(config *rest.Config, resync time.Duration, stopCh <-chan struct{}, log logr.Logger) (*Client, error) { func NewClient(config *rest.Config, resync time.Duration, stopCh <-chan struct{}) (*Client, error) {
dclient, err := dynamic.NewForConfig(config) dclient, err := dynamic.NewForConfig(config)
if err != nil { if err != nil {
return nil, err return nil, err
@ -52,10 +51,9 @@ func NewClient(config *rest.Config, resync time.Duration, stopCh <-chan struct{}
client: dclient, client: dclient,
clientConfig: config, clientConfig: config,
kclient: kclient, kclient: kclient,
log: log.WithName("Client"),
} }
// Set discovery client // Set discovery client
discoveryClient := ServerPreferredResources{cachedClient: memory.NewMemCacheClient(kclient.Discovery()), log: client.log} discoveryClient := ServerPreferredResources{memory.NewMemCacheClient(kclient.Discovery())}
// client will invalidate registered resources cache every x seconds, // client will invalidate registered resources cache every x seconds,
// As there is no way to identify if the registered resource is available or not // As there is no way to identify if the registered resource is available or not
// we will be invalidating the local cache, so the next request get a fresh cache // we will be invalidating the local cache, so the next request get a fresh cache
@ -191,6 +189,7 @@ func (c *Client) UpdateStatusResource(kind string, namespace string, obj interfa
func convertToUnstructured(obj interface{}) *unstructured.Unstructured { func convertToUnstructured(obj interface{}) *unstructured.Unstructured {
unstructuredObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&obj) unstructuredObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&obj)
if err != nil { if err != nil {
glog.Errorf("Unable to convert : %v", err)
return nil return nil
} }
return &unstructured.Unstructured{Object: unstructuredObj} return &unstructured.Unstructured{Object: unstructuredObj}
@ -229,24 +228,22 @@ func (c *Client) SetDiscovery(discoveryClient IDiscovery) {
//ServerPreferredResources stores the cachedClient instance for discovery client //ServerPreferredResources stores the cachedClient instance for discovery client
type ServerPreferredResources struct { type ServerPreferredResources struct {
cachedClient discovery.CachedDiscoveryInterface cachedClient discovery.CachedDiscoveryInterface
log logr.Logger
} }
//Poll will keep invalidate the local cache //Poll will keep invalidate the local cache
func (c ServerPreferredResources) Poll(resync time.Duration, stopCh <-chan struct{}) { func (c ServerPreferredResources) Poll(resync time.Duration, stopCh <-chan struct{}) {
logger := c.log.WithName("Poll")
// start a ticker // start a ticker
ticker := time.NewTicker(resync) ticker := time.NewTicker(resync)
defer func() { ticker.Stop() }() defer func() { ticker.Stop() }()
logger.Info("starting registered resources sync", "period", resync) glog.Infof("Starting registered resources sync: every %d seconds", resync)
for { for {
select { select {
case <-stopCh: case <-stopCh:
logger.Info("stopping registered resources sync") glog.Info("Stopping registered resources sync")
return return
case <-ticker.C: case <-ticker.C:
// set cache as stale // set cache as stale
logger.V(6).Info("invalidating local client cache for registered resources") glog.V(6).Info("invalidating local client cache for registered resources")
c.cachedClient.Invalidate() c.cachedClient.Invalidate()
} }
} }
@ -264,12 +261,12 @@ func (c ServerPreferredResources) OpenAPISchema() (*openapi_v2.Document, error)
func (c ServerPreferredResources) GetGVRFromKind(kind string) schema.GroupVersionResource { func (c ServerPreferredResources) GetGVRFromKind(kind string) schema.GroupVersionResource {
var gvr schema.GroupVersionResource var gvr schema.GroupVersionResource
var err error var err error
gvr, err = loadServerResources(kind, c.cachedClient, c.log) gvr, err = loadServerResources(kind, c.cachedClient)
if err != nil && !c.cachedClient.Fresh() { if err != nil && !c.cachedClient.Fresh() {
// invalidate cahce & re-try once more // invalidate cahce & re-try once more
c.cachedClient.Invalidate() c.cachedClient.Invalidate()
gvr, err = loadServerResources(kind, c.cachedClient, c.log) gvr, err = loadServerResources(kind, c.cachedClient)
if err == nil { if err == nil {
return gvr return gvr
} }
@ -282,12 +279,11 @@ func (c ServerPreferredResources) GetServerVersion() (*version.Info, error) {
return c.cachedClient.ServerVersion() return c.cachedClient.ServerVersion()
} }
func loadServerResources(k string, cdi discovery.CachedDiscoveryInterface, log logr.Logger) (schema.GroupVersionResource, error) { func loadServerResources(k string, cdi discovery.CachedDiscoveryInterface) (schema.GroupVersionResource, error) {
logger := log.WithName("loadServerResources")
emptyGVR := schema.GroupVersionResource{}
serverresources, err := cdi.ServerPreferredResources() serverresources, err := cdi.ServerPreferredResources()
emptyGVR := schema.GroupVersionResource{}
if err != nil { if err != nil {
logger.Error(err, "failed to get registered preferred resources") glog.Error(err)
return emptyGVR, err return emptyGVR, err
} }
for _, serverresource := range serverresources { for _, serverresource := range serverresources {
@ -297,7 +293,7 @@ func loadServerResources(k string, cdi discovery.CachedDiscoveryInterface, log l
if resource.Kind == k && !strings.Contains(resource.Name, "/") { if resource.Kind == k && !strings.Contains(resource.Name, "/") {
gv, err := schema.ParseGroupVersion(serverresource.GroupVersion) gv, err := schema.ParseGroupVersion(serverresource.GroupVersion)
if err != nil { if err != nil {
logger.Error(err, "failed to parse groupVersion from schema", "groupVersion", serverresource.GroupVersion) glog.Error(err)
return emptyGVR, err return emptyGVR, err
} }
return gv.WithResource(resource.Name), nil return gv.WithResource(resource.Name), nil

View file

@ -4,8 +4,7 @@ import (
"fmt" "fmt"
"strconv" "strconv"
"github.com/go-logr/logr" "github.com/golang/glog"
"sigs.k8s.io/controller-runtime/pkg/log"
) )
//ValidationHandler for element processes //ValidationHandler for element processes
@ -13,7 +12,7 @@ type ValidationHandler interface {
Handle(handler resourceElementHandler, resourceMap map[string]interface{}, originPattern interface{}) (string, error) Handle(handler resourceElementHandler, resourceMap map[string]interface{}, originPattern interface{}) (string, error)
} }
type resourceElementHandler = func(log logr.Logger, resourceElement, patternElement, originPattern interface{}, path string) (string, error) type resourceElementHandler = func(resourceElement, patternElement, originPattern interface{}, path string) (string, error)
//CreateElementHandler factory to process elements //CreateElementHandler factory to process elements
func CreateElementHandler(element string, pattern interface{}, path string) ValidationHandler { func CreateElementHandler(element string, pattern interface{}, path string) ValidationHandler {
@ -83,7 +82,7 @@ func (eh EqualityHandler) Handle(handler resourceElementHandler, resourceMap map
// check if anchor is present in resource // check if anchor is present in resource
if value, ok := resourceMap[anchorKey]; ok { if value, ok := resourceMap[anchorKey]; ok {
// validate the values of the pattern // validate the values of the pattern
returnPath, err := handler(log.Log, value, eh.pattern, originPattern, currentPath) returnPath, err := handler(value, eh.pattern, originPattern, currentPath)
if err != nil { if err != nil {
return returnPath, err return returnPath, err
} }
@ -116,7 +115,7 @@ func (dh DefaultHandler) Handle(handler resourceElementHandler, resourceMap map[
} else if dh.pattern == "*" && resourceMap[dh.element] == nil { } else if dh.pattern == "*" && resourceMap[dh.element] == nil {
return dh.path, fmt.Errorf("Validation rule failed at %s, Field %s is not present", dh.path, dh.element) return dh.path, fmt.Errorf("Validation rule failed at %s, Field %s is not present", dh.path, dh.element)
} else { } else {
path, err := handler(log.Log, resourceMap[dh.element], dh.pattern, originPattern, currentPath) path, err := handler(resourceMap[dh.element], dh.pattern, originPattern, currentPath)
if err != nil { if err != nil {
return path, err return path, err
} }
@ -147,7 +146,7 @@ func (ch ConditionAnchorHandler) Handle(handler resourceElementHandler, resource
// check if anchor is present in resource // check if anchor is present in resource
if value, ok := resourceMap[anchorKey]; ok { if value, ok := resourceMap[anchorKey]; ok {
// validate the values of the pattern // validate the values of the pattern
returnPath, err := handler(log.Log, value, ch.pattern, originPattern, currentPath) returnPath, err := handler(value, ch.pattern, originPattern, currentPath)
if err != nil { if err != nil {
return returnPath, err return returnPath, err
} }
@ -195,6 +194,7 @@ func (eh ExistenceHandler) Handle(handler resourceElementHandler, resourceMap ma
} }
return validateExistenceListResource(handler, typedResource, typedPatternMap, originPattern, currentPath) return validateExistenceListResource(handler, typedResource, typedPatternMap, originPattern, currentPath)
default: default:
glog.Error("Invalid type: Existence ^ () anchor can be used only on list/array type resource")
return currentPath, fmt.Errorf("Invalid resource type %T: Existence ^ () anchor can be used only on list/array type resource", value) return currentPath, fmt.Errorf("Invalid resource type %T: Existence ^ () anchor can be used only on list/array type resource", value)
} }
} }
@ -206,9 +206,10 @@ func validateExistenceListResource(handler resourceElementHandler, resourceList
// if non satisfy then throw an error // if non satisfy then throw an error
for i, resourceElement := range resourceList { for i, resourceElement := range resourceList {
currentPath := path + strconv.Itoa(i) + "/" currentPath := path + strconv.Itoa(i) + "/"
_, err := handler(log.Log, resourceElement, patternMap, originPattern, currentPath) _, err := handler(resourceElement, patternMap, originPattern, currentPath)
if err == nil { if err == nil {
// condition is satisfied, dont check further // condition is satisfied, dont check further
glog.V(4).Infof("Existence check satisfied at path %s, for pattern %v", currentPath, patternMap)
return "", nil return "", nil
} }
} }

View file

@ -6,9 +6,8 @@ import (
"sync" "sync"
jsonpatch "github.com/evanphx/json-patch" jsonpatch "github.com/evanphx/json-patch"
"github.com/go-logr/logr" "github.com/golang/glog"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1" kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
"sigs.k8s.io/controller-runtime/pkg/log"
) )
//Interface to manage context operations //Interface to manage context operations
@ -34,7 +33,6 @@ type Context struct {
mu sync.RWMutex mu sync.RWMutex
jsonRaw []byte jsonRaw []byte
whiteListVars []string whiteListVars []string
log logr.Logger
} }
//NewContext returns a new context //NewContext returns a new context
@ -44,7 +42,6 @@ func NewContext(whiteListVars ...string) *Context {
// data: map[string]interface{}{}, // data: map[string]interface{}{},
jsonRaw: []byte(`{}`), // empty json struct jsonRaw: []byte(`{}`), // empty json struct
whiteListVars: whiteListVars, whiteListVars: whiteListVars,
log: log.Log.WithName("context"),
} }
return &ctx return &ctx
} }
@ -57,7 +54,7 @@ func (ctx *Context) AddJSON(dataRaw []byte) error {
// merge json // merge json
ctx.jsonRaw, err = jsonpatch.MergePatch(ctx.jsonRaw, dataRaw) ctx.jsonRaw, err = jsonpatch.MergePatch(ctx.jsonRaw, dataRaw)
if err != nil { if err != nil {
ctx.log.Error(err, "failed to merge JSON data") glog.V(4).Infof("failed to merge JSON data: %v", err)
return err return err
} }
return nil return nil
@ -69,7 +66,7 @@ func (ctx *Context) AddResource(dataRaw []byte) error {
// unmarshall the resource struct // unmarshall the resource struct
var data interface{} var data interface{}
if err := json.Unmarshal(dataRaw, &data); err != nil { if err := json.Unmarshal(dataRaw, &data); err != nil {
ctx.log.Error(err, "failed to unmarshall the resource") glog.V(4).Infof("failed to unmarshall the context data: %v", err)
return err return err
} }
@ -85,7 +82,7 @@ func (ctx *Context) AddResource(dataRaw []byte) error {
objRaw, err := json.Marshal(modifiedResource) objRaw, err := json.Marshal(modifiedResource)
if err != nil { if err != nil {
ctx.log.Error(err, "failed to marshal the resource") glog.V(4).Infof("failed to marshall the updated context data")
return err return err
} }
return ctx.AddJSON(objRaw) return ctx.AddJSON(objRaw)
@ -101,7 +98,7 @@ func (ctx *Context) AddUserInfo(userRequestInfo kyverno.RequestInfo) error {
objRaw, err := json.Marshal(modifiedResource) objRaw, err := json.Marshal(modifiedResource)
if err != nil { if err != nil {
ctx.log.Error(err, "failed to marshal the UserInfo") glog.V(4).Infof("failed to marshall the updated context data")
return err return err
} }
return ctx.AddJSON(objRaw) return ctx.AddJSON(objRaw)
@ -121,6 +118,8 @@ func (ctx *Context) AddSA(userName string) error {
// filter namespace // filter namespace
groups := strings.Split(sa, ":") groups := strings.Split(sa, ":")
if len(groups) >= 2 { if len(groups) >= 2 {
glog.V(4).Infof("serviceAccount namespace: %s", groups[0])
glog.V(4).Infof("serviceAccount name: %s", groups[1])
saName = groups[1] saName = groups[1]
saNamespace = groups[0] saNamespace = groups[0]
} }
@ -132,7 +131,7 @@ func (ctx *Context) AddSA(userName string) error {
} }
saNameRaw, err := json.Marshal(saNameObj) saNameRaw, err := json.Marshal(saNameObj)
if err != nil { if err != nil {
ctx.log.Error(err, "failed to marshal the SA") glog.V(4).Infof("failed to marshall the updated context data")
return err return err
} }
if err := ctx.AddJSON(saNameRaw); err != nil { if err := ctx.AddJSON(saNameRaw); err != nil {
@ -146,7 +145,7 @@ func (ctx *Context) AddSA(userName string) error {
} }
saNsRaw, err := json.Marshal(saNsObj) saNsRaw, err := json.Marshal(saNsObj)
if err != nil { if err != nil {
ctx.log.Error(err, "failed to marshal the SA namespace") glog.V(4).Infof("failed to marshall the updated context data")
return err return err
} }
if err := ctx.AddJSON(saNsRaw); err != nil { if err := ctx.AddJSON(saNsRaw); err != nil {

View file

@ -4,6 +4,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/golang/glog"
jmespath "github.com/jmespath/go-jmespath" jmespath "github.com/jmespath/go-jmespath"
) )
@ -18,7 +19,7 @@ func (ctx *Context) Query(query string) (interface{}, error) {
// compile the query // compile the query
queryPath, err := jmespath.Compile(query) queryPath, err := jmespath.Compile(query)
if err != nil { if err != nil {
ctx.log.Error(err, "incorrect query", "query", query) glog.V(4).Infof("incorrect query %s: %v", query, err)
return emptyResult, fmt.Errorf("incorrect query %s: %v", query, err) return emptyResult, fmt.Errorf("incorrect query %s: %v", query, err)
} }
// search // search
@ -27,13 +28,13 @@ func (ctx *Context) Query(query string) (interface{}, error) {
var data interface{} var data interface{}
if err := json.Unmarshal(ctx.jsonRaw, &data); err != nil { if err := json.Unmarshal(ctx.jsonRaw, &data); err != nil {
ctx.log.Error(err, "failed to unmarshal context") glog.V(4).Infof("failed to unmarshall context: %v", err)
return emptyResult, fmt.Errorf("failed to unmarshall context: %v", err) return emptyResult, fmt.Errorf("failed to unmarshall context: %v", err)
} }
result, err := queryPath.Search(data) result, err := queryPath.Search(data)
if err != nil { if err != nil {
ctx.log.Error(err, "failed to search query", "query", query) glog.V(4).Infof("failed to search query %s: %v", query, err)
return emptyResult, fmt.Errorf("failed to search query %s: %v", query, err) return emptyResult, fmt.Errorf("failed to search query %s: %v", query, err)
} }
return result, nil return result, nil

View file

@ -12,7 +12,6 @@ import (
"github.com/nirmata/kyverno/pkg/engine/utils" "github.com/nirmata/kyverno/pkg/engine/utils"
"github.com/nirmata/kyverno/pkg/engine/variables" "github.com/nirmata/kyverno/pkg/engine/variables"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"sigs.k8s.io/controller-runtime/pkg/log"
) )
func mutateResourceWithOverlay(resource unstructured.Unstructured, overlay interface{}) (unstructured.Unstructured, error) { func mutateResourceWithOverlay(resource unstructured.Unstructured, overlay interface{}) (unstructured.Unstructured, error) {
@ -58,7 +57,7 @@ func ForceMutate(ctx context.EvalInterface, policy kyverno.ClusterPolicy, resour
if mutation.Overlay != nil { if mutation.Overlay != nil {
overlay := mutation.Overlay overlay := mutation.Overlay
if ctx != nil { if ctx != nil {
if overlay, err = variables.SubstituteVars(log.Log, ctx, overlay); err != nil { if overlay, err = variables.SubstituteVars(ctx, overlay); err != nil {
return unstructured.Unstructured{}, err return unstructured.Unstructured{}, err
} }
} else { } else {
@ -73,7 +72,7 @@ func ForceMutate(ctx context.EvalInterface, policy kyverno.ClusterPolicy, resour
if rule.Mutation.Patches != nil { if rule.Mutation.Patches != nil {
var resp response.RuleResponse var resp response.RuleResponse
resp, resource = mutate.ProcessPatches(log.Log, rule, resource) resp, resource = mutate.ProcessPatches(rule, resource)
if !resp.Success { if !resp.Success {
return unstructured.Unstructured{}, fmt.Errorf(resp.Message) return unstructured.Unstructured{}, fmt.Errorf(resp.Message)
} }

View file

@ -3,14 +3,12 @@ package engine
import ( import (
"time" "time"
"github.com/go-logr/logr" "github.com/golang/glog"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1" kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
"github.com/nirmata/kyverno/pkg/engine/context" "github.com/nirmata/kyverno/pkg/engine/context"
"github.com/nirmata/kyverno/pkg/engine/response" "github.com/nirmata/kyverno/pkg/engine/response"
"github.com/nirmata/kyverno/pkg/engine/variables" "github.com/nirmata/kyverno/pkg/engine/variables"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"sigs.k8s.io/controller-runtime/pkg/log"
) )
// Generate checks for validity of generate rule on the resource // Generate checks for validity of generate rule on the resource
@ -22,11 +20,10 @@ func Generate(policyContext PolicyContext) (resp response.EngineResponse) {
resource := policyContext.NewResource resource := policyContext.NewResource
admissionInfo := policyContext.AdmissionInfo admissionInfo := policyContext.AdmissionInfo
ctx := policyContext.Context ctx := policyContext.Context
logger := log.Log.WithName("Generate").WithValues("policy", policy.Name, "kind", resource.GetKind(), "namespace", resource.GetNamespace(), "name", resource.GetName()) return filterRules(policy, resource, admissionInfo, ctx)
return filterRules(policy, resource, admissionInfo, ctx, logger)
} }
func filterRule(rule kyverno.Rule, resource unstructured.Unstructured, admissionInfo kyverno.RequestInfo, ctx context.EvalInterface, log logr.Logger) *response.RuleResponse { func filterRule(rule kyverno.Rule, resource unstructured.Unstructured, admissionInfo kyverno.RequestInfo, ctx context.EvalInterface) *response.RuleResponse {
if !rule.HasGenerate() { if !rule.HasGenerate() {
return nil return nil
} }
@ -34,14 +31,15 @@ func filterRule(rule kyverno.Rule, resource unstructured.Unstructured, admission
startTime := time.Now() startTime := time.Now()
if err := MatchesResourceDescription(resource, rule, admissionInfo); err != nil { if err := MatchesResourceDescription(resource, rule, admissionInfo); err != nil {
glog.V(4).Infof(err.Error())
return nil return nil
} }
// operate on the copy of the conditions, as we perform variable substitution // operate on the copy of the conditions, as we perform variable substitution
copyConditions := copyConditions(rule.Conditions) copyConditions := copyConditions(rule.Conditions)
// evaluate pre-conditions // evaluate pre-conditions
if !variables.EvaluateConditions(log, ctx, copyConditions) { if !variables.EvaluateConditions(ctx, copyConditions) {
log.V(4).Info("preconditions not satisfied, skipping rule", "rule", rule.Name) glog.V(4).Infof("resource %s/%s does not satisfy the conditions for the rule ", resource.GetNamespace(), resource.GetName())
return nil return nil
} }
// build rule Response // build rule Response
@ -55,7 +53,7 @@ func filterRule(rule kyverno.Rule, resource unstructured.Unstructured, admission
} }
} }
func filterRules(policy kyverno.ClusterPolicy, resource unstructured.Unstructured, admissionInfo kyverno.RequestInfo, ctx context.EvalInterface, log logr.Logger) response.EngineResponse { func filterRules(policy kyverno.ClusterPolicy, resource unstructured.Unstructured, admissionInfo kyverno.RequestInfo, ctx context.EvalInterface) response.EngineResponse {
resp := response.EngineResponse{ resp := response.EngineResponse{
PolicyResponse: response.PolicyResponse{ PolicyResponse: response.PolicyResponse{
Policy: policy.Name, Policy: policy.Name,
@ -68,7 +66,7 @@ func filterRules(policy kyverno.ClusterPolicy, resource unstructured.Unstructure
} }
for _, rule := range policy.Spec.Rules { for _, rule := range policy.Spec.Rules {
if ruleResp := filterRule(rule, resource, admissionInfo, ctx, log); ruleResp != nil { if ruleResp := filterRule(rule, resource, admissionInfo, ctx); ruleResp != nil {
resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, *ruleResp) resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, *ruleResp)
} }
} }

View file

@ -10,53 +10,51 @@ import (
"strings" "strings"
"time" "time"
"github.com/golang/glog"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"sigs.k8s.io/controller-runtime/pkg/log"
jsonpatch "github.com/evanphx/json-patch" jsonpatch "github.com/evanphx/json-patch"
"github.com/go-logr/logr"
"github.com/nirmata/kyverno/pkg/engine/anchor" "github.com/nirmata/kyverno/pkg/engine/anchor"
"github.com/nirmata/kyverno/pkg/engine/response" "github.com/nirmata/kyverno/pkg/engine/response"
"github.com/nirmata/kyverno/pkg/engine/utils" "github.com/nirmata/kyverno/pkg/engine/utils"
) )
// ProcessOverlay processes mutation overlay on the resource // ProcessOverlay processes mutation overlay on the resource
func ProcessOverlay(log logr.Logger, ruleName string, overlay interface{}, resource unstructured.Unstructured) (resp response.RuleResponse, patchedResource unstructured.Unstructured) { func ProcessOverlay(ruleName string, overlay interface{}, resource unstructured.Unstructured) (resp response.RuleResponse, patchedResource unstructured.Unstructured) {
startTime := time.Now() startTime := time.Now()
logger := log.WithValues("rule", ruleName) glog.V(4).Infof("started applying overlay rule %q (%v)", ruleName, startTime)
logger.V(4).Info("started applying overlay rule ", "startTime", startTime)
resp.Name = ruleName resp.Name = ruleName
resp.Type = utils.Mutation.String() resp.Type = utils.Mutation.String()
defer func() { defer func() {
resp.RuleStats.ProcessingTime = time.Since(startTime) resp.RuleStats.ProcessingTime = time.Since(startTime)
logger.V(4).Info("finished applying overlay rule", "processingTime", resp.RuleStats.ProcessingTime) glog.V(4).Infof("finished applying overlay rule %q (%v)", resp.Name, resp.RuleStats.ProcessingTime)
}() }()
patches, overlayerr := processOverlayPatches(logger, resource.UnstructuredContent(), overlay) patches, overlayerr := processOverlayPatches(resource.UnstructuredContent(), overlay)
// resource does not satisfy the overlay pattern, we don't apply this rule // resource does not satisfy the overlay pattern, we don't apply this rule
if !reflect.DeepEqual(overlayerr, overlayError{}) { if !reflect.DeepEqual(overlayerr, overlayError{}) {
switch overlayerr.statusCode { switch overlayerr.statusCode {
// condition key is not present in the resource, don't apply this rule // condition key is not present in the resource, don't apply this rule
// consider as success // consider as success
case conditionNotPresent: case conditionNotPresent:
logger.V(3).Info("skip applying rule") glog.V(3).Infof("Skip applying rule '%s' on resource '%s/%s/%s': %s", ruleName, resource.GetKind(), resource.GetNamespace(), resource.GetName(), overlayerr.ErrorMsg())
resp.Success = true resp.Success = true
return resp, resource return resp, resource
// conditions are not met, don't apply this rule // conditions are not met, don't apply this rule
case conditionFailure: case conditionFailure:
logger.V(3).Info("skip applying rule") glog.V(3).Infof("Skip applying rule '%s' on resource '%s/%s/%s': %s", ruleName, resource.GetKind(), resource.GetNamespace(), resource.GetName(), overlayerr.ErrorMsg())
//TODO: send zero response and not consider this as applied? //TODO: send zero response and not consider this as applied?
resp.Success = true resp.Success = true
resp.Message = overlayerr.ErrorMsg() resp.Message = overlayerr.ErrorMsg()
return resp, resource return resp, resource
// rule application failed // rule application failed
case overlayFailure: case overlayFailure:
logger.Info("failed to process overlay") glog.Errorf("Resource %s/%s/%s: failed to process overlay: %v in the rule %s", resource.GetKind(), resource.GetNamespace(), resource.GetName(), overlayerr.ErrorMsg(), ruleName)
resp.Success = false resp.Success = false
resp.Message = fmt.Sprintf("failed to process overlay: %v", overlayerr.ErrorMsg()) resp.Message = fmt.Sprintf("failed to process overlay: %v", overlayerr.ErrorMsg())
return resp, resource return resp, resource
default: default:
logger.Info("failed to process overlay") glog.Errorf("Resource %s/%s/%s: Unknown type of error: %v", resource.GetKind(), resource.GetNamespace(), resource.GetName(), overlayerr.Error())
resp.Success = false resp.Success = false
resp.Message = fmt.Sprintf("Unknown type of error: %v", overlayerr.Error()) resp.Message = fmt.Sprintf("Unknown type of error: %v", overlayerr.Error())
return resp, resource return resp, resource
@ -72,7 +70,7 @@ func ProcessOverlay(log logr.Logger, ruleName string, overlay interface{}, resou
resourceRaw, err := resource.MarshalJSON() resourceRaw, err := resource.MarshalJSON()
if err != nil { if err != nil {
resp.Success = false resp.Success = false
logger.Error(err, "failed to marshal resource") glog.Infof("unable to marshall resource: %v", err)
resp.Message = fmt.Sprintf("failed to process JSON patches: %v", err) resp.Message = fmt.Sprintf("failed to process JSON patches: %v", err)
return resp, resource return resp, resource
} }
@ -81,7 +79,7 @@ func ProcessOverlay(log logr.Logger, ruleName string, overlay interface{}, resou
patchResource, err = utils.ApplyPatches(resourceRaw, patches) patchResource, err = utils.ApplyPatches(resourceRaw, patches)
if err != nil { if err != nil {
msg := fmt.Sprintf("failed to apply JSON patches: %v", err) msg := fmt.Sprintf("failed to apply JSON patches: %v", err)
logger.V(2).Info("applying patches", "patches", string(utils.JoinPatches(patches))) glog.V(2).Infof("%s, patches=%s", msg, string(utils.JoinPatches(patches)))
resp.Success = false resp.Success = false
resp.Message = msg resp.Message = msg
return resp, resource return resp, resource
@ -89,7 +87,7 @@ func ProcessOverlay(log logr.Logger, ruleName string, overlay interface{}, resou
err = patchedResource.UnmarshalJSON(patchResource) err = patchedResource.UnmarshalJSON(patchResource)
if err != nil { if err != nil {
logger.Error(err, "failed to unmarshal resource") glog.Infof("failed to unmarshall resource to undstructured: %v", err)
resp.Success = false resp.Success = false
resp.Message = fmt.Sprintf("failed to process JSON patches: %v", err) resp.Message = fmt.Sprintf("failed to process JSON patches: %v", err)
return resp, resource return resp, resource
@ -103,17 +101,17 @@ func ProcessOverlay(log logr.Logger, ruleName string, overlay interface{}, resou
return resp, patchedResource return resp, patchedResource
} }
func processOverlayPatches(log logr.Logger, resource, overlay interface{}) ([][]byte, overlayError) { func processOverlayPatches(resource, overlay interface{}) ([][]byte, overlayError) {
if path, overlayerr := meetConditions(log, resource, overlay); !reflect.DeepEqual(overlayerr, overlayError{}) { if path, overlayerr := meetConditions(resource, overlay); !reflect.DeepEqual(overlayerr, overlayError{}) {
switch overlayerr.statusCode { switch overlayerr.statusCode {
// anchor key does not exist in the resource, skip applying policy // anchor key does not exist in the resource, skip applying policy
case conditionNotPresent: case conditionNotPresent:
log.V(4).Info("skip applying policy", "path", path, "error", overlayerr) glog.V(4).Infof("Mutate rule: skip applying policy: %v at %s", overlayerr, path)
return nil, newOverlayError(overlayerr.statusCode, fmt.Sprintf("Policy not applied, condition tag not present: %v at %s", overlayerr.ErrorMsg(), path)) return nil, newOverlayError(overlayerr.statusCode, fmt.Sprintf("Policy not applied, condition tag not present: %v at %s", overlayerr.ErrorMsg(), path))
// anchor key is not satisfied in the resource, skip applying policy // anchor key is not satisfied in the resource, skip applying policy
case conditionFailure: case conditionFailure:
// anchor key is not satisfied in the resource, skip applying policy // anchor key is not satisfied in the resource, skip applying policy
log.V(4).Info("failed to validate condition", "path", path, "error", overlayerr) glog.V(4).Infof("Mutate rule: failed to validate condition at %s, err: %v", path, overlayerr)
return nil, newOverlayError(overlayerr.statusCode, fmt.Sprintf("Policy not applied, conditions are not met at %s, %v", path, overlayerr)) return nil, newOverlayError(overlayerr.statusCode, fmt.Sprintf("Policy not applied, conditions are not met at %s, %v", path, overlayerr))
} }
} }
@ -385,7 +383,7 @@ func prepareJSONValue(overlay interface{}) string {
overlayWithoutAnchors := removeAnchorFromSubTree(overlay) overlayWithoutAnchors := removeAnchorFromSubTree(overlay)
jsonOverlay, err := json.Marshal(overlayWithoutAnchors) jsonOverlay, err := json.Marshal(overlayWithoutAnchors)
if err != nil || hasOnlyAnchors(overlay) { if err != nil || hasOnlyAnchors(overlay) {
log.Log.Error(err, "failed to marshall withoutanchors or has only anchors") glog.V(3).Info(err)
return "" return ""
} }
@ -411,7 +409,7 @@ func removeAnchorFromSubTree(overlay interface{}) interface{} {
} }
func removeAnchroFromMap(overlay map[string]interface{}) map[string]interface{} { func removeAnchroFromMap(overlay map[string]interface{}) map[string]interface{} {
result := make(map[string]interface{}) result := make(map[string]interface{}, 0)
for k, v := range overlay { for k, v := range overlay {
result[getRawKeyIfWrappedWithAttributes(k)] = removeAnchorFromSubTree(v) result[getRawKeyIfWrappedWithAttributes(k)] = removeAnchorFromSubTree(v)
} }

View file

@ -5,18 +5,17 @@ import (
"reflect" "reflect"
"strconv" "strconv"
"github.com/go-logr/logr" "github.com/golang/glog"
"github.com/nirmata/kyverno/pkg/engine/anchor" "github.com/nirmata/kyverno/pkg/engine/anchor"
"github.com/nirmata/kyverno/pkg/engine/validate" "github.com/nirmata/kyverno/pkg/engine/validate"
"sigs.k8s.io/controller-runtime/pkg/log"
) )
func meetConditions(log logr.Logger, resource, overlay interface{}) (string, overlayError) { func meetConditions(resource, overlay interface{}) (string, overlayError) {
return checkConditions(log, resource, overlay, "/") return checkConditions(resource, overlay, "/")
} }
// resource and overlay should be the same type // resource and overlay should be the same type
func checkConditions(log logr.Logger, resource, overlay interface{}, path string) (string, overlayError) { func checkConditions(resource, overlay interface{}, path string) (string, overlayError) {
// overlay has no anchor, return true // overlay has no anchor, return true
if !hasNestedAnchors(overlay) { if !hasNestedAnchors(overlay) {
return "", overlayError{} return "", overlayError{}
@ -27,7 +26,7 @@ func checkConditions(log logr.Logger, resource, overlay interface{}, path string
// condition never be true in this case // condition never be true in this case
if reflect.TypeOf(resource) != reflect.TypeOf(overlay) { if reflect.TypeOf(resource) != reflect.TypeOf(overlay) {
if hasNestedAnchors(overlay) { if hasNestedAnchors(overlay) {
log.V(4).Info(fmt.Sprintf("Found anchor on different types of element at path %s: overlay %T, resource %T", path, overlay, resource)) glog.V(4).Infof("Found anchor on different types of element at path %s: overlay %T, resource %T", path, overlay, resource)
return path, newOverlayError(conditionFailure, return path, newOverlayError(conditionFailure,
fmt.Sprintf("Found anchor on different types of element at path %s: overlay %T %v, resource %T %v", path, overlay, overlay, resource, resource)) fmt.Sprintf("Found anchor on different types of element at path %s: overlay %T %v, resource %T %v", path, overlay, overlay, resource, resource))
@ -45,7 +44,7 @@ func checkConditions(log logr.Logger, resource, overlay interface{}, path string
default: default:
// anchor on non map/array is invalid: // anchor on non map/array is invalid:
// - anchor defined on values // - anchor defined on values
log.Info("Found invalid conditional anchor: anchor defined on values") glog.Warningln("Found invalid conditional anchor: anchor defined on values")
return "", overlayError{} return "", overlayError{}
} }
} }
@ -69,12 +68,12 @@ func checkConditionOnMap(resourceMap, overlayMap map[string]interface{}, path st
func checkConditionOnArray(resource, overlay []interface{}, path string) (string, overlayError) { func checkConditionOnArray(resource, overlay []interface{}, path string) (string, overlayError) {
if 0 == len(overlay) { if 0 == len(overlay) {
log.Log.V(4).Info("Mutate overlay pattern is empty", "path", path) glog.Infof("Mutate overlay pattern is empty, path %s", path)
return "", overlayError{} return "", overlayError{}
} }
if reflect.TypeOf(resource[0]) != reflect.TypeOf(overlay[0]) { if reflect.TypeOf(resource[0]) != reflect.TypeOf(overlay[0]) {
log.Log.V(4).Info(fmt.Sprintf("Overlay array and resource array have elements of different types: %T and %T", overlay[0], resource[0])) glog.V(4).Infof("Overlay array and resource array have elements of different types: %T and %T", overlay[0], resource[0])
return path, newOverlayError(conditionFailure, return path, newOverlayError(conditionFailure,
fmt.Sprintf("Overlay array and resource array have elements of different types: %T and %T", overlay[0], resource[0])) fmt.Sprintf("Overlay array and resource array have elements of different types: %T and %T", overlay[0], resource[0]))
} }
@ -112,7 +111,7 @@ func validateConditionAnchorMap(resourceMap, anchors map[string]interface{}, pat
// resource - A: B2 // resource - A: B2
func compareOverlay(resource, overlay interface{}, path string) (string, overlayError) { func compareOverlay(resource, overlay interface{}, path string) (string, overlayError) {
if reflect.TypeOf(resource) != reflect.TypeOf(overlay) { if reflect.TypeOf(resource) != reflect.TypeOf(overlay) {
log.Log.V(4).Info("Found anchor on different types of element: overlay %T, resource %T", overlay, resource) glog.V(4).Infof("Found anchor on different types of element: overlay %T, resource %T", overlay, resource)
return path, newOverlayError(conditionFailure, fmt.Sprintf("Found anchor on different types of element: overlay %T, resource %T", overlay, resource)) return path, newOverlayError(conditionFailure, fmt.Sprintf("Found anchor on different types of element: overlay %T, resource %T", overlay, resource))
} }
@ -140,8 +139,8 @@ func compareOverlay(resource, overlay interface{}, path string) (string, overlay
} }
} }
case string, float64, int, int64, bool, nil: case string, float64, int, int64, bool, nil:
if !validate.ValidateValueWithPattern(log.Log, resource, overlay) { if !validate.ValidateValueWithPattern(resource, overlay) {
log.Log.V(4).Info(fmt.Sprintf("Mutate rule: failed validating value %v with overlay %v", resource, overlay)) glog.V(4).Infof("Mutate rule: failed validating value %v with overlay %v", resource, overlay)
return path, newOverlayError(conditionFailure, fmt.Sprintf("Failed validating value %v with overlay %v", resource, overlay)) return path, newOverlayError(conditionFailure, fmt.Sprintf("Failed validating value %v with overlay %v", resource, overlay))
} }
default: default:
@ -166,7 +165,7 @@ func validateNonAnchorOverlayMap(resourceMap, overlayWithoutAnchor map[string]in
continue continue
} }
} }
if newPath, err := checkConditions(log.Log, resourceValue, overlayValue, curPath); !reflect.DeepEqual(err, overlayError{}) { if newPath, err := checkConditions(resourceValue, overlayValue, curPath); !reflect.DeepEqual(err, overlayError{}) {
return newPath, err return newPath, err
} }
} }
@ -180,7 +179,7 @@ func checkConditionsOnArrayOfSameTypes(resource, overlay []interface{}, path str
default: default:
for i, overlayElement := range overlay { for i, overlayElement := range overlay {
curPath := path + strconv.Itoa(i) + "/" curPath := path + strconv.Itoa(i) + "/"
path, err := checkConditions(log.Log, resource[i], overlayElement, curPath) path, err := checkConditions(resource[i], overlayElement, curPath)
if !reflect.DeepEqual(err, overlayError{}) { if !reflect.DeepEqual(err, overlayError{}) {
return path, err return path, err
} }

View file

@ -7,7 +7,6 @@ import (
"testing" "testing"
"gotest.tools/assert" "gotest.tools/assert"
"sigs.k8s.io/controller-runtime/pkg/log"
) )
func TestMeetConditions_NoAnchor(t *testing.T) { func TestMeetConditions_NoAnchor(t *testing.T) {
@ -27,11 +26,9 @@ func TestMeetConditions_NoAnchor(t *testing.T) {
}`) }`)
var overlay interface{} var overlay interface{}
err := json.Unmarshal(overlayRaw, &overlay) json.Unmarshal(overlayRaw, &overlay)
assert.Assert(t, reflect.DeepEqual(err, nil))
_, err = meetConditions(log.Log, nil, overlay)
_, err := meetConditions(nil, overlay)
assert.Assert(t, reflect.DeepEqual(err, overlayError{})) assert.Assert(t, reflect.DeepEqual(err, overlayError{}))
} }
@ -81,12 +78,10 @@ func TestMeetConditions_conditionalAnchorOnMap(t *testing.T) {
var resource, overlay interface{} var resource, overlay interface{}
err := json.Unmarshal(resourceRaw, &resource) json.Unmarshal(resourceRaw, &resource)
assert.NilError(t, err) json.Unmarshal(overlayRaw, &overlay)
err = json.Unmarshal(overlayRaw, &overlay)
assert.NilError(t, err)
_, err = meetConditions(log.Log, resource, overlay) _, err := meetConditions(resource, overlay)
assert.Assert(t, !reflect.DeepEqual(err, overlayError{})) assert.Assert(t, !reflect.DeepEqual(err, overlayError{}))
overlayRaw = []byte(` overlayRaw = []byte(`
@ -104,10 +99,9 @@ func TestMeetConditions_conditionalAnchorOnMap(t *testing.T) {
] ]
}`) }`)
err = json.Unmarshal(overlayRaw, &overlay) json.Unmarshal(overlayRaw, &overlay)
assert.NilError(t, err)
_, overlayerr := meetConditions(log.Log, resource, overlay) _, overlayerr := meetConditions(resource, overlay)
assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{})) assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{}))
} }
@ -142,14 +136,11 @@ func TestMeetConditions_DifferentTypes(t *testing.T) {
}`) }`)
var resource, overlay interface{} var resource, overlay interface{}
err := json.Unmarshal(resourceRaw, &resource) json.Unmarshal(resourceRaw, &resource)
assert.NilError(t, err) json.Unmarshal(overlayRaw, &overlay)
err = json.Unmarshal(overlayRaw, &overlay)
assert.NilError(t, err)
// anchor exist // anchor exist
_, err := meetConditions(resource, overlay)
_, err = meetConditions(log.Log, resource, overlay)
assert.Assert(t, strings.Contains(err.Error(), "Found anchor on different types of element at path /subsets/")) assert.Assert(t, strings.Contains(err.Error(), "Found anchor on different types of element at path /subsets/"))
} }
@ -199,12 +190,10 @@ func TestMeetConditions_anchosInSameObject(t *testing.T) {
var resource, overlay interface{} var resource, overlay interface{}
err := json.Unmarshal(resourceRaw, &resource) json.Unmarshal(resourceRaw, &resource)
assert.NilError(t, err) json.Unmarshal(overlayRaw, &overlay)
err = json.Unmarshal(overlayRaw, &overlay)
assert.NilError(t, err)
_, err = meetConditions(log.Log, resource, overlay) _, err := meetConditions(resource, overlay)
assert.Error(t, err, "[overlayError:0] Failed validating value 443 with overlay 444") assert.Error(t, err, "[overlayError:0] Failed validating value 443 with overlay 444")
} }
@ -259,13 +248,10 @@ func TestMeetConditions_anchorOnPeer(t *testing.T) {
var resource, overlay interface{} var resource, overlay interface{}
err := json.Unmarshal(resourceRaw, &resource) json.Unmarshal(resourceRaw, &resource)
assert.NilError(t, err) json.Unmarshal(overlayRaw, &overlay)
err = json.Unmarshal(overlayRaw, &overlay)
assert.NilError(t, err)
_, err = meetConditions(log.Log, resource, overlay)
_, err := meetConditions(resource, overlay)
assert.Assert(t, reflect.DeepEqual(err, overlayError{})) assert.Assert(t, reflect.DeepEqual(err, overlayError{}))
} }
@ -339,13 +325,10 @@ func TestMeetConditions_anchorsOnMetaAndSpec(t *testing.T) {
var resource, overlay interface{} var resource, overlay interface{}
err := json.Unmarshal(resourceRaw, &resource) json.Unmarshal(resourceRaw, &resource)
assert.NilError(t, err) json.Unmarshal(overlayRaw, &overlay)
err = json.Unmarshal(overlayRaw, &overlay)
assert.NilError(t, err)
_, err = meetConditions(log.Log, resource, overlay)
_, err := meetConditions(resource, overlay)
assert.Assert(t, reflect.DeepEqual(err, overlayError{})) assert.Assert(t, reflect.DeepEqual(err, overlayError{}))
} }
@ -423,13 +406,10 @@ func TestMeetConditions_anchorsOnPeer_single(t *testing.T) {
var resource, overlay interface{} var resource, overlay interface{}
err := json.Unmarshal(resourceRawAnchorOnPeers, &resource) json.Unmarshal(resourceRawAnchorOnPeers, &resource)
assert.NilError(t, err) json.Unmarshal(overlayRaw, &overlay)
err = json.Unmarshal(overlayRaw, &overlay)
assert.NilError(t, err)
_, err = meetConditions(log.Log, resource, overlay)
_, err := meetConditions(resource, overlay)
assert.Assert(t, reflect.DeepEqual(err, overlayError{})) assert.Assert(t, reflect.DeepEqual(err, overlayError{}))
} }
@ -460,13 +440,10 @@ func TestMeetConditions_anchorsOnPeer_two(t *testing.T) {
var resource, overlay interface{} var resource, overlay interface{}
err := json.Unmarshal(resourceRawAnchorOnPeers, &resource) json.Unmarshal(resourceRawAnchorOnPeers, &resource)
assert.NilError(t, err) json.Unmarshal(overlayRaw, &overlay)
err = json.Unmarshal(overlayRaw, &overlay)
assert.NilError(t, err)
_, err = meetConditions(log.Log, resource, overlay)
_, err := meetConditions(resource, overlay)
assert.Error(t, err, "[overlayError:0] Failed validating value true with overlay false") assert.Error(t, err, "[overlayError:0] Failed validating value true with overlay false")
overlayRaw = []byte(`{ overlayRaw = []byte(`{
@ -493,10 +470,9 @@ func TestMeetConditions_anchorsOnPeer_two(t *testing.T) {
} }
}`) }`)
err = json.Unmarshal(overlayRaw, &overlay) json.Unmarshal(overlayRaw, &overlay)
assert.NilError(t, err)
_, err = meetConditions(log.Log, resource, overlay) _, err = meetConditions(resource, overlay)
assert.Assert(t, reflect.DeepEqual(err, overlayError{})) assert.Assert(t, reflect.DeepEqual(err, overlayError{}))
overlayRaw = []byte(`{ overlayRaw = []byte(`{
@ -523,10 +499,9 @@ func TestMeetConditions_anchorsOnPeer_two(t *testing.T) {
} }
}`) }`)
err = json.Unmarshal(overlayRaw, &overlay) json.Unmarshal(overlayRaw, &overlay)
assert.NilError(t, err)
_, err = meetConditions(log.Log, resource, overlay) _, err = meetConditions(resource, overlay)
assert.Assert(t, reflect.DeepEqual(err, overlayError{})) assert.Assert(t, reflect.DeepEqual(err, overlayError{}))
} }
@ -557,13 +532,10 @@ func TestMeetConditions_anchorsOnPeer_multiple(t *testing.T) {
var resource, overlay interface{} var resource, overlay interface{}
err := json.Unmarshal(resourceRawAnchorOnPeers, &resource) json.Unmarshal(resourceRawAnchorOnPeers, &resource)
assert.NilError(t, err) json.Unmarshal(overlayRaw, &overlay)
err = json.Unmarshal(overlayRaw, &overlay)
assert.NilError(t, err)
_, err = meetConditions(log.Log, resource, overlay)
_, err := meetConditions(resource, overlay)
assert.Assert(t, reflect.DeepEqual(err, overlayError{})) assert.Assert(t, reflect.DeepEqual(err, overlayError{}))
overlayRaw = []byte(`{ overlayRaw = []byte(`{
@ -590,10 +562,9 @@ func TestMeetConditions_anchorsOnPeer_multiple(t *testing.T) {
} }
}`) }`)
err = json.Unmarshal(overlayRaw, &overlay) json.Unmarshal(overlayRaw, &overlay)
assert.NilError(t, err)
_, err = meetConditions(log.Log, resource, overlay) _, err = meetConditions(resource, overlay)
assert.Assert(t, reflect.DeepEqual(err, overlayError{})) assert.Assert(t, reflect.DeepEqual(err, overlayError{}))
overlayRaw = []byte(`{ overlayRaw = []byte(`{
@ -620,10 +591,9 @@ func TestMeetConditions_anchorsOnPeer_multiple(t *testing.T) {
} }
}`) }`)
err = json.Unmarshal(overlayRaw, &overlay) json.Unmarshal(overlayRaw, &overlay)
assert.NilError(t, err)
_, err = meetConditions(log.Log, resource, overlay) _, err = meetConditions(resource, overlay)
assert.Error(t, err, "[overlayError:0] Failed validating value ENV_VALUE with overlay ENV_VALUE1") assert.Error(t, err, "[overlayError:0] Failed validating value ENV_VALUE with overlay ENV_VALUE1")
} }
@ -679,13 +649,10 @@ func TestMeetConditions_AtleastOneExist(t *testing.T) {
var resource, overlay interface{} var resource, overlay interface{}
err := json.Unmarshal(resourceRaw, &resource) json.Unmarshal(resourceRaw, &resource)
assert.NilError(t, err) json.Unmarshal(overlayRaw, &overlay)
err = json.Unmarshal(overlayRaw, &overlay)
assert.NilError(t, err)
path, err := meetConditions(log.Log, resource, overlay)
path, err := meetConditions(resource, overlay)
assert.Assert(t, reflect.DeepEqual(err, overlayError{})) assert.Assert(t, reflect.DeepEqual(err, overlayError{}))
assert.Assert(t, len(path) == 0) assert.Assert(t, len(path) == 0)
} }

View file

@ -8,7 +8,6 @@ import (
jsonpatch "github.com/evanphx/json-patch" jsonpatch "github.com/evanphx/json-patch"
"github.com/nirmata/kyverno/pkg/engine/utils" "github.com/nirmata/kyverno/pkg/engine/utils"
"gotest.tools/assert" "gotest.tools/assert"
"sigs.k8s.io/controller-runtime/pkg/log"
) )
func compareJSONAsMap(t *testing.T, expected, actual []byte) { func compareJSONAsMap(t *testing.T, expected, actual []byte) {
@ -64,12 +63,10 @@ func TestProcessOverlayPatches_NestedListWithAnchor(t *testing.T) {
var resource, overlay interface{} var resource, overlay interface{}
err := json.Unmarshal(resourceRaw, &resource) json.Unmarshal(resourceRaw, &resource)
assert.NilError(t, err) json.Unmarshal(overlayRaw, &overlay)
err = json.Unmarshal(overlayRaw, &overlay)
assert.NilError(t, err)
patches, overlayerr := processOverlayPatches(log.Log, resource, overlay) patches, overlayerr := processOverlayPatches(resource, overlay)
assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{})) assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{}))
assert.Assert(t, patches != nil) assert.Assert(t, patches != nil)
@ -166,12 +163,10 @@ func TestProcessOverlayPatches_InsertIntoArray(t *testing.T) {
var resource, overlay interface{} var resource, overlay interface{}
err := json.Unmarshal(resourceRaw, &resource) json.Unmarshal(resourceRaw, &resource)
assert.NilError(t, err) json.Unmarshal(overlayRaw, &overlay)
err = json.Unmarshal(overlayRaw, &overlay)
assert.NilError(t, err)
patches, overlayerr := processOverlayPatches(log.Log, resource, overlay) patches, overlayerr := processOverlayPatches(resource, overlay)
assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{})) assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{}))
assert.Assert(t, patches != nil) assert.Assert(t, patches != nil)
@ -289,12 +284,10 @@ func TestProcessOverlayPatches_TestInsertToArray(t *testing.T) {
var resource, overlay interface{} var resource, overlay interface{}
err := json.Unmarshal(resourceRaw, &resource) json.Unmarshal(resourceRaw, &resource)
assert.NilError(t, err) json.Unmarshal(overlayRaw, &overlay)
err = json.Unmarshal(overlayRaw, &overlay)
assert.NilError(t, err)
patches, overlayerr := processOverlayPatches(log.Log, resource, overlay) patches, overlayerr := processOverlayPatches(resource, overlay)
assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{})) assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{}))
assert.Assert(t, patches != nil) assert.Assert(t, patches != nil)
@ -374,12 +367,10 @@ func TestProcessOverlayPatches_ImagePullPolicy(t *testing.T) {
var resource, overlay interface{} var resource, overlay interface{}
err := json.Unmarshal(resourceRaw, &resource) json.Unmarshal(resourceRaw, &resource)
assert.NilError(t, err) json.Unmarshal(overlayRaw, &overlay)
err = json.Unmarshal(overlayRaw, &overlay)
assert.NilError(t, err)
patches, overlayerr := processOverlayPatches(log.Log, resource, overlay) patches, overlayerr := processOverlayPatches(resource, overlay)
assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{})) assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{}))
assert.Assert(t, len(patches) != 0) assert.Assert(t, len(patches) != 0)
@ -465,10 +456,9 @@ func TestProcessOverlayPatches_ImagePullPolicy(t *testing.T) {
} }
}`) }`)
err = json.Unmarshal(overlayRaw, &overlay) json.Unmarshal(overlayRaw, &overlay)
assert.NilError(t, err)
patches, err = processOverlayPatches(log.Log, resource, overlay) patches, err = processOverlayPatches(resource, overlay)
assert.Assert(t, reflect.DeepEqual(err, overlayError{})) assert.Assert(t, reflect.DeepEqual(err, overlayError{}))
assert.Assert(t, len(patches) != 0) assert.Assert(t, len(patches) != 0)
@ -502,10 +492,9 @@ func TestProcessOverlayPatches_ImagePullPolicy(t *testing.T) {
} }
}`) }`)
err = json.Unmarshal(overlayRaw, &overlay) json.Unmarshal(overlayRaw, &overlay)
assert.NilError(t, err)
patches, err = processOverlayPatches(log.Log, resource, overlay) patches, err = processOverlayPatches(resource, overlay)
assert.Error(t, err, "[overlayError:0] Policy not applied, conditions are not met at /spec/template/metadata/labels/app/, [overlayError:0] Failed validating value nginx with overlay nginx1") assert.Error(t, err, "[overlayError:0] Policy not applied, conditions are not met at /spec/template/metadata/labels/app/, [overlayError:0] Failed validating value nginx with overlay nginx1")
assert.Assert(t, len(patches) == 0) assert.Assert(t, len(patches) == 0)
} }
@ -531,12 +520,10 @@ func TestProcessOverlayPatches_AddingAnchor(t *testing.T) {
var resource, overlay interface{} var resource, overlay interface{}
err := json.Unmarshal(resourceRaw, &resource) json.Unmarshal(resourceRaw, &resource)
assert.NilError(t, err) json.Unmarshal(overlayRaw, &overlay)
err = json.Unmarshal(overlayRaw, &overlay)
assert.NilError(t, err)
patches, overlayerr := processOverlayPatches(log.Log, resource, overlay) patches, overlayerr := processOverlayPatches(resource, overlay)
assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{})) assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{}))
assert.Assert(t, len(patches) != 0) assert.Assert(t, len(patches) != 0)
@ -618,12 +605,10 @@ func TestProcessOverlayPatches_AddingAnchorInsideListElement(t *testing.T) {
var resource, overlay interface{} var resource, overlay interface{}
err := json.Unmarshal(resourceRaw, &resource) json.Unmarshal(resourceRaw, &resource)
assert.NilError(t, err) json.Unmarshal(overlayRaw, &overlay)
err = json.Unmarshal(overlayRaw, &overlay)
assert.NilError(t, err)
patches, overlayerr := processOverlayPatches(log.Log, resource, overlay) patches, overlayerr := processOverlayPatches(resource, overlay)
assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{})) assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{}))
assert.Assert(t, len(patches) != 0) assert.Assert(t, len(patches) != 0)
@ -699,10 +684,9 @@ func TestProcessOverlayPatches_AddingAnchorInsideListElement(t *testing.T) {
} }
}`) }`)
err = json.Unmarshal(overlayRaw, &overlay) json.Unmarshal(overlayRaw, &overlay)
assert.NilError(t, err)
patches, err = processOverlayPatches(log.Log, resource, overlay) patches, err = processOverlayPatches(resource, overlay)
assert.Assert(t, reflect.DeepEqual(err, overlayError{})) assert.Assert(t, reflect.DeepEqual(err, overlayError{}))
assert.Assert(t, len(patches) != 0) assert.Assert(t, len(patches) != 0)
@ -763,12 +747,10 @@ func TestProcessOverlayPatches_anchorOnPeer(t *testing.T) {
var resource, overlay interface{} var resource, overlay interface{}
err := json.Unmarshal(resourceRaw, &resource) json.Unmarshal(resourceRaw, &resource)
assert.NilError(t, err) json.Unmarshal(overlayRaw, &overlay)
err = json.Unmarshal(overlayRaw, &overlay)
assert.NilError(t, err)
patches, overlayerr := processOverlayPatches(log.Log, resource, overlay) patches, overlayerr := processOverlayPatches(resource, overlay)
assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{})) assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{}))
assert.Assert(t, len(patches) != 0) assert.Assert(t, len(patches) != 0)
@ -823,10 +805,9 @@ func TestProcessOverlayPatches_anchorOnPeer(t *testing.T) {
] ]
}`) }`)
err = json.Unmarshal(overlayRaw, &overlay) json.Unmarshal(overlayRaw, &overlay)
assert.NilError(t, err)
patches, err = processOverlayPatches(log.Log, resource, overlay) patches, err = processOverlayPatches(resource, overlay)
assert.Error(t, err, "[overlayError:0] Policy not applied, conditions are not met at /subsets/0/ports/0/port/, [overlayError:0] Failed validating value 443 with overlay 444") assert.Error(t, err, "[overlayError:0] Policy not applied, conditions are not met at /subsets/0/ports/0/port/, [overlayError:0] Failed validating value 443 with overlay 444")
assert.Assert(t, len(patches) == 0) assert.Assert(t, len(patches) == 0)
} }
@ -905,12 +886,10 @@ func TestProcessOverlayPatches_insertWithCondition(t *testing.T) {
var resource, overlay interface{} var resource, overlay interface{}
err := json.Unmarshal(resourceRaw, &resource) json.Unmarshal(resourceRaw, &resource)
assert.NilError(t, err) json.Unmarshal(overlayRaw, &overlay)
err = json.Unmarshal(overlayRaw, &overlay)
assert.NilError(t, err)
patches, overlayerr := processOverlayPatches(log.Log, resource, overlay) patches, overlayerr := processOverlayPatches(resource, overlay)
assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{})) assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{}))
assert.Assert(t, len(patches) != 0) assert.Assert(t, len(patches) != 0)
@ -1018,12 +997,10 @@ func TestProcessOverlayPatches_InsertIfNotPresentWithConditions(t *testing.T) {
var resource, overlay interface{} var resource, overlay interface{}
err := json.Unmarshal(resourceRaw, &resource) json.Unmarshal(resourceRaw, &resource)
assert.NilError(t, err) json.Unmarshal(overlayRaw, &overlay)
err = json.Unmarshal(overlayRaw, &overlay)
assert.NilError(t, err)
patches, overlayerr := processOverlayPatches(log.Log, resource, overlay) patches, overlayerr := processOverlayPatches(resource, overlay)
assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{})) assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{}))
assert.Assert(t, len(patches) != 0) assert.Assert(t, len(patches) != 0)

View file

@ -6,7 +6,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/go-logr/logr" "github.com/golang/glog"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1" kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
"github.com/nirmata/kyverno/pkg/engine/response" "github.com/nirmata/kyverno/pkg/engine/response"
"github.com/nirmata/kyverno/pkg/engine/utils" "github.com/nirmata/kyverno/pkg/engine/utils"
@ -20,22 +20,21 @@ func applyPatch(resource []byte, patchRaw []byte) ([]byte, error) {
} }
//ProcessPatches applies the patches on the resource and returns the patched resource //ProcessPatches applies the patches on the resource and returns the patched resource
func ProcessPatches(log logr.Logger, rule kyverno.Rule, resource unstructured.Unstructured) (resp response.RuleResponse, patchedResource unstructured.Unstructured) { func ProcessPatches(rule kyverno.Rule, resource unstructured.Unstructured) (resp response.RuleResponse, patchedResource unstructured.Unstructured) {
logger := log.WithValues("rule", rule.Name)
startTime := time.Now() startTime := time.Now()
logger.V(4).Info("started JSON patch", "startTime", startTime) glog.V(4).Infof("started JSON patch rule %q (%v)", rule.Name, startTime)
resp.Name = rule.Name resp.Name = rule.Name
resp.Type = utils.Mutation.String() resp.Type = utils.Mutation.String()
defer func() { defer func() {
resp.RuleStats.ProcessingTime = time.Since(startTime) resp.RuleStats.ProcessingTime = time.Since(startTime)
logger.V(4).Info("finished JSON patch", "processingTime", resp.RuleStats.ProcessingTime) glog.V(4).Infof("finished JSON patch rule %q (%v)", resp.Name, resp.RuleStats.ProcessingTime)
}() }()
// convert to RAW // convert to RAW
resourceRaw, err := resource.MarshalJSON() resourceRaw, err := resource.MarshalJSON()
if err != nil { if err != nil {
resp.Success = false resp.Success = false
logger.Error(err, "failed to marshal resource") glog.Infof("unable to marshall resource: %v", err)
resp.Message = fmt.Sprintf("failed to process JSON patches: %v", err) resp.Message = fmt.Sprintf("failed to process JSON patches: %v", err)
return resp, resource return resp, resource
} }
@ -46,14 +45,14 @@ func ProcessPatches(log logr.Logger, rule kyverno.Rule, resource unstructured.Un
// JSON patch // JSON patch
patchRaw, err := json.Marshal(patch) patchRaw, err := json.Marshal(patch)
if err != nil { if err != nil {
logger.Error(err, "failed to marshal JSON patch") glog.V(4).Infof("failed to marshall JSON patch %v: %v", patch, err)
errs = append(errs, err) errs = append(errs, err)
continue continue
} }
patchResource, err := applyPatch(resourceRaw, patchRaw) patchResource, err := applyPatch(resourceRaw, patchRaw)
// TODO: continue on error if one of the patches fails, will add the failure event in such case // TODO: continue on error if one of the patches fails, will add the failure event in such case
if err != nil && patch.Operation == "remove" { if err != nil && patch.Operation == "remove" {
log.Error(err, "failed to process JSON path or patch is a 'remove' operation") glog.Info(err)
continue continue
} }
if err != nil { if err != nil {
@ -78,7 +77,7 @@ func ProcessPatches(log logr.Logger, rule kyverno.Rule, resource unstructured.Un
} }
err = patchedResource.UnmarshalJSON(resourceRaw) err = patchedResource.UnmarshalJSON(resourceRaw)
if err != nil { if err != nil {
logger.Error(err, "failed to unmmarshal resource") glog.Infof("failed to unmarshall resource to undstructured: %v", err)
resp.Success = false resp.Success = false
resp.Message = fmt.Sprintf("failed to process JSON patches: %v", err) resp.Message = fmt.Sprintf("failed to process JSON patches: %v", err)
return resp, resource return resp, resource

View file

@ -5,7 +5,6 @@ import (
"gotest.tools/assert" "gotest.tools/assert"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"sigs.k8s.io/controller-runtime/pkg/log"
types "github.com/nirmata/kyverno/pkg/api/kyverno/v1" types "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
"github.com/nirmata/kyverno/pkg/engine/utils" "github.com/nirmata/kyverno/pkg/engine/utils"
@ -42,7 +41,7 @@ func TestProcessPatches_EmptyPatches(t *testing.T) {
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
rr, _ := ProcessPatches(log.Log, emptyRule, *resourceUnstructured) rr, _ := ProcessPatches(emptyRule, *resourceUnstructured)
assert.Check(t, rr.Success) assert.Check(t, rr.Success)
assert.Assert(t, len(rr.Patches) == 0) assert.Assert(t, len(rr.Patches) == 0)
} }
@ -71,14 +70,14 @@ func makeRuleWithPatches(patches []types.Patch) types.Rule {
func TestProcessPatches_EmptyDocument(t *testing.T) { func TestProcessPatches_EmptyDocument(t *testing.T) {
rule := makeRuleWithPatch(makeAddIsMutatedLabelPatch()) rule := makeRuleWithPatch(makeAddIsMutatedLabelPatch())
rr, _ := ProcessPatches(log.Log, rule, unstructured.Unstructured{}) rr, _ := ProcessPatches(rule, unstructured.Unstructured{})
assert.Assert(t, !rr.Success) assert.Assert(t, !rr.Success)
assert.Assert(t, len(rr.Patches) == 0) assert.Assert(t, len(rr.Patches) == 0)
} }
func TestProcessPatches_AllEmpty(t *testing.T) { func TestProcessPatches_AllEmpty(t *testing.T) {
emptyRule := types.Rule{} emptyRule := types.Rule{}
rr, _ := ProcessPatches(log.Log, emptyRule, unstructured.Unstructured{}) rr, _ := ProcessPatches(emptyRule, unstructured.Unstructured{})
assert.Check(t, !rr.Success) assert.Check(t, !rr.Success)
assert.Assert(t, len(rr.Patches) == 0) assert.Assert(t, len(rr.Patches) == 0)
} }
@ -91,7 +90,7 @@ func TestProcessPatches_AddPathDoesntExist(t *testing.T) {
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
rr, _ := ProcessPatches(log.Log, rule, *resourceUnstructured) rr, _ := ProcessPatches(rule, *resourceUnstructured)
assert.Check(t, !rr.Success) assert.Check(t, !rr.Success)
assert.Assert(t, len(rr.Patches) == 0) assert.Assert(t, len(rr.Patches) == 0)
} }
@ -103,7 +102,7 @@ func TestProcessPatches_RemovePathDoesntExist(t *testing.T) {
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
rr, _ := ProcessPatches(log.Log, rule, *resourceUnstructured) rr, _ := ProcessPatches(rule, *resourceUnstructured)
assert.Check(t, rr.Success) assert.Check(t, rr.Success)
assert.Assert(t, len(rr.Patches) == 0) assert.Assert(t, len(rr.Patches) == 0)
} }
@ -116,7 +115,7 @@ func TestProcessPatches_AddAndRemovePathsDontExist_EmptyResult(t *testing.T) {
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
rr, _ := ProcessPatches(log.Log, rule, *resourceUnstructured) rr, _ := ProcessPatches(rule, *resourceUnstructured)
assert.Check(t, !rr.Success) assert.Check(t, !rr.Success)
assert.Assert(t, len(rr.Patches) == 0) assert.Assert(t, len(rr.Patches) == 0)
} }
@ -130,7 +129,7 @@ func TestProcessPatches_AddAndRemovePathsDontExist_ContinueOnError_NotEmptyResul
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
rr, _ := ProcessPatches(log.Log, rule, *resourceUnstructured) rr, _ := ProcessPatches(rule, *resourceUnstructured)
assert.Check(t, rr.Success) assert.Check(t, rr.Success)
assert.Assert(t, len(rr.Patches) != 0) assert.Assert(t, len(rr.Patches) != 0)
assertEqStringAndData(t, `{"path":"/metadata/labels/label3","op":"add","value":"label3Value"}`, rr.Patches[0]) assertEqStringAndData(t, `{"path":"/metadata/labels/label3","op":"add","value":"label3Value"}`, rr.Patches[0])
@ -143,7 +142,7 @@ func TestProcessPatches_RemovePathDoesntExist_EmptyResult(t *testing.T) {
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
rr, _ := ProcessPatches(log.Log, rule, *resourceUnstructured) rr, _ := ProcessPatches(rule, *resourceUnstructured)
assert.Check(t, rr.Success) assert.Check(t, rr.Success)
assert.Assert(t, len(rr.Patches) == 0) assert.Assert(t, len(rr.Patches) == 0)
} }
@ -156,7 +155,7 @@ func TestProcessPatches_RemovePathDoesntExist_NotEmptyResult(t *testing.T) {
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
rr, _ := ProcessPatches(log.Log, rule, *resourceUnstructured) rr, _ := ProcessPatches(rule, *resourceUnstructured)
assert.Check(t, rr.Success) assert.Check(t, rr.Success)
assert.Assert(t, len(rr.Patches) == 1) assert.Assert(t, len(rr.Patches) == 1)
assertEqStringAndData(t, `{"path":"/metadata/labels/label2","op":"add","value":"label2Value"}`, rr.Patches[0]) assertEqStringAndData(t, `{"path":"/metadata/labels/label2","op":"add","value":"label2Value"}`, rr.Patches[0])

View file

@ -5,13 +5,12 @@ import (
"strings" "strings"
"time" "time"
"github.com/go-logr/logr" "github.com/golang/glog"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1" kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
"github.com/nirmata/kyverno/pkg/engine/mutate" "github.com/nirmata/kyverno/pkg/engine/mutate"
"github.com/nirmata/kyverno/pkg/engine/response" "github.com/nirmata/kyverno/pkg/engine/response"
"github.com/nirmata/kyverno/pkg/engine/variables" "github.com/nirmata/kyverno/pkg/engine/variables"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"sigs.k8s.io/controller-runtime/pkg/log"
) )
const ( const (
@ -29,25 +28,26 @@ func Mutate(policyContext PolicyContext) (resp response.EngineResponse) {
policy := policyContext.Policy policy := policyContext.Policy
resource := policyContext.NewResource resource := policyContext.NewResource
ctx := policyContext.Context ctx := policyContext.Context
logger := log.Log.WithName("Mutate").WithValues("policy", policy.Name, "kind", resource.GetKind(), "namespace", resource.GetNamespace(), "name", resource.GetName())
logger.V(4).Info("start processing", "startTime", startTime)
startMutateResultResponse(&resp, policy, resource) startMutateResultResponse(&resp, policy, resource)
defer endMutateResultResponse(logger, &resp, startTime) glog.V(4).Infof("started applying mutation rules of policy %q (%v)", policy.Name, startTime)
defer endMutateResultResponse(&resp, startTime)
patchedResource := policyContext.NewResource patchedResource := policyContext.NewResource
for _, rule := range policy.Spec.Rules { for _, rule := range policy.Spec.Rules {
var ruleResponse response.RuleResponse var ruleResponse response.RuleResponse
logger := logger.WithValues("rule", rule.Name)
//TODO: to be checked before calling the resources as well //TODO: to be checked before calling the resources as well
if !rule.HasMutate() && !strings.Contains(PodControllers, resource.GetKind()) { if !rule.HasMutate() && !strings.Contains(PodControllers, resource.GetKind()) {
continue continue
} }
startTime := time.Now()
glog.V(4).Infof("Time: Mutate matchAdmissionInfo %v", time.Since(startTime))
// check if the resource satisfies the filter conditions defined in the rule // check if the resource satisfies the filter conditions defined in the rule
//TODO: this needs to be extracted, to filter the resource so that we can avoid passing resources that //TODO: this needs to be extracted, to filter the resource so that we can avoid passing resources that
// dont statisfy a policy rule resource description // dont statisfy a policy rule resource description
if err := MatchesResourceDescription(resource, rule, policyContext.AdmissionInfo); err != nil { if err := MatchesResourceDescription(resource, rule, policyContext.AdmissionInfo); err != nil {
logger.V(4).Info("resource fails the match description") glog.V(4).Infof("resource %s/%s does not satisfy the resource description for the rule:\n%s", resource.GetNamespace(), resource.GetName(), err.Error())
continue continue
} }
@ -55,8 +55,8 @@ func Mutate(policyContext PolicyContext) (resp response.EngineResponse) {
copyConditions := copyConditions(rule.Conditions) copyConditions := copyConditions(rule.Conditions)
// evaluate pre-conditions // evaluate pre-conditions
// - handle variable subsitutions // - handle variable subsitutions
if !variables.EvaluateConditions(logger, ctx, copyConditions) { if !variables.EvaluateConditions(ctx, copyConditions) {
logger.V(4).Info("resource fails the preconditions") glog.V(4).Infof("resource %s/%s does not satisfy the conditions for the rule ", resource.GetNamespace(), resource.GetName())
continue continue
} }
@ -66,7 +66,7 @@ func Mutate(policyContext PolicyContext) (resp response.EngineResponse) {
overlay := mutation.Overlay overlay := mutation.Overlay
// subsiitue the variables // subsiitue the variables
var err error var err error
if overlay, err = variables.SubstituteVars(logger, ctx, overlay); err != nil { if overlay, err = variables.SubstituteVars(ctx, overlay); err != nil {
// variable subsitution failed // variable subsitution failed
ruleResponse.Success = false ruleResponse.Success = false
ruleResponse.Message = err.Error() ruleResponse.Message = err.Error()
@ -74,13 +74,15 @@ func Mutate(policyContext PolicyContext) (resp response.EngineResponse) {
continue continue
} }
ruleResponse, patchedResource = mutate.ProcessOverlay(logger, rule.Name, overlay, patchedResource) ruleResponse, patchedResource = mutate.ProcessOverlay(rule.Name, overlay, patchedResource)
if ruleResponse.Success { if ruleResponse.Success {
// - overlay pattern does not match the resource conditions // - overlay pattern does not match the resource conditions
if ruleResponse.Patches == nil { if ruleResponse.Patches == nil {
glog.V(4).Infof(ruleResponse.Message)
continue continue
} }
logger.V(4).Info("overlay applied succesfully")
glog.V(4).Infof("Mutate overlay in rule '%s' successfully applied on %s/%s/%s", rule.Name, resource.GetKind(), resource.GetNamespace(), resource.GetName())
} }
resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, ruleResponse) resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, ruleResponse)
@ -90,8 +92,8 @@ func Mutate(policyContext PolicyContext) (resp response.EngineResponse) {
// Process Patches // Process Patches
if rule.Mutation.Patches != nil { if rule.Mutation.Patches != nil {
var ruleResponse response.RuleResponse var ruleResponse response.RuleResponse
ruleResponse, patchedResource = mutate.ProcessPatches(logger, rule, patchedResource) ruleResponse, patchedResource = mutate.ProcessPatches(rule, patchedResource)
logger.V(4).Info("patches applied successfully") glog.Infof("Mutate patches in rule '%s' successfully applied on %s/%s/%s", rule.Name, resource.GetKind(), resource.GetNamespace(), resource.GetName())
resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, ruleResponse) resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, ruleResponse)
incrementAppliedRuleCount(&resp) incrementAppliedRuleCount(&resp)
} }
@ -104,14 +106,14 @@ func Mutate(policyContext PolicyContext) (resp response.EngineResponse) {
if strings.Contains(PodControllers, resource.GetKind()) { if strings.Contains(PodControllers, resource.GetKind()) {
var ruleResponse response.RuleResponse var ruleResponse response.RuleResponse
ruleResponse, patchedResource = mutate.ProcessOverlay(logger, rule.Name, podTemplateRule, patchedResource) ruleResponse, patchedResource = mutate.ProcessOverlay(rule.Name, podTemplateRule, patchedResource)
if !ruleResponse.Success { if !ruleResponse.Success {
logger.Info("failed to insert annotation for podTemplate", "error", ruleResponse.Message) glog.Errorf("Failed to insert annotation to podTemplate of %s/%s/%s: %s", resource.GetKind(), resource.GetNamespace(), resource.GetName(), ruleResponse.Message)
continue continue
} }
if ruleResponse.Success && ruleResponse.Patches != nil { if ruleResponse.Success && ruleResponse.Patches != nil {
logger.V(2).Info("inserted annotation for podTemplate") glog.V(2).Infof("Inserted annotation to podTemplate of %s/%s/%s: %s", resource.GetKind(), resource.GetNamespace(), resource.GetName(), ruleResponse.Message)
resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, ruleResponse) resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, ruleResponse)
} }
} }
@ -135,9 +137,10 @@ func startMutateResultResponse(resp *response.EngineResponse, policy kyverno.Clu
// TODO(shuting): set response with mutationFailureAction // TODO(shuting): set response with mutationFailureAction
} }
func endMutateResultResponse(logger logr.Logger, resp *response.EngineResponse, startTime time.Time) { func endMutateResultResponse(resp *response.EngineResponse, startTime time.Time) {
resp.PolicyResponse.ProcessingTime = time.Since(startTime) resp.PolicyResponse.ProcessingTime = time.Since(startTime)
logger.V(4).Info("finshed processing", "processingTime", resp.PolicyResponse.ProcessingTime, "mutationRulesApplied", resp.PolicyResponse.RulesAppliedCount) glog.V(4).Infof("finished applying mutation rules policy %v (%v)", resp.PolicyResponse.Policy, resp.PolicyResponse.ProcessingTime)
glog.V(4).Infof("Mutation Rules appplied count %v for policy %q", resp.PolicyResponse.RulesAppliedCount, resp.PolicyResponse.Policy)
} }
// podTemplateRule mutate pod template with annotation // podTemplateRule mutate pod template with annotation

View file

@ -67,17 +67,11 @@ func Test_VariableSubstitutionOverlay(t *testing.T) {
expectedPatch := []byte(`{ "op": "add", "path": "/metadata/labels", "value":{"appname":"check-root-user"} }`) expectedPatch := []byte(`{ "op": "add", "path": "/metadata/labels", "value":{"appname":"check-root-user"} }`)
var policy kyverno.ClusterPolicy var policy kyverno.ClusterPolicy
err := json.Unmarshal(rawPolicy, &policy) json.Unmarshal(rawPolicy, &policy)
if err != nil {
t.Error(err)
}
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource) resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err) assert.NilError(t, err)
ctx := context.NewContext() ctx := context.NewContext()
err = ctx.AddResource(rawResource) ctx.AddResource(rawResource)
if err != nil {
t.Error(err)
}
value, err := ctx.Query("request.object.metadata.name") value, err := ctx.Query("request.object.metadata.name")
t.Log(value) t.Log(value)
if err != nil { if err != nil {
@ -145,14 +139,12 @@ func Test_variableSubstitutionPathNotExist(t *testing.T) {
}`) }`)
var policy kyverno.ClusterPolicy var policy kyverno.ClusterPolicy
err := json.Unmarshal(policyraw, &policy) json.Unmarshal(policyraw, &policy)
assert.NilError(t, err)
resourceUnstructured, err := utils.ConvertToUnstructured(resourceRaw) resourceUnstructured, err := utils.ConvertToUnstructured(resourceRaw)
assert.NilError(t, err) assert.NilError(t, err)
ctx := context.NewContext() ctx := context.NewContext()
err = ctx.AddResource(resourceRaw) ctx.AddResource(resourceRaw)
assert.NilError(t, err)
policyContext := PolicyContext{ policyContext := PolicyContext{
Policy: policy, Policy: policy,

View file

@ -9,7 +9,8 @@ import (
"github.com/nirmata/kyverno/pkg/utils" "github.com/nirmata/kyverno/pkg/utils"
authenticationv1 "k8s.io/api/authentication/v1" authenticationv1 "k8s.io/api/authentication/v1"
rbacv1 "k8s.io/api/rbac/v1" rbacv1 "k8s.io/api/rbac/v1"
"sigs.k8s.io/controller-runtime/pkg/log"
"github.com/golang/glog"
"github.com/minio/minio/pkg/wildcard" "github.com/minio/minio/pkg/wildcard"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1" kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
@ -52,7 +53,7 @@ func checkNameSpace(namespaces []string, resourceNameSpace string) bool {
func checkSelector(labelSelector *metav1.LabelSelector, resourceLabels map[string]string) (bool, error) { func checkSelector(labelSelector *metav1.LabelSelector, resourceLabels map[string]string) (bool, error) {
selector, err := metav1.LabelSelectorAsSelector(labelSelector) selector, err := metav1.LabelSelectorAsSelector(labelSelector)
if err != nil { if err != nil {
log.Log.Error(err, "failed to build label selector") glog.Error(err)
return false, err return false, err
} }

View file

@ -1,13 +1,12 @@
package validate package validate
import ( import (
"fmt"
"math" "math"
"regexp" "regexp"
"strconv" "strconv"
"strings" "strings"
"github.com/go-logr/logr" "github.com/golang/glog"
"github.com/minio/minio/pkg/wildcard" "github.com/minio/minio/pkg/wildcard"
"github.com/nirmata/kyverno/pkg/engine/operator" "github.com/nirmata/kyverno/pkg/engine/operator"
apiresource "k8s.io/apimachinery/pkg/api/resource" apiresource "k8s.io/apimachinery/pkg/api/resource"
@ -22,52 +21,52 @@ const (
) )
// ValidateValueWithPattern validates value with operators and wildcards // ValidateValueWithPattern validates value with operators and wildcards
func ValidateValueWithPattern(log logr.Logger, value, pattern interface{}) bool { func ValidateValueWithPattern(value, pattern interface{}) bool {
switch typedPattern := pattern.(type) { switch typedPattern := pattern.(type) {
case bool: case bool:
typedValue, ok := value.(bool) typedValue, ok := value.(bool)
if !ok { if !ok {
log.V(4).Info("Expected type bool", "type", fmt.Sprintf("%T", value), "value", value) glog.V(4).Infof("Expected bool, found %T", value)
return false return false
} }
return typedPattern == typedValue return typedPattern == typedValue
case int: case int:
return validateValueWithIntPattern(log, value, int64(typedPattern)) return validateValueWithIntPattern(value, int64(typedPattern))
case int64: case int64:
return validateValueWithIntPattern(log, value, typedPattern) return validateValueWithIntPattern(value, typedPattern)
case float64: case float64:
return validateValueWithFloatPattern(log, value, typedPattern) return validateValueWithFloatPattern(value, typedPattern)
case string: case string:
return validateValueWithStringPatterns(log, value, typedPattern) return validateValueWithStringPatterns(value, typedPattern)
case nil: case nil:
return validateValueWithNilPattern(log, value) return validateValueWithNilPattern(value)
case map[string]interface{}: case map[string]interface{}:
// TODO: check if this is ever called? // TODO: check if this is ever called?
return validateValueWithMapPattern(log, value, typedPattern) return validateValueWithMapPattern(value, typedPattern)
case []interface{}: case []interface{}:
// TODO: check if this is ever called? // TODO: check if this is ever called?
log.Info("arrays as patterns is not supported") glog.Warning("Arrays as patterns are not supported")
return false return false
default: default:
log.Info("Unkown type", "type", fmt.Sprintf("%T", typedPattern), "value", typedPattern) glog.Warningf("Unknown type as pattern: %v", typedPattern)
return false return false
} }
} }
func validateValueWithMapPattern(log logr.Logger, value interface{}, typedPattern map[string]interface{}) bool { func validateValueWithMapPattern(value interface{}, typedPattern map[string]interface{}) bool {
// verify the type of the resource value is map[string]interface, // verify the type of the resource value is map[string]interface,
// we only check for existence of object, not the equality of content and value // we only check for existence of object, not the equality of content and value
//TODO: check if adding //TODO: check if adding
_, ok := value.(map[string]interface{}) _, ok := value.(map[string]interface{})
if !ok { if !ok {
log.Info("Expected type map[string]interface{}", "type", fmt.Sprintf("%T", value), "value", value) glog.Warningf("Expected map[string]interface{}, found %T\n", value)
return false return false
} }
return true return true
} }
// Handler for int values during validation process // Handler for int values during validation process
func validateValueWithIntPattern(log logr.Logger, value interface{}, pattern int64) bool { func validateValueWithIntPattern(value interface{}, pattern int64) bool {
switch typedValue := value.(type) { switch typedValue := value.(type) {
case int: case int:
return int64(typedValue) == pattern return int64(typedValue) == pattern
@ -79,38 +78,38 @@ func validateValueWithIntPattern(log logr.Logger, value interface{}, pattern int
return int64(typedValue) == pattern return int64(typedValue) == pattern
} }
log.Info("Expected type int", "type", fmt.Sprintf("%T", typedValue), "value", typedValue) glog.Warningf("Expected int, found float: %f\n", typedValue)
return false return false
case string: case string:
// extract int64 from string // extract int64 from string
int64Num, err := strconv.ParseInt(typedValue, 10, 64) int64Num, err := strconv.ParseInt(typedValue, 10, 64)
if err != nil { if err != nil {
log.Error(err, "Failed to parse int64 from string") glog.Warningf("Failed to parse int64 from string: %v", err)
return false return false
} }
return int64Num == pattern return int64Num == pattern
default: default:
log.Info("Expected type int", "type", fmt.Sprintf("%T", value), "value", value) glog.Warningf("Expected int, found: %T\n", value)
return false return false
} }
} }
// Handler for float values during validation process // Handler for float values during validation process
func validateValueWithFloatPattern(log logr.Logger, value interface{}, pattern float64) bool { func validateValueWithFloatPattern(value interface{}, pattern float64) bool {
switch typedValue := value.(type) { switch typedValue := value.(type) {
case int: case int:
// check that float has no fraction // check that float has no fraction
if pattern == math.Trunc(pattern) { if pattern == math.Trunc(pattern) {
return int(pattern) == value return int(pattern) == value
} }
log.Info("Expected type float", "type", fmt.Sprintf("%T", typedValue), "value", typedValue) glog.Warningf("Expected float, found int: %d\n", typedValue)
return false return false
case int64: case int64:
// check that float has no fraction // check that float has no fraction
if pattern == math.Trunc(pattern) { if pattern == math.Trunc(pattern) {
return int64(pattern) == value return int64(pattern) == value
} }
log.Info("Expected type float", "type", fmt.Sprintf("%T", typedValue), "value", typedValue) glog.Warningf("Expected float, found int: %d\n", typedValue)
return false return false
case float64: case float64:
return typedValue == pattern return typedValue == pattern
@ -118,18 +117,18 @@ func validateValueWithFloatPattern(log logr.Logger, value interface{}, pattern f
// extract float64 from string // extract float64 from string
float64Num, err := strconv.ParseFloat(typedValue, 64) float64Num, err := strconv.ParseFloat(typedValue, 64)
if err != nil { if err != nil {
log.Error(err, "Failed to parse float64 from string") glog.Warningf("Failed to parse float64 from string: %v", err)
return false return false
} }
return float64Num == pattern return float64Num == pattern
default: default:
log.Info("Expected type float", "type", fmt.Sprintf("%T", value), "value", value) glog.Warningf("Expected float, found: %T\n", value)
return false return false
} }
} }
// Handler for nil values during validation process // Handler for nil values during validation process
func validateValueWithNilPattern(log logr.Logger, value interface{}) bool { func validateValueWithNilPattern(value interface{}) bool {
switch typed := value.(type) { switch typed := value.(type) {
case float64: case float64:
return typed == 0.0 return typed == 0.0
@ -144,20 +143,20 @@ func validateValueWithNilPattern(log logr.Logger, value interface{}) bool {
case nil: case nil:
return true return true
case map[string]interface{}, []interface{}: case map[string]interface{}, []interface{}:
log.Info("Maps and arrays could not be checked with nil pattern") glog.Warningf("Maps and arrays could not be checked with nil pattern")
return false return false
default: default:
log.Info("Unknown type as value when checking for nil pattern", "type", fmt.Sprintf("%T", value), "value", value) glog.Warningf("Unknown type as value when checking for nil pattern: %T\n", value)
return false return false
} }
} }
// Handler for pattern values during validation process // Handler for pattern values during validation process
func validateValueWithStringPatterns(log logr.Logger, value interface{}, pattern string) bool { func validateValueWithStringPatterns(value interface{}, pattern string) bool {
statements := strings.Split(pattern, "|") statements := strings.Split(pattern, "|")
for _, statement := range statements { for _, statement := range statements {
statement = strings.Trim(statement, " ") statement = strings.Trim(statement, " ")
if validateValueWithStringPattern(log, value, statement) { if validateValueWithStringPattern(value, statement) {
return true return true
} }
} }
@ -167,24 +166,24 @@ func validateValueWithStringPatterns(log logr.Logger, value interface{}, pattern
// Handler for single pattern value during validation process // Handler for single pattern value during validation process
// Detects if pattern has a number // Detects if pattern has a number
func validateValueWithStringPattern(log logr.Logger, value interface{}, pattern string) bool { func validateValueWithStringPattern(value interface{}, pattern string) bool {
operator := operator.GetOperatorFromStringPattern(pattern) operator := operator.GetOperatorFromStringPattern(pattern)
pattern = pattern[len(operator):] pattern = pattern[len(operator):]
number, str := getNumberAndStringPartsFromPattern(pattern) number, str := getNumberAndStringPartsFromPattern(pattern)
if "" == number { if "" == number {
return validateString(log, value, str, operator) return validateString(value, str, operator)
} }
return validateNumberWithStr(log, value, pattern, operator) return validateNumberWithStr(value, pattern, operator)
} }
// Handler for string values // Handler for string values
func validateString(log logr.Logger, value interface{}, pattern string, operatorVariable operator.Operator) bool { func validateString(value interface{}, pattern string, operatorVariable operator.Operator) bool {
if operator.NotEqual == operatorVariable || operator.Equal == operatorVariable { if operator.NotEqual == operatorVariable || operator.Equal == operatorVariable {
strValue, ok := value.(string) strValue, ok := value.(string)
if !ok { if !ok {
log.Info("Expected type string", "type", fmt.Sprintf("%T", value), "value", value) glog.Warningf("Expected string, found %T\n", value)
return false return false
} }
@ -196,16 +195,17 @@ func validateString(log logr.Logger, value interface{}, pattern string, operator
return wildcardResult return wildcardResult
} }
log.Info("Operators >, >=, <, <= are not applicable to strings")
glog.Warningf("Operators >, >=, <, <= are not applicable to strings")
return false return false
} }
// validateNumberWithStr compares quantity if pattern type is quantity // validateNumberWithStr compares quantity if pattern type is quantity
// or a wildcard match to pattern string // or a wildcard match to pattern string
func validateNumberWithStr(log logr.Logger, value interface{}, pattern string, operator operator.Operator) bool { func validateNumberWithStr(value interface{}, pattern string, operator operator.Operator) bool {
typedValue, err := convertToString(value) typedValue, err := convertToString(value)
if err != nil { if err != nil {
log.Error(err, "failed to convert to string") glog.Warning(err)
return false return false
} }
@ -214,7 +214,7 @@ func validateNumberWithStr(log logr.Logger, value interface{}, pattern string, o
if err == nil { if err == nil {
valueQuan, err := apiresource.ParseQuantity(typedValue) valueQuan, err := apiresource.ParseQuantity(typedValue)
if err != nil { if err != nil {
log.Error(err, "invalid quantity in resource", "type", fmt.Sprintf("%T", typedValue), "value", typedValue) glog.Warningf("Invalid quantity in resource %s, err: %v\n", typedValue, err)
return false return false
} }
@ -223,7 +223,7 @@ func validateNumberWithStr(log logr.Logger, value interface{}, pattern string, o
// 2. wildcard match // 2. wildcard match
if !wildcard.Match(pattern, typedValue) { if !wildcard.Match(pattern, typedValue) {
log.Info("value failed wildcard check", "type", fmt.Sprintf("%T", typedValue), "value", typedValue, "check", pattern) glog.Warningf("Value '%s' has not passed wildcard check: %s", typedValue, pattern)
return false return false
} }
return true return true

View file

@ -6,14 +6,13 @@ import (
"github.com/nirmata/kyverno/pkg/engine/operator" "github.com/nirmata/kyverno/pkg/engine/operator"
"gotest.tools/assert" "gotest.tools/assert"
"sigs.k8s.io/controller-runtime/pkg/log"
) )
func TestValidateValueWithPattern_Bool(t *testing.T) { func TestValidateValueWithPattern_Bool(t *testing.T) {
assert.Assert(t, ValidateValueWithPattern(log.Log, true, true)) assert.Assert(t, ValidateValueWithPattern(true, true))
assert.Assert(t, !ValidateValueWithPattern(log.Log, true, false)) assert.Assert(t, !ValidateValueWithPattern(true, false))
assert.Assert(t, !ValidateValueWithPattern(log.Log, false, true)) assert.Assert(t, !ValidateValueWithPattern(false, true))
assert.Assert(t, ValidateValueWithPattern(log.Log, false, false)) assert.Assert(t, ValidateValueWithPattern(false, false))
} }
func TestValidateString_AsteriskTest(t *testing.T) { func TestValidateString_AsteriskTest(t *testing.T) {
@ -21,8 +20,8 @@ func TestValidateString_AsteriskTest(t *testing.T) {
value := "anything" value := "anything"
empty := "" empty := ""
assert.Assert(t, validateString(log.Log, value, pattern, operator.Equal)) assert.Assert(t, validateString(value, pattern, operator.Equal))
assert.Assert(t, validateString(log.Log, empty, pattern, operator.Equal)) assert.Assert(t, validateString(empty, pattern, operator.Equal))
} }
func TestValidateString_LeftAsteriskTest(t *testing.T) { func TestValidateString_LeftAsteriskTest(t *testing.T) {
@ -30,32 +29,32 @@ func TestValidateString_LeftAsteriskTest(t *testing.T) {
value := "leftright" value := "leftright"
right := "right" right := "right"
assert.Assert(t, validateString(log.Log, value, pattern, operator.Equal)) assert.Assert(t, validateString(value, pattern, operator.Equal))
assert.Assert(t, validateString(log.Log, right, pattern, operator.Equal)) assert.Assert(t, validateString(right, pattern, operator.Equal))
value = "leftmiddle" value = "leftmiddle"
middle := "middle" middle := "middle"
assert.Assert(t, !validateString(log.Log, value, pattern, operator.Equal)) assert.Assert(t, !validateString(value, pattern, operator.Equal))
assert.Assert(t, !validateString(log.Log, middle, pattern, operator.Equal)) assert.Assert(t, !validateString(middle, pattern, operator.Equal))
} }
func TestValidateString_MiddleAsteriskTest(t *testing.T) { func TestValidateString_MiddleAsteriskTest(t *testing.T) {
pattern := "ab*ba" pattern := "ab*ba"
value := "abbeba" value := "abbeba"
assert.Assert(t, validateString(log.Log, value, pattern, operator.Equal)) assert.Assert(t, validateString(value, pattern, operator.Equal))
value = "abbca" value = "abbca"
assert.Assert(t, !validateString(log.Log, value, pattern, operator.Equal)) assert.Assert(t, !validateString(value, pattern, operator.Equal))
} }
func TestValidateString_QuestionMark(t *testing.T) { func TestValidateString_QuestionMark(t *testing.T) {
pattern := "ab?ba" pattern := "ab?ba"
value := "abbba" value := "abbba"
assert.Assert(t, validateString(log.Log, value, pattern, operator.Equal)) assert.Assert(t, validateString(value, pattern, operator.Equal))
value = "abbbba" value = "abbbba"
assert.Assert(t, !validateString(log.Log, value, pattern, operator.Equal)) assert.Assert(t, !validateString(value, pattern, operator.Equal))
} }
func TestValidateValueWithPattern_BoolInJson(t *testing.T) { func TestValidateValueWithPattern_BoolInJson(t *testing.T) {
@ -77,7 +76,7 @@ func TestValidateValueWithPattern_BoolInJson(t *testing.T) {
err = json.Unmarshal(rawValue, &value) err = json.Unmarshal(rawValue, &value)
assert.Assert(t, err) assert.Assert(t, err)
assert.Assert(t, ValidateValueWithPattern(log.Log, value["key"], pattern["key"])) assert.Assert(t, ValidateValueWithPattern(value["key"], pattern["key"]))
} }
func TestValidateValueWithPattern_NullPatternStringValue(t *testing.T) { func TestValidateValueWithPattern_NullPatternStringValue(t *testing.T) {
@ -99,7 +98,7 @@ func TestValidateValueWithPattern_NullPatternStringValue(t *testing.T) {
err = json.Unmarshal(rawValue, &value) err = json.Unmarshal(rawValue, &value)
assert.Assert(t, err) assert.Assert(t, err)
assert.Assert(t, !ValidateValueWithPattern(log.Log, value["key"], pattern["key"])) assert.Assert(t, !ValidateValueWithPattern(value["key"], pattern["key"]))
} }
func TestValidateValueWithPattern_NullPatternDefaultString(t *testing.T) { func TestValidateValueWithPattern_NullPatternDefaultString(t *testing.T) {
@ -121,7 +120,7 @@ func TestValidateValueWithPattern_NullPatternDefaultString(t *testing.T) {
err = json.Unmarshal(rawValue, &value) err = json.Unmarshal(rawValue, &value)
assert.Assert(t, err) assert.Assert(t, err)
assert.Assert(t, ValidateValueWithPattern(log.Log, value["key"], pattern["key"])) assert.Assert(t, ValidateValueWithPattern(value["key"], pattern["key"]))
} }
func TestValidateValueWithPattern_NullPatternDefaultFloat(t *testing.T) { func TestValidateValueWithPattern_NullPatternDefaultFloat(t *testing.T) {
@ -143,7 +142,7 @@ func TestValidateValueWithPattern_NullPatternDefaultFloat(t *testing.T) {
err = json.Unmarshal(rawValue, &value) err = json.Unmarshal(rawValue, &value)
assert.Assert(t, err) assert.Assert(t, err)
assert.Assert(t, ValidateValueWithPattern(log.Log, value["key"], pattern["key"])) assert.Assert(t, ValidateValueWithPattern(value["key"], pattern["key"]))
} }
func TestValidateValueWithPattern_NullPatternDefaultInt(t *testing.T) { func TestValidateValueWithPattern_NullPatternDefaultInt(t *testing.T) {
@ -165,7 +164,7 @@ func TestValidateValueWithPattern_NullPatternDefaultInt(t *testing.T) {
err = json.Unmarshal(rawValue, &value) err = json.Unmarshal(rawValue, &value)
assert.Assert(t, err) assert.Assert(t, err)
assert.Assert(t, ValidateValueWithPattern(log.Log, value["key"], pattern["key"])) assert.Assert(t, ValidateValueWithPattern(value["key"], pattern["key"]))
} }
func TestValidateValueWithPattern_NullPatternDefaultBool(t *testing.T) { func TestValidateValueWithPattern_NullPatternDefaultBool(t *testing.T) {
@ -187,77 +186,77 @@ func TestValidateValueWithPattern_NullPatternDefaultBool(t *testing.T) {
err = json.Unmarshal(rawValue, &value) err = json.Unmarshal(rawValue, &value)
assert.Assert(t, err) assert.Assert(t, err)
assert.Assert(t, ValidateValueWithPattern(log.Log, value["key"], pattern["key"])) assert.Assert(t, ValidateValueWithPattern(value["key"], pattern["key"]))
} }
func TestValidateValueWithPattern_StringsLogicalOr(t *testing.T) { func TestValidateValueWithPattern_StringsLogicalOr(t *testing.T) {
pattern := "192.168.88.1 | 10.100.11.*" pattern := "192.168.88.1 | 10.100.11.*"
value := "10.100.11.54" value := "10.100.11.54"
assert.Assert(t, ValidateValueWithPattern(log.Log, value, pattern)) assert.Assert(t, ValidateValueWithPattern(value, pattern))
} }
func TestValidateValueWithPattern_EqualTwoFloats(t *testing.T) { func TestValidateValueWithPattern_EqualTwoFloats(t *testing.T) {
assert.Assert(t, ValidateValueWithPattern(log.Log, 7.0, 7.000)) assert.Assert(t, ValidateValueWithPattern(7.0, 7.000))
} }
func TestValidateValueWithNilPattern_NullPatternStringValue(t *testing.T) { func TestValidateValueWithNilPattern_NullPatternStringValue(t *testing.T) {
assert.Assert(t, !validateValueWithNilPattern(log.Log, "value")) assert.Assert(t, !validateValueWithNilPattern("value"))
} }
func TestValidateValueWithNilPattern_NullPatternDefaultString(t *testing.T) { func TestValidateValueWithNilPattern_NullPatternDefaultString(t *testing.T) {
assert.Assert(t, validateValueWithNilPattern(log.Log, "")) assert.Assert(t, validateValueWithNilPattern(""))
} }
func TestValidateValueWithNilPattern_NullPatternDefaultFloat(t *testing.T) { func TestValidateValueWithNilPattern_NullPatternDefaultFloat(t *testing.T) {
assert.Assert(t, validateValueWithNilPattern(log.Log, 0.0)) assert.Assert(t, validateValueWithNilPattern(0.0))
} }
func TestValidateValueWithNilPattern_NullPatternFloat(t *testing.T) { func TestValidateValueWithNilPattern_NullPatternFloat(t *testing.T) {
assert.Assert(t, !validateValueWithNilPattern(log.Log, 0.1)) assert.Assert(t, !validateValueWithNilPattern(0.1))
} }
func TestValidateValueWithNilPattern_NullPatternDefaultInt(t *testing.T) { func TestValidateValueWithNilPattern_NullPatternDefaultInt(t *testing.T) {
assert.Assert(t, validateValueWithNilPattern(log.Log, 0)) assert.Assert(t, validateValueWithNilPattern(0))
} }
func TestValidateValueWithNilPattern_NullPatternInt(t *testing.T) { func TestValidateValueWithNilPattern_NullPatternInt(t *testing.T) {
assert.Assert(t, !validateValueWithNilPattern(log.Log, 1)) assert.Assert(t, !validateValueWithNilPattern(1))
} }
func TestValidateValueWithNilPattern_NullPatternDefaultBool(t *testing.T) { func TestValidateValueWithNilPattern_NullPatternDefaultBool(t *testing.T) {
assert.Assert(t, validateValueWithNilPattern(log.Log, false)) assert.Assert(t, validateValueWithNilPattern(false))
} }
func TestValidateValueWithNilPattern_NullPatternTrueBool(t *testing.T) { func TestValidateValueWithNilPattern_NullPatternTrueBool(t *testing.T) {
assert.Assert(t, !validateValueWithNilPattern(log.Log, true)) assert.Assert(t, !validateValueWithNilPattern(true))
} }
func TestValidateValueWithFloatPattern_FloatValue(t *testing.T) { func TestValidateValueWithFloatPattern_FloatValue(t *testing.T) {
assert.Assert(t, validateValueWithFloatPattern(log.Log, 7.9914, 7.9914)) assert.Assert(t, validateValueWithFloatPattern(7.9914, 7.9914))
} }
func TestValidateValueWithFloatPattern_FloatValueNotPass(t *testing.T) { func TestValidateValueWithFloatPattern_FloatValueNotPass(t *testing.T) {
assert.Assert(t, !validateValueWithFloatPattern(log.Log, 7.9914, 7.99141)) assert.Assert(t, !validateValueWithFloatPattern(7.9914, 7.99141))
} }
func TestValidateValueWithFloatPattern_FloatPatternWithoutFractionIntValue(t *testing.T) { func TestValidateValueWithFloatPattern_FloatPatternWithoutFractionIntValue(t *testing.T) {
assert.Assert(t, validateValueWithFloatPattern(log.Log, 7, 7.000000)) assert.Assert(t, validateValueWithFloatPattern(7, 7.000000))
} }
func TestValidateValueWithFloatPattern_FloatPatternWithoutFraction(t *testing.T) { func TestValidateValueWithFloatPattern_FloatPatternWithoutFraction(t *testing.T) {
assert.Assert(t, validateValueWithFloatPattern(log.Log, 7.000000, 7.000000)) assert.Assert(t, validateValueWithFloatPattern(7.000000, 7.000000))
} }
func TestValidateValueWithIntPattern_FloatValueWithoutFraction(t *testing.T) { func TestValidateValueWithIntPattern_FloatValueWithoutFraction(t *testing.T) {
assert.Assert(t, validateValueWithFloatPattern(log.Log, 7.000000, 7)) assert.Assert(t, validateValueWithFloatPattern(7.000000, 7))
} }
func TestValidateValueWithIntPattern_FloatValueWitFraction(t *testing.T) { func TestValidateValueWithIntPattern_FloatValueWitFraction(t *testing.T) {
assert.Assert(t, !validateValueWithFloatPattern(log.Log, 7.000001, 7)) assert.Assert(t, !validateValueWithFloatPattern(7.000001, 7))
} }
func TestValidateValueWithIntPattern_NotPass(t *testing.T) { func TestValidateValueWithIntPattern_NotPass(t *testing.T) {
assert.Assert(t, !validateValueWithFloatPattern(log.Log, 8, 7)) assert.Assert(t, !validateValueWithFloatPattern(8, 7))
} }
func TestGetNumberAndStringPartsFromPattern_NumberAndString(t *testing.T) { func TestGetNumberAndStringPartsFromPattern_NumberAndString(t *testing.T) {
@ -291,35 +290,35 @@ func TestGetNumberAndStringPartsFromPattern_Empty(t *testing.T) {
} }
func TestValidateNumberWithStr_LessFloatAndInt(t *testing.T) { func TestValidateNumberWithStr_LessFloatAndInt(t *testing.T) {
assert.Assert(t, validateNumberWithStr(log.Log, 7.00001, "7.000001", operator.More)) assert.Assert(t, validateNumberWithStr(7.00001, "7.000001", operator.More))
assert.Assert(t, validateNumberWithStr(log.Log, 7.00001, "7", operator.NotEqual)) assert.Assert(t, validateNumberWithStr(7.00001, "7", operator.NotEqual))
assert.Assert(t, validateNumberWithStr(log.Log, 7.0000, "7", operator.Equal)) assert.Assert(t, validateNumberWithStr(7.0000, "7", operator.Equal))
assert.Assert(t, !validateNumberWithStr(log.Log, 6.000000001, "6", operator.Less)) assert.Assert(t, !validateNumberWithStr(6.000000001, "6", operator.Less))
} }
func TestValidateQuantity_InvalidQuantity(t *testing.T) { func TestValidateQuantity_InvalidQuantity(t *testing.T) {
assert.Assert(t, !validateNumberWithStr(log.Log, "1024Gi", "", operator.Equal)) assert.Assert(t, !validateNumberWithStr("1024Gi", "", operator.Equal))
assert.Assert(t, !validateNumberWithStr(log.Log, "gii", "1024Gi", operator.Equal)) assert.Assert(t, !validateNumberWithStr("gii", "1024Gi", operator.Equal))
} }
func TestValidateQuantity_Equal(t *testing.T) { func TestValidateQuantity_Equal(t *testing.T) {
assert.Assert(t, validateNumberWithStr(log.Log, "1024Gi", "1024Gi", operator.Equal)) assert.Assert(t, validateNumberWithStr("1024Gi", "1024Gi", operator.Equal))
assert.Assert(t, validateNumberWithStr(log.Log, "1024Mi", "1Gi", operator.Equal)) assert.Assert(t, validateNumberWithStr("1024Mi", "1Gi", operator.Equal))
assert.Assert(t, validateNumberWithStr(log.Log, "0.2", "200m", operator.Equal)) assert.Assert(t, validateNumberWithStr("0.2", "200m", operator.Equal))
assert.Assert(t, validateNumberWithStr(log.Log, "500", "500", operator.Equal)) assert.Assert(t, validateNumberWithStr("500", "500", operator.Equal))
assert.Assert(t, !validateNumberWithStr(log.Log, "2048", "1024", operator.Equal)) assert.Assert(t, !validateNumberWithStr("2048", "1024", operator.Equal))
assert.Assert(t, validateNumberWithStr(log.Log, 1024, "1024", operator.Equal)) assert.Assert(t, validateNumberWithStr(1024, "1024", operator.Equal))
} }
func TestValidateQuantity_Operation(t *testing.T) { func TestValidateQuantity_Operation(t *testing.T) {
assert.Assert(t, validateNumberWithStr(log.Log, "1Gi", "1000Mi", operator.More)) assert.Assert(t, validateNumberWithStr("1Gi", "1000Mi", operator.More))
assert.Assert(t, validateNumberWithStr(log.Log, "1G", "1Gi", operator.Less)) assert.Assert(t, validateNumberWithStr("1G", "1Gi", operator.Less))
assert.Assert(t, validateNumberWithStr(log.Log, "500m", "0.5", operator.MoreEqual)) assert.Assert(t, validateNumberWithStr("500m", "0.5", operator.MoreEqual))
assert.Assert(t, validateNumberWithStr(log.Log, "1", "500m", operator.MoreEqual)) assert.Assert(t, validateNumberWithStr("1", "500m", operator.MoreEqual))
assert.Assert(t, validateNumberWithStr(log.Log, "0.5", ".5", operator.LessEqual)) assert.Assert(t, validateNumberWithStr("0.5", ".5", operator.LessEqual))
assert.Assert(t, validateNumberWithStr(log.Log, "0.2", ".5", operator.LessEqual)) assert.Assert(t, validateNumberWithStr("0.2", ".5", operator.LessEqual))
assert.Assert(t, validateNumberWithStr(log.Log, "0.2", ".5", operator.NotEqual)) assert.Assert(t, validateNumberWithStr("0.2", ".5", operator.NotEqual))
} }
func TestGetOperatorFromStringPattern_OneChar(t *testing.T) { func TestGetOperatorFromStringPattern_OneChar(t *testing.T) {

View file

@ -8,15 +8,15 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/go-logr/logr" "github.com/golang/glog"
"github.com/nirmata/kyverno/pkg/engine/anchor" "github.com/nirmata/kyverno/pkg/engine/anchor"
"github.com/nirmata/kyverno/pkg/engine/operator" "github.com/nirmata/kyverno/pkg/engine/operator"
) )
// ValidateResourceWithPattern is a start of element-by-element validation process // ValidateResourceWithPattern is a start of element-by-element validation process
// It assumes that validation is started from root, so "/" is passed // It assumes that validation is started from root, so "/" is passed
func ValidateResourceWithPattern(log logr.Logger, resource, pattern interface{}) (string, error) { func ValidateResourceWithPattern(resource, pattern interface{}) (string, error) {
path, err := validateResourceElement(log, resource, pattern, pattern, "/") path, err := validateResourceElement(resource, pattern, pattern, "/")
if err != nil { if err != nil {
return path, err return path, err
} }
@ -27,44 +27,44 @@ func ValidateResourceWithPattern(log logr.Logger, resource, pattern interface{})
// validateResourceElement detects the element type (map, array, nil, string, int, bool, float) // validateResourceElement detects the element type (map, array, nil, string, int, bool, float)
// and calls corresponding handler // and calls corresponding handler
// Pattern tree and resource tree can have different structure. In this case validation fails // Pattern tree and resource tree can have different structure. In this case validation fails
func validateResourceElement(log logr.Logger, resourceElement, patternElement, originPattern interface{}, path string) (string, error) { func validateResourceElement(resourceElement, patternElement, originPattern interface{}, path string) (string, error) {
var err error var err error
switch typedPatternElement := patternElement.(type) { switch typedPatternElement := patternElement.(type) {
// map // map
case map[string]interface{}: case map[string]interface{}:
typedResourceElement, ok := resourceElement.(map[string]interface{}) typedResourceElement, ok := resourceElement.(map[string]interface{})
if !ok { if !ok {
log.V(4).Info("Pattern and resource have different structures.", "path", path, "expected", fmt.Sprintf("%T", patternElement), "current", fmt.Sprintf("%T", resourceElement)) glog.V(4).Infof("Pattern and resource have different structures. Path: %s. Expected %T, found %T", path, patternElement, resourceElement)
return path, fmt.Errorf("Pattern and resource have different structures. Path: %s. Expected %T, found %T", path, patternElement, resourceElement) return path, fmt.Errorf("Pattern and resource have different structures. Path: %s. Expected %T, found %T", path, patternElement, resourceElement)
} }
return validateMap(log, typedResourceElement, typedPatternElement, originPattern, path) return validateMap(typedResourceElement, typedPatternElement, originPattern, path)
// array // array
case []interface{}: case []interface{}:
typedResourceElement, ok := resourceElement.([]interface{}) typedResourceElement, ok := resourceElement.([]interface{})
if !ok { if !ok {
log.V(4).Info("Pattern and resource have different structures.", "path", path, "expected", fmt.Sprintf("%T", patternElement), "current", fmt.Sprintf("%T", resourceElement)) glog.V(4).Infof("Pattern and resource have different structures. Path: %s. Expected %T, found %T", path, patternElement, resourceElement)
return path, fmt.Errorf("Validation rule Failed at path %s, resource does not satisfy the expected overlay pattern", path) return path, fmt.Errorf("Validation rule Failed at path %s, resource does not satisfy the expected overlay pattern", path)
} }
return validateArray(log, typedResourceElement, typedPatternElement, originPattern, path) return validateArray(typedResourceElement, typedPatternElement, originPattern, path)
// elementary values // elementary values
case string, float64, int, int64, bool, nil: case string, float64, int, int64, bool, nil:
/*Analyze pattern */ /*Analyze pattern */
if checkedPattern := reflect.ValueOf(patternElement); checkedPattern.Kind() == reflect.String { if checkedPattern := reflect.ValueOf(patternElement); checkedPattern.Kind() == reflect.String {
if isStringIsReference(checkedPattern.String()) { //check for $ anchor if isStringIsReference(checkedPattern.String()) { //check for $ anchor
patternElement, err = actualizePattern(log, originPattern, checkedPattern.String(), path) patternElement, err = actualizePattern(originPattern, checkedPattern.String(), path)
if err != nil { if err != nil {
return path, err return path, err
} }
} }
} }
if !ValidateValueWithPattern(log, resourceElement, patternElement) { if !ValidateValueWithPattern(resourceElement, patternElement) {
return path, fmt.Errorf("Validation rule failed at '%s' to validate value '%v' with pattern '%v'", path, resourceElement, patternElement) return path, fmt.Errorf("Validation rule failed at '%s' to validate value '%v' with pattern '%v'", path, resourceElement, patternElement)
} }
default: default:
log.V(4).Info("Pattern contains unknown type", "path", path, "current", fmt.Sprintf("%T", patternElement)) glog.V(4).Infof("Pattern contains unknown type %T. Path: %s", patternElement, path)
return path, fmt.Errorf("Validation rule failed at '%s', pattern contains unknown type", path) return path, fmt.Errorf("Validation rule failed at '%s', pattern contains unknown type", path)
} }
return "", nil return "", nil
@ -72,7 +72,7 @@ func validateResourceElement(log logr.Logger, resourceElement, patternElement, o
// If validateResourceElement detects map element inside resource and pattern trees, it goes to validateMap // If validateResourceElement detects map element inside resource and pattern trees, it goes to validateMap
// For each element of the map we must detect the type again, so we pass these elements to validateResourceElement // For each element of the map we must detect the type again, so we pass these elements to validateResourceElement
func validateMap(log logr.Logger, resourceMap, patternMap map[string]interface{}, origPattern interface{}, path string) (string, error) { func validateMap(resourceMap, patternMap map[string]interface{}, origPattern interface{}, path string) (string, error) {
// check if there is anchor in pattern // check if there is anchor in pattern
// Phase 1 : Evaluate all the anchors // Phase 1 : Evaluate all the anchors
// Phase 2 : Evaluate non-anchors // Phase 2 : Evaluate non-anchors
@ -91,7 +91,7 @@ func validateMap(log logr.Logger, resourceMap, patternMap map[string]interface{}
if err != nil { if err != nil {
// If Conditional anchor fails then we dont process the resources // If Conditional anchor fails then we dont process the resources
if anchor.IsConditionAnchor(key) { if anchor.IsConditionAnchor(key) {
log.Error(err, "condition anchor did not satisfy, wont process the resource") glog.V(4).Infof("condition anchor did not satisfy, wont process the resources: %s", err)
return "", nil return "", nil
} }
return handlerPath, err return handlerPath, err
@ -109,7 +109,7 @@ func validateMap(log logr.Logger, resourceMap, patternMap map[string]interface{}
return "", nil return "", nil
} }
func validateArray(log logr.Logger, resourceArray, patternArray []interface{}, originPattern interface{}, path string) (string, error) { func validateArray(resourceArray, patternArray []interface{}, originPattern interface{}, path string) (string, error) {
if 0 == len(patternArray) { if 0 == len(patternArray) {
return path, fmt.Errorf("Pattern Array empty") return path, fmt.Errorf("Pattern Array empty")
@ -119,7 +119,7 @@ func validateArray(log logr.Logger, resourceArray, patternArray []interface{}, o
case map[string]interface{}: case map[string]interface{}:
// This is special case, because maps in arrays can have anchors that must be // This is special case, because maps in arrays can have anchors that must be
// processed with the special way affecting the entire array // processed with the special way affecting the entire array
path, err := validateArrayOfMaps(log, resourceArray, typedPatternElement, originPattern, path) path, err := validateArrayOfMaps(resourceArray, typedPatternElement, originPattern, path)
if err != nil { if err != nil {
return path, err return path, err
} }
@ -127,7 +127,7 @@ func validateArray(log logr.Logger, resourceArray, patternArray []interface{}, o
// In all other cases - detect type and handle each array element with validateResourceElement // In all other cases - detect type and handle each array element with validateResourceElement
for i, patternElement := range patternArray { for i, patternElement := range patternArray {
currentPath := path + strconv.Itoa(i) + "/" currentPath := path + strconv.Itoa(i) + "/"
path, err := validateResourceElement(log, resourceArray[i], patternElement, originPattern, currentPath) path, err := validateResourceElement(resourceArray[i], patternElement, originPattern, currentPath)
if err != nil { if err != nil {
return path, err return path, err
} }
@ -137,7 +137,7 @@ func validateArray(log logr.Logger, resourceArray, patternArray []interface{}, o
return "", nil return "", nil
} }
func actualizePattern(log logr.Logger, origPattern interface{}, referencePattern, absolutePath string) (interface{}, error) { func actualizePattern(origPattern interface{}, referencePattern, absolutePath string) (interface{}, error) {
var foundValue interface{} var foundValue interface{}
referencePattern = strings.Trim(referencePattern, "$()") referencePattern = strings.Trim(referencePattern, "$()")
@ -155,7 +155,7 @@ func actualizePattern(log logr.Logger, origPattern interface{}, referencePattern
// value := // value :=
actualPath := formAbsolutePath(referencePattern, absolutePath) actualPath := formAbsolutePath(referencePattern, absolutePath)
valFromReference, err := getValueFromReference(log, origPattern, actualPath) valFromReference, err := getValueFromReference(origPattern, actualPath)
if err != nil { if err != nil {
return err, nil return err, nil
} }
@ -196,15 +196,15 @@ func formAbsolutePath(referencePath, absolutePath string) string {
} }
//Prepares original pattern, path to value, and call traverse function //Prepares original pattern, path to value, and call traverse function
func getValueFromReference(log logr.Logger, origPattern interface{}, reference string) (interface{}, error) { func getValueFromReference(origPattern interface{}, reference string) (interface{}, error) {
originalPatternMap := origPattern.(map[string]interface{}) originalPatternMap := origPattern.(map[string]interface{})
reference = reference[1:] reference = reference[1:]
statements := strings.Split(reference, "/") statements := strings.Split(reference, "/")
return getValueFromPattern(log, originalPatternMap, statements, 0) return getValueFromPattern(originalPatternMap, statements, 0)
} }
func getValueFromPattern(log logr.Logger, patternMap map[string]interface{}, keys []string, currentKeyIndex int) (interface{}, error) { func getValueFromPattern(patternMap map[string]interface{}, keys []string, currentKeyIndex int) (interface{}, error) {
for key, pattern := range patternMap { for key, pattern := range patternMap {
rawKey := getRawKeyIfWrappedWithAttributes(key) rawKey := getRawKeyIfWrappedWithAttributes(key)
@ -221,21 +221,19 @@ func getValueFromPattern(log logr.Logger, patternMap map[string]interface{}, key
for i, value := range typedPattern { for i, value := range typedPattern {
resourceMap, ok := value.(map[string]interface{}) resourceMap, ok := value.(map[string]interface{})
if !ok { if !ok {
log.V(4).Info("Pattern and resource have different structures.", "expected", fmt.Sprintf("%T", pattern), "current", fmt.Sprintf("%T", value)) glog.V(4).Infof("Pattern and resource have different structures. Expected %T, found %T", pattern, value)
return nil, fmt.Errorf("Validation rule failed, resource does not have expected pattern %v", patternMap) return nil, fmt.Errorf("Validation rule failed, resource does not have expected pattern %v", patternMap)
} }
if keys[currentKeyIndex+1] == strconv.Itoa(i) { if keys[currentKeyIndex+1] == strconv.Itoa(i) {
return getValueFromPattern(log, resourceMap, keys, currentKeyIndex+2) return getValueFromPattern(resourceMap, keys, currentKeyIndex+2)
} }
// TODO : SA4004: the surrounding loop is unconditionally terminated (staticcheck)
return nil, errors.New("Reference to non-existent place in the document") return nil, errors.New("Reference to non-existent place in the document")
} }
return nil, nil // Just a hack to fix the lint
} }
return nil, errors.New("Reference to non-existent place in the document") return nil, errors.New("Reference to non-existent place in the document")
case map[string]interface{}: case map[string]interface{}:
if keys[currentKeyIndex] == rawKey { if keys[currentKeyIndex] == rawKey {
return getValueFromPattern(log, typedPattern, keys, currentKeyIndex+1) return getValueFromPattern(typedPattern, keys, currentKeyIndex+1)
} }
return nil, errors.New("Reference to non-existent place in the document") return nil, errors.New("Reference to non-existent place in the document")
case string, float64, int, int64, bool, nil: case string, float64, int, int64, bool, nil:
@ -253,12 +251,12 @@ func getValueFromPattern(log logr.Logger, patternMap map[string]interface{}, key
// validateArrayOfMaps gets anchors from pattern array map element, applies anchors logic // validateArrayOfMaps gets anchors from pattern array map element, applies anchors logic
// and then validates each map due to the pattern // and then validates each map due to the pattern
func validateArrayOfMaps(log logr.Logger, resourceMapArray []interface{}, patternMap map[string]interface{}, originPattern interface{}, path string) (string, error) { func validateArrayOfMaps(resourceMapArray []interface{}, patternMap map[string]interface{}, originPattern interface{}, path string) (string, error) {
for i, resourceElement := range resourceMapArray { for i, resourceElement := range resourceMapArray {
// check the types of resource element // check the types of resource element
// expect it to be map, but can be anything ?:( // expect it to be map, but can be anything ?:(
currentPath := path + strconv.Itoa(i) + "/" currentPath := path + strconv.Itoa(i) + "/"
returnpath, err := validateResourceElement(log, resourceElement, patternMap, originPattern, currentPath) returnpath, err := validateResourceElement(resourceElement, patternMap, originPattern, currentPath)
if err != nil { if err != nil {
return returnpath, err return returnpath, err
} }

View file

@ -5,7 +5,6 @@ import (
"testing" "testing"
"gotest.tools/assert" "gotest.tools/assert"
"sigs.k8s.io/controller-runtime/pkg/log"
) )
func TestValidateMap(t *testing.T) { func TestValidateMap(t *testing.T) {
@ -101,7 +100,7 @@ func TestValidateMap(t *testing.T) {
assert.Assert(t, json.Unmarshal(rawPattern, &pattern)) assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
assert.Assert(t, json.Unmarshal(rawMap, &resource)) assert.Assert(t, json.Unmarshal(rawMap, &resource))
path, err := validateMap(log.Log, resource, pattern, pattern, "/") path, err := validateMap(resource, pattern, pattern, "/")
assert.Equal(t, path, "") assert.Equal(t, path, "")
assert.NilError(t, err) assert.NilError(t, err)
} }
@ -197,7 +196,7 @@ func TestValidateMap_AsteriskForInt(t *testing.T) {
assert.Assert(t, json.Unmarshal(rawPattern, &pattern)) assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
assert.Assert(t, json.Unmarshal(rawMap, &resource)) assert.Assert(t, json.Unmarshal(rawMap, &resource))
path, err := validateMap(log.Log, resource, pattern, pattern, "/") path, err := validateMap(resource, pattern, pattern, "/")
t.Log(path) t.Log(path)
assert.NilError(t, err) assert.NilError(t, err)
} }
@ -290,7 +289,7 @@ func TestValidateMap_AsteriskForMap(t *testing.T) {
assert.Assert(t, json.Unmarshal(rawPattern, &pattern)) assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
assert.Assert(t, json.Unmarshal(rawMap, &resource)) assert.Assert(t, json.Unmarshal(rawMap, &resource))
path, err := validateMap(log.Log, resource, pattern, pattern, "/") path, err := validateMap(resource, pattern, pattern, "/")
assert.Equal(t, path, "") assert.Equal(t, path, "")
assert.NilError(t, err) assert.NilError(t, err)
} }
@ -378,7 +377,7 @@ func TestValidateMap_AsteriskForArray(t *testing.T) {
assert.Assert(t, json.Unmarshal(rawPattern, &pattern)) assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
assert.Assert(t, json.Unmarshal(rawMap, &resource)) assert.Assert(t, json.Unmarshal(rawMap, &resource))
path, err := validateMap(log.Log, resource, pattern, pattern, "/") path, err := validateMap(resource, pattern, pattern, "/")
assert.Equal(t, path, "") assert.Equal(t, path, "")
assert.NilError(t, err) assert.NilError(t, err)
} }
@ -469,7 +468,7 @@ func TestValidateMap_AsteriskFieldIsMissing(t *testing.T) {
assert.Assert(t, json.Unmarshal(rawPattern, &pattern)) assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
assert.Assert(t, json.Unmarshal(rawMap, &resource)) assert.Assert(t, json.Unmarshal(rawMap, &resource))
path, err := validateMap(log.Log, resource, pattern, pattern, "/") path, err := validateMap(resource, pattern, pattern, "/")
assert.Equal(t, path, "/spec/template/spec/containers/0/") assert.Equal(t, path, "/spec/template/spec/containers/0/")
assert.Assert(t, err != nil) assert.Assert(t, err != nil)
} }
@ -558,10 +557,9 @@ func TestValidateMap_livenessProbeIsNull(t *testing.T) {
var pattern, resource map[string]interface{} var pattern, resource map[string]interface{}
assert.Assert(t, json.Unmarshal(rawPattern, &pattern)) assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
err := json.Unmarshal(rawMap, &resource) json.Unmarshal(rawMap, &resource)
assert.NilError(t, err)
path, err := validateMap(log.Log, resource, pattern, pattern, "/") path, err := validateMap(resource, pattern, pattern, "/")
assert.Equal(t, path, "") assert.Equal(t, path, "")
assert.NilError(t, err) assert.NilError(t, err)
} }
@ -651,7 +649,7 @@ func TestValidateMap_livenessProbeIsMissing(t *testing.T) {
assert.Assert(t, json.Unmarshal(rawPattern, &pattern)) assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
assert.Assert(t, json.Unmarshal(rawMap, &resource)) assert.Assert(t, json.Unmarshal(rawMap, &resource))
path, err := validateMap(log.Log, resource, pattern, pattern, "/") path, err := validateMap(resource, pattern, pattern, "/")
assert.Equal(t, path, "") assert.Equal(t, path, "")
assert.NilError(t, err) assert.NilError(t, err)
} }
@ -697,7 +695,7 @@ func TestValidateMapElement_TwoElementsInArrayOnePass(t *testing.T) {
assert.Assert(t, json.Unmarshal(rawPattern, &pattern)) assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
assert.Assert(t, json.Unmarshal(rawMap, &resource)) assert.Assert(t, json.Unmarshal(rawMap, &resource))
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/") path, err := validateResourceElement(resource, pattern, pattern, "/")
assert.Equal(t, path, "") assert.Equal(t, path, "")
// assert.Equal(t, path, "/1/object/0/key2/") // assert.Equal(t, path, "/1/object/0/key2/")
// assert.NilError(t, err) // assert.NilError(t, err)
@ -732,7 +730,7 @@ func TestValidateMapElement_OneElementInArrayPass(t *testing.T) {
assert.Assert(t, json.Unmarshal(rawPattern, &pattern)) assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
assert.Assert(t, json.Unmarshal(rawMap, &resource)) assert.Assert(t, json.Unmarshal(rawMap, &resource))
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/") path, err := validateResourceElement(resource, pattern, pattern, "/")
assert.Equal(t, path, "") assert.Equal(t, path, "")
assert.NilError(t, err) assert.NilError(t, err)
} }
@ -786,7 +784,7 @@ func TestValidateMap_CorrectRelativePathInConfig(t *testing.T) {
assert.Assert(t, json.Unmarshal(rawPattern, &pattern)) assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
assert.Assert(t, json.Unmarshal(rawMap, &resource)) assert.Assert(t, json.Unmarshal(rawMap, &resource))
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/") path, err := validateResourceElement(resource, pattern, pattern, "/")
assert.Equal(t, path, "") assert.Equal(t, path, "")
assert.NilError(t, err) assert.NilError(t, err)
} }
@ -840,7 +838,7 @@ func TestValidateMap_RelativePathDoesNotExists(t *testing.T) {
assert.Assert(t, json.Unmarshal(rawPattern, &pattern)) assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
assert.Assert(t, json.Unmarshal(rawMap, &resource)) assert.Assert(t, json.Unmarshal(rawMap, &resource))
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/") path, err := validateResourceElement(resource, pattern, pattern, "/")
assert.Equal(t, path, "/spec/containers/0/resources/requests/memory/") assert.Equal(t, path, "/spec/containers/0/resources/requests/memory/")
assert.Assert(t, err != nil) assert.Assert(t, err != nil)
} }
@ -894,7 +892,7 @@ func TestValidateMap_OnlyAnchorsInPath(t *testing.T) {
assert.Assert(t, json.Unmarshal(rawPattern, &pattern)) assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
assert.Assert(t, json.Unmarshal(rawMap, &resource)) assert.Assert(t, json.Unmarshal(rawMap, &resource))
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/") path, err := validateResourceElement(resource, pattern, pattern, "/")
assert.Equal(t, path, "/spec/containers/0/resources/requests/memory/") assert.Equal(t, path, "/spec/containers/0/resources/requests/memory/")
assert.Assert(t, err != nil) assert.Assert(t, err != nil)
} }
@ -948,7 +946,7 @@ func TestValidateMap_MalformedReferenceOnlyDolarMark(t *testing.T) {
assert.Assert(t, json.Unmarshal(rawPattern, &pattern)) assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
assert.Assert(t, json.Unmarshal(rawMap, &resource)) assert.Assert(t, json.Unmarshal(rawMap, &resource))
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/") path, err := validateResourceElement(resource, pattern, pattern, "/")
assert.Equal(t, path, "/spec/containers/0/resources/requests/memory/") assert.Equal(t, path, "/spec/containers/0/resources/requests/memory/")
assert.Assert(t, err != nil) assert.Assert(t, err != nil)
} }
@ -1002,7 +1000,7 @@ func TestValidateMap_RelativePathWithParentheses(t *testing.T) {
assert.Assert(t, json.Unmarshal(rawPattern, &pattern)) assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
assert.Assert(t, json.Unmarshal(rawMap, &resource)) assert.Assert(t, json.Unmarshal(rawMap, &resource))
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/") path, err := validateResourceElement(resource, pattern, pattern, "/")
assert.Equal(t, path, "") assert.Equal(t, path, "")
assert.NilError(t, err) assert.NilError(t, err)
} }
@ -1056,7 +1054,7 @@ func TestValidateMap_MalformedPath(t *testing.T) {
assert.Assert(t, json.Unmarshal(rawPattern, &pattern)) assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
assert.Assert(t, json.Unmarshal(rawMap, &resource)) assert.Assert(t, json.Unmarshal(rawMap, &resource))
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/") path, err := validateResourceElement(resource, pattern, pattern, "/")
assert.Equal(t, path, "/spec/containers/0/resources/requests/memory/") assert.Equal(t, path, "/spec/containers/0/resources/requests/memory/")
assert.Assert(t, err != nil) assert.Assert(t, err != nil)
} }
@ -1110,7 +1108,7 @@ func TestValidateMap_AbosolutePathExists(t *testing.T) {
assert.Assert(t, json.Unmarshal(rawPattern, &pattern)) assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
assert.Assert(t, json.Unmarshal(rawMap, &resource)) assert.Assert(t, json.Unmarshal(rawMap, &resource))
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/") path, err := validateResourceElement(resource, pattern, pattern, "/")
assert.Equal(t, path, "") assert.Equal(t, path, "")
assert.Assert(t, err == nil) assert.Assert(t, err == nil)
} }
@ -1151,7 +1149,7 @@ func TestValidateMap_AbsolutePathToMetadata(t *testing.T) {
assert.Assert(t, json.Unmarshal(rawPattern, &pattern)) assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
assert.Assert(t, json.Unmarshal(rawMap, &resource)) assert.Assert(t, json.Unmarshal(rawMap, &resource))
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/") path, err := validateResourceElement(resource, pattern, pattern, "/")
assert.Equal(t, path, "") assert.Equal(t, path, "")
assert.Assert(t, err == nil) assert.Assert(t, err == nil)
} }
@ -1193,7 +1191,7 @@ func TestValidateMap_AbsolutePathToMetadata_fail(t *testing.T) {
assert.Assert(t, json.Unmarshal(rawPattern, &pattern)) assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
assert.Assert(t, json.Unmarshal(rawMap, &resource)) assert.Assert(t, json.Unmarshal(rawMap, &resource))
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/") path, err := validateResourceElement(resource, pattern, pattern, "/")
assert.Equal(t, path, "/spec/containers/0/image/") assert.Equal(t, path, "/spec/containers/0/image/")
assert.Assert(t, err != nil) assert.Assert(t, err != nil)
} }
@ -1247,7 +1245,7 @@ func TestValidateMap_AbosolutePathDoesNotExists(t *testing.T) {
assert.Assert(t, json.Unmarshal(rawPattern, &pattern)) assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
assert.Assert(t, json.Unmarshal(rawMap, &resource)) assert.Assert(t, json.Unmarshal(rawMap, &resource))
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/") path, err := validateResourceElement(resource, pattern, pattern, "/")
assert.Equal(t, path, "/spec/containers/0/resources/requests/memory/") assert.Equal(t, path, "/spec/containers/0/resources/requests/memory/")
assert.Assert(t, err != nil) assert.Assert(t, err != nil)
} }
@ -1278,7 +1276,7 @@ func TestActualizePattern_GivenRelativePathThatExists(t *testing.T) {
assert.Assert(t, json.Unmarshal(rawPattern, &pattern)) assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
pattern, err := actualizePattern(log.Log, pattern, referencePath, absolutePath) pattern, err := actualizePattern(pattern, referencePath, absolutePath)
assert.Assert(t, err == nil) assert.Assert(t, err == nil)
} }
@ -1346,12 +1344,10 @@ func TestValidateMapElement_OneElementInArrayNotPass(t *testing.T) {
]`) ]`)
var pattern, resource interface{} var pattern, resource interface{}
err := json.Unmarshal(rawPattern, &pattern) json.Unmarshal(rawPattern, &pattern)
assert.NilError(t, err) json.Unmarshal(rawMap, &resource)
err = json.Unmarshal(rawMap, &resource)
assert.NilError(t, err)
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/") path, err := validateResourceElement(resource, pattern, pattern, "/")
assert.Equal(t, path, "/0/object/0/key2/") assert.Equal(t, path, "/0/object/0/key2/")
assert.Assert(t, err != nil) assert.Assert(t, err != nil)
} }

View file

@ -5,7 +5,7 @@ import (
"reflect" "reflect"
"time" "time"
"github.com/go-logr/logr" "github.com/golang/glog"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1" kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
"github.com/nirmata/kyverno/pkg/engine/context" "github.com/nirmata/kyverno/pkg/engine/context"
"github.com/nirmata/kyverno/pkg/engine/response" "github.com/nirmata/kyverno/pkg/engine/response"
@ -13,7 +13,6 @@ import (
"github.com/nirmata/kyverno/pkg/engine/validate" "github.com/nirmata/kyverno/pkg/engine/validate"
"github.com/nirmata/kyverno/pkg/engine/variables" "github.com/nirmata/kyverno/pkg/engine/variables"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"sigs.k8s.io/controller-runtime/pkg/log"
) )
//Validate applies validation rules from policy on the resource //Validate applies validation rules from policy on the resource
@ -24,18 +23,17 @@ func Validate(policyContext PolicyContext) (resp response.EngineResponse) {
oldR := policyContext.OldResource oldR := policyContext.OldResource
ctx := policyContext.Context ctx := policyContext.Context
admissionInfo := policyContext.AdmissionInfo admissionInfo := policyContext.AdmissionInfo
logger := log.Log.WithName("Validate").WithValues("policy", policy.Name, "kind", newR.GetKind(), "namespace", newR.GetNamespace(), "name", newR.GetName())
// policy information // policy information
logger.V(4).Info("start processing", "startTime", startTime) glog.V(4).Infof("started applying validation rules of policy %q (%v)", policy.Name, startTime)
// Process new & old resource // Process new & old resource
if reflect.DeepEqual(oldR, unstructured.Unstructured{}) { if reflect.DeepEqual(oldR, unstructured.Unstructured{}) {
// Create Mode // Create Mode
// Operate on New Resource only // Operate on New Resource only
resp := validateResource(logger, ctx, policy, newR, admissionInfo) resp := validateResource(ctx, policy, newR, admissionInfo)
startResultResponse(resp, policy, newR) startResultResponse(resp, policy, newR)
defer endResultResponse(logger, resp, startTime) defer endResultResponse(resp, startTime)
// set PatchedResource with origin resource if empty // set PatchedResource with origin resource if empty
// in order to create policy violation // in order to create policy violation
if reflect.DeepEqual(resp.PatchedResource, unstructured.Unstructured{}) { if reflect.DeepEqual(resp.PatchedResource, unstructured.Unstructured{}) {
@ -46,14 +44,14 @@ func Validate(policyContext PolicyContext) (resp response.EngineResponse) {
// Update Mode // Update Mode
// Operate on New and Old Resource only // Operate on New and Old Resource only
// New resource // New resource
oldResponse := validateResource(logger, ctx, policy, oldR, admissionInfo) oldResponse := validateResource(ctx, policy, oldR, admissionInfo)
newResponse := validateResource(logger, ctx, policy, newR, admissionInfo) newResponse := validateResource(ctx, policy, newR, admissionInfo)
// if the old and new response is same then return empty response // if the old and new response is same then return empty response
if !isSameResponse(oldResponse, newResponse) { if !isSameResponse(oldResponse, newResponse) {
// there are changes send response // there are changes send response
startResultResponse(newResponse, policy, newR) startResultResponse(newResponse, policy, newR)
defer endResultResponse(logger, newResponse, startTime) defer endResultResponse(newResponse, startTime)
if reflect.DeepEqual(newResponse.PatchedResource, unstructured.Unstructured{}) { if reflect.DeepEqual(newResponse.PatchedResource, unstructured.Unstructured{}) {
newResponse.PatchedResource = newR newResponse.PatchedResource = newR
} }
@ -75,9 +73,10 @@ func startResultResponse(resp *response.EngineResponse, policy kyverno.ClusterPo
resp.PolicyResponse.ValidationFailureAction = policy.Spec.ValidationFailureAction resp.PolicyResponse.ValidationFailureAction = policy.Spec.ValidationFailureAction
} }
func endResultResponse(log logr.Logger, resp *response.EngineResponse, startTime time.Time) { func endResultResponse(resp *response.EngineResponse, startTime time.Time) {
resp.PolicyResponse.ProcessingTime = time.Since(startTime) resp.PolicyResponse.ProcessingTime = time.Since(startTime)
log.V(4).Info("finshed processing", "processingTime", resp.PolicyResponse.ProcessingTime, "validationRulesApplied", resp.PolicyResponse.RulesAppliedCount) glog.V(4).Infof("Finished applying validation rules policy %v (%v)", resp.PolicyResponse.Policy, resp.PolicyResponse.ProcessingTime)
glog.V(4).Infof("Validation Rules appplied successfully count %v for policy %q", resp.PolicyResponse.RulesAppliedCount, resp.PolicyResponse.Policy)
} }
func incrementAppliedCount(resp *response.EngineResponse) { func incrementAppliedCount(resp *response.EngineResponse) {
@ -85,18 +84,20 @@ func incrementAppliedCount(resp *response.EngineResponse) {
resp.PolicyResponse.RulesAppliedCount++ resp.PolicyResponse.RulesAppliedCount++
} }
func validateResource(log logr.Logger, ctx context.EvalInterface, policy kyverno.ClusterPolicy, resource unstructured.Unstructured, admissionInfo kyverno.RequestInfo) *response.EngineResponse { func validateResource(ctx context.EvalInterface, policy kyverno.ClusterPolicy, resource unstructured.Unstructured, admissionInfo kyverno.RequestInfo) *response.EngineResponse {
resp := &response.EngineResponse{} resp := &response.EngineResponse{}
for _, rule := range policy.Spec.Rules { for _, rule := range policy.Spec.Rules {
if !rule.HasValidate() { if !rule.HasValidate() {
continue continue
} }
startTime := time.Now()
glog.V(4).Infof("Time: Validate matchAdmissionInfo %v", time.Since(startTime))
// check if the resource satisfies the filter conditions defined in the rule // check if the resource satisfies the filter conditions defined in the rule
// TODO: this needs to be extracted, to filter the resource so that we can avoid passing resources that // TODO: this needs to be extracted, to filter the resource so that we can avoid passing resources that
// dont statisfy a policy rule resource description // dont statisfy a policy rule resource description
if err := MatchesResourceDescription(resource, rule, admissionInfo); err != nil { if err := MatchesResourceDescription(resource, rule, admissionInfo); err != nil {
log.V(4).Info("resource fails the match description") glog.V(4).Infof("resource %s/%s does not satisfy the resource description for the rule:\n%s", resource.GetNamespace(), resource.GetName(), err.Error())
continue continue
} }
@ -104,13 +105,13 @@ func validateResource(log logr.Logger, ctx context.EvalInterface, policy kyverno
copyConditions := copyConditions(rule.Conditions) copyConditions := copyConditions(rule.Conditions)
// evaluate pre-conditions // evaluate pre-conditions
// - handle variable subsitutions // - handle variable subsitutions
if !variables.EvaluateConditions(log, ctx, copyConditions) { if !variables.EvaluateConditions(ctx, copyConditions) {
log.V(4).Info("resource fails the preconditions") glog.V(4).Infof("resource %s/%s does not satisfy the conditions for the rule ", resource.GetNamespace(), resource.GetName())
continue continue
} }
if rule.Validation.Pattern != nil || rule.Validation.AnyPattern != nil { if rule.Validation.Pattern != nil || rule.Validation.AnyPattern != nil {
ruleResponse := validatePatterns(log, ctx, resource, rule) ruleResponse := validatePatterns(ctx, resource, rule)
incrementAppliedCount(resp) incrementAppliedCount(resp)
resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, ruleResponse) resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, ruleResponse)
} }
@ -158,15 +159,14 @@ func isSameRules(oldRules []response.RuleResponse, newRules []response.RuleRespo
} }
// validatePatterns validate pattern and anyPattern // validatePatterns validate pattern and anyPattern
func validatePatterns(log logr.Logger, ctx context.EvalInterface, resource unstructured.Unstructured, rule kyverno.Rule) (resp response.RuleResponse) { func validatePatterns(ctx context.EvalInterface, resource unstructured.Unstructured, rule kyverno.Rule) (resp response.RuleResponse) {
startTime := time.Now() startTime := time.Now()
logger := log.WithValues("rule", rule.Name) glog.V(4).Infof("started applying validation rule %q (%v)", rule.Name, startTime)
logger.V(4).Info("start processing rule", "startTime", startTime)
resp.Name = rule.Name resp.Name = rule.Name
resp.Type = utils.Validation.String() resp.Type = utils.Validation.String()
defer func() { defer func() {
resp.RuleStats.ProcessingTime = time.Since(startTime) resp.RuleStats.ProcessingTime = time.Since(startTime)
logger.V(4).Info("finshed processing", "processingTime", resp.RuleStats.ProcessingTime) glog.V(4).Infof("finished applying validation rule %q (%v)", resp.Name, resp.RuleStats.ProcessingTime)
}() }()
// work on a copy of validation rule // work on a copy of validation rule
validationRule := rule.Validation.DeepCopy() validationRule := rule.Validation.DeepCopy()
@ -176,7 +176,7 @@ func validatePatterns(log logr.Logger, ctx context.EvalInterface, resource unstr
// substitute variables in the pattern // substitute variables in the pattern
pattern := validationRule.Pattern pattern := validationRule.Pattern
var err error var err error
if pattern, err = variables.SubstituteVars(logger, ctx, pattern); err != nil { if pattern, err = variables.SubstituteVars(ctx, pattern); err != nil {
// variable subsitution failed // variable subsitution failed
resp.Success = false resp.Success = false
resp.Message = fmt.Sprintf("Validation error: %s; Validation rule '%s' failed. '%s'", resp.Message = fmt.Sprintf("Validation error: %s; Validation rule '%s' failed. '%s'",
@ -184,7 +184,7 @@ func validatePatterns(log logr.Logger, ctx context.EvalInterface, resource unstr
return resp return resp
} }
if path, err := validate.ValidateResourceWithPattern(logger, resource.Object, pattern); err != nil { if path, err := validate.ValidateResourceWithPattern(resource.Object, pattern); err != nil {
// validation failed // validation failed
resp.Success = false resp.Success = false
resp.Message = fmt.Sprintf("Validation error: %s; Validation rule '%s' failed at path '%s'", resp.Message = fmt.Sprintf("Validation error: %s; Validation rule '%s' failed at path '%s'",
@ -192,7 +192,7 @@ func validatePatterns(log logr.Logger, ctx context.EvalInterface, resource unstr
return resp return resp
} }
// rule application successful // rule application successful
logger.V(4).Info("successfully processed rule") glog.V(4).Infof("rule %s pattern validated successfully on resource %s/%s/%s", rule.Name, resource.GetKind(), resource.GetNamespace(), resource.GetName())
resp.Success = true resp.Success = true
resp.Message = fmt.Sprintf("Validation rule '%s' succeeded.", rule.Name) resp.Message = fmt.Sprintf("Validation rule '%s' succeeded.", rule.Name)
return resp return resp
@ -203,18 +203,19 @@ func validatePatterns(log logr.Logger, ctx context.EvalInterface, resource unstr
var failedAnyPatternsErrors []error var failedAnyPatternsErrors []error
var err error var err error
for idx, pattern := range validationRule.AnyPattern { for idx, pattern := range validationRule.AnyPattern {
if pattern, err = variables.SubstituteVars(logger, ctx, pattern); err != nil { if pattern, err = variables.SubstituteVars(ctx, pattern); err != nil {
// variable subsitution failed // variable subsitution failed
failedSubstitutionsErrors = append(failedSubstitutionsErrors, err) failedSubstitutionsErrors = append(failedSubstitutionsErrors, err)
continue continue
} }
_, err := validate.ValidateResourceWithPattern(logger, resource.Object, pattern) _, err := validate.ValidateResourceWithPattern(resource.Object, pattern)
if err == nil { if err == nil {
resp.Success = true resp.Success = true
resp.Message = fmt.Sprintf("Validation rule '%s' anyPattern[%d] succeeded.", rule.Name, idx) resp.Message = fmt.Sprintf("Validation rule '%s' anyPattern[%d] succeeded.", rule.Name, idx)
return resp return resp
} }
logger.V(4).Info(fmt.Sprintf("validation rule failed for anyPattern[%d]", idx), "message", rule.Validation.Message) glog.V(4).Infof("Validation error: %s; Validation rule %s anyPattern[%d] for %s/%s/%s",
rule.Validation.Message, rule.Name, idx, resource.GetKind(), resource.GetNamespace(), resource.GetName())
patternErr := fmt.Errorf("anyPattern[%d] failed; %s", idx, err) patternErr := fmt.Errorf("anyPattern[%d] failed; %s", idx, err)
failedAnyPatternsErrors = append(failedAnyPatternsErrors, patternErr) failedAnyPatternsErrors = append(failedAnyPatternsErrors, patternErr)
} }
@ -233,7 +234,7 @@ func validatePatterns(log logr.Logger, ctx context.EvalInterface, resource unstr
errorStr = append(errorStr, err.Error()) errorStr = append(errorStr, err.Error())
} }
resp.Success = false resp.Success = false
log.V(4).Info(fmt.Sprintf("Validation rule '%s' failed. %s", rule.Name, errorStr)) glog.V(4).Infof("Validation rule '%s' failed. %s", rule.Name, errorStr)
if rule.Validation.Message == "" { if rule.Validation.Message == "" {
resp.Message = fmt.Sprintf("Validation rule '%s' has failed", rule.Name) resp.Message = fmt.Sprintf("Validation rule '%s' has failed", rule.Name)
} else { } else {

View file

@ -23,8 +23,7 @@ func TestGetAnchorsFromMap_ThereAreAnchors(t *testing.T) {
}`) }`)
var unmarshalled map[string]interface{} var unmarshalled map[string]interface{}
err := json.Unmarshal(rawMap, &unmarshalled) json.Unmarshal(rawMap, &unmarshalled)
assert.NilError(t, err)
actualMap := utils.GetAnchorsFromMap(unmarshalled) actualMap := utils.GetAnchorsFromMap(unmarshalled)
assert.Equal(t, len(actualMap), 2) assert.Equal(t, len(actualMap), 2)
@ -115,8 +114,7 @@ func TestValidate_image_tag_fail(t *testing.T) {
`) `)
var policy kyverno.ClusterPolicy var policy kyverno.ClusterPolicy
err := json.Unmarshal(rawPolicy, &policy) json.Unmarshal(rawPolicy, &policy)
assert.NilError(t, err)
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource) resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err) assert.NilError(t, err)
@ -214,8 +212,7 @@ func TestValidate_image_tag_pass(t *testing.T) {
`) `)
var policy kyverno.ClusterPolicy var policy kyverno.ClusterPolicy
err := json.Unmarshal(rawPolicy, &policy) json.Unmarshal(rawPolicy, &policy)
assert.NilError(t, err)
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource) resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err) assert.NilError(t, err)
@ -292,8 +289,7 @@ func TestValidate_Fail_anyPattern(t *testing.T) {
`) `)
var policy kyverno.ClusterPolicy var policy kyverno.ClusterPolicy
err := json.Unmarshal(rawPolicy, &policy) json.Unmarshal(rawPolicy, &policy)
assert.NilError(t, err)
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource) resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err) assert.NilError(t, err)
@ -374,8 +370,7 @@ func TestValidate_host_network_port(t *testing.T) {
`) `)
var policy kyverno.ClusterPolicy var policy kyverno.ClusterPolicy
err := json.Unmarshal(rawPolicy, &policy) json.Unmarshal(rawPolicy, &policy)
assert.NilError(t, err)
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource) resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err) assert.NilError(t, err)
@ -464,8 +459,7 @@ func TestValidate_anchor_arraymap_pass(t *testing.T) {
} `) } `)
var policy kyverno.ClusterPolicy var policy kyverno.ClusterPolicy
err := json.Unmarshal(rawPolicy, &policy) json.Unmarshal(rawPolicy, &policy)
assert.NilError(t, err)
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource) resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err) assert.NilError(t, err)
@ -553,8 +547,8 @@ func TestValidate_anchor_arraymap_fail(t *testing.T) {
} `) } `)
var policy kyverno.ClusterPolicy var policy kyverno.ClusterPolicy
err := json.Unmarshal(rawPolicy, &policy) json.Unmarshal(rawPolicy, &policy)
assert.NilError(t, err)
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource) resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err) assert.NilError(t, err)
er := Validate(PolicyContext{Policy: policy, NewResource: *resourceUnstructured}) er := Validate(PolicyContext{Policy: policy, NewResource: *resourceUnstructured})
@ -622,8 +616,7 @@ func TestValidate_anchor_map_notfound(t *testing.T) {
`) `)
var policy kyverno.ClusterPolicy var policy kyverno.ClusterPolicy
err := json.Unmarshal(rawPolicy, &policy) json.Unmarshal(rawPolicy, &policy)
assert.NilError(t, err)
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource) resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err) assert.NilError(t, err)
@ -695,8 +688,7 @@ func TestValidate_anchor_map_found_valid(t *testing.T) {
`) `)
var policy kyverno.ClusterPolicy var policy kyverno.ClusterPolicy
err := json.Unmarshal(rawPolicy, &policy) json.Unmarshal(rawPolicy, &policy)
assert.NilError(t, err)
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource) resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err) assert.NilError(t, err)
@ -768,8 +760,7 @@ func TestValidate_anchor_map_found_invalid(t *testing.T) {
`) `)
var policy kyverno.ClusterPolicy var policy kyverno.ClusterPolicy
err := json.Unmarshal(rawPolicy, &policy) json.Unmarshal(rawPolicy, &policy)
assert.NilError(t, err)
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource) resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err) assert.NilError(t, err)
@ -843,8 +834,7 @@ func TestValidate_AnchorList_pass(t *testing.T) {
`) `)
var policy kyverno.ClusterPolicy var policy kyverno.ClusterPolicy
err := json.Unmarshal(rawPolicy, &policy) json.Unmarshal(rawPolicy, &policy)
assert.NilError(t, err)
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource) resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err) assert.NilError(t, err)
@ -918,8 +908,7 @@ func TestValidate_AnchorList_fail(t *testing.T) {
`) `)
var policy kyverno.ClusterPolicy var policy kyverno.ClusterPolicy
err := json.Unmarshal(rawPolicy, &policy) json.Unmarshal(rawPolicy, &policy)
assert.NilError(t, err)
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource) resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err) assert.NilError(t, err)
@ -993,8 +982,7 @@ func TestValidate_existenceAnchor_fail(t *testing.T) {
`) `)
var policy kyverno.ClusterPolicy var policy kyverno.ClusterPolicy
err := json.Unmarshal(rawPolicy, &policy) json.Unmarshal(rawPolicy, &policy)
assert.NilError(t, err)
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource) resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err) assert.NilError(t, err)
@ -1069,8 +1057,7 @@ func TestValidate_existenceAnchor_pass(t *testing.T) {
`) `)
var policy kyverno.ClusterPolicy var policy kyverno.ClusterPolicy
err := json.Unmarshal(rawPolicy, &policy) json.Unmarshal(rawPolicy, &policy)
assert.NilError(t, err)
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource) resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err) assert.NilError(t, err)
@ -1157,8 +1144,7 @@ func TestValidate_negationAnchor_deny(t *testing.T) {
} `) } `)
var policy kyverno.ClusterPolicy var policy kyverno.ClusterPolicy
err := json.Unmarshal(rawPolicy, &policy) json.Unmarshal(rawPolicy, &policy)
assert.NilError(t, err)
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource) resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err) assert.NilError(t, err)
@ -1244,8 +1230,7 @@ func TestValidate_negationAnchor_pass(t *testing.T) {
`) `)
var policy kyverno.ClusterPolicy var policy kyverno.ClusterPolicy
err := json.Unmarshal(rawPolicy, &policy) json.Unmarshal(rawPolicy, &policy)
assert.NilError(t, err)
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource) resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err) assert.NilError(t, err)
@ -1312,14 +1297,12 @@ func Test_VariableSubstitutionPathNotExistInPattern(t *testing.T) {
}`) }`)
var policy kyverno.ClusterPolicy var policy kyverno.ClusterPolicy
err := json.Unmarshal(policyraw, &policy) json.Unmarshal(policyraw, &policy)
assert.NilError(t, err)
resourceUnstructured, err := utils.ConvertToUnstructured(resourceRaw) resourceUnstructured, err := utils.ConvertToUnstructured(resourceRaw)
assert.NilError(t, err) assert.NilError(t, err)
ctx := context.NewContext() ctx := context.NewContext()
err = ctx.AddResource(resourceRaw) ctx.AddResource(resourceRaw)
assert.NilError(t, err)
policyContext := PolicyContext{ policyContext := PolicyContext{
Policy: policy, Policy: policy,
@ -1409,8 +1392,7 @@ func Test_VariableSubstitutionPathNotExistInAnyPattern_OnePatternStatisfies(t *t
assert.NilError(t, err) assert.NilError(t, err)
ctx := context.NewContext() ctx := context.NewContext()
err = ctx.AddResource(resourceRaw) ctx.AddResource(resourceRaw)
assert.NilError(t, err)
policyContext := PolicyContext{ policyContext := PolicyContext{
Policy: policy, Policy: policy,
@ -1500,8 +1482,7 @@ func Test_VariableSubstitutionPathNotExistInAnyPattern_AllPathNotPresent(t *test
assert.NilError(t, err) assert.NilError(t, err)
ctx := context.NewContext() ctx := context.NewContext()
err = ctx.AddResource(resourceRaw) ctx.AddResource(resourceRaw)
assert.NilError(t, err)
policyContext := PolicyContext{ policyContext := PolicyContext{
Policy: policy, Policy: policy,
@ -1591,8 +1572,7 @@ func Test_VariableSubstitutionPathNotExistInAnyPattern_AllPathPresent_NonePatter
assert.NilError(t, err) assert.NilError(t, err)
ctx := context.NewContext() ctx := context.NewContext()
err = ctx.AddResource(resourceRaw) ctx.AddResource(resourceRaw)
assert.NilError(t, err)
policyContext := PolicyContext{ policyContext := PolicyContext{
Policy: policy, Policy: policy,

View file

@ -1,10 +0,0 @@
package variables
import "regexp"
//IsVariable returns true if the element contains a 'valid' variable {{}}
func IsVariable(element string) bool {
validRegex := regexp.MustCompile(variableRegex)
groups := validRegex.FindAllStringSubmatch(element, -1)
return len(groups) != 0
}

View file

@ -1,16 +1,16 @@
package variables package variables
import ( import (
"github.com/go-logr/logr" "github.com/golang/glog"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1" kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
"github.com/nirmata/kyverno/pkg/engine/context" "github.com/nirmata/kyverno/pkg/engine/context"
"github.com/nirmata/kyverno/pkg/engine/variables/operator" "github.com/nirmata/kyverno/pkg/engine/variables/operator"
) )
//Evaluate evaluates the condition //Evaluate evaluates the condition
func Evaluate(log logr.Logger, ctx context.EvalInterface, condition kyverno.Condition) bool { func Evaluate(ctx context.EvalInterface, condition kyverno.Condition) bool {
// get handler for the operator // get handler for the operator
handle := operator.CreateOperatorHandler(log, ctx, condition.Operator, SubstituteVars) handle := operator.CreateOperatorHandler(ctx, condition.Operator, SubstituteVars)
if handle == nil { if handle == nil {
return false return false
} }
@ -18,10 +18,11 @@ func Evaluate(log logr.Logger, ctx context.EvalInterface, condition kyverno.Cond
} }
//EvaluateConditions evaluates multiple conditions //EvaluateConditions evaluates multiple conditions
func EvaluateConditions(log logr.Logger, ctx context.EvalInterface, conditions []kyverno.Condition) bool { func EvaluateConditions(ctx context.EvalInterface, conditions []kyverno.Condition) bool {
// AND the conditions // AND the conditions
for _, condition := range conditions { for _, condition := range conditions {
if !Evaluate(log, ctx, condition) { if !Evaluate(ctx, condition) {
glog.V(4).Infof("condition %v failed", condition)
return false return false
} }
} }

View file

@ -6,7 +6,6 @@ import (
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1" kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
"github.com/nirmata/kyverno/pkg/engine/context" "github.com/nirmata/kyverno/pkg/engine/context"
"sigs.k8s.io/controller-runtime/pkg/log"
) )
// STRINGS // STRINGS
@ -19,7 +18,7 @@ func Test_Eval_Equal_Const_String_Pass(t *testing.T) {
Value: "name", Value: "name",
} }
if !Evaluate(log.Log, ctx, condition) { if !Evaluate(ctx, condition) {
t.Error("expected to pass") t.Error("expected to pass")
} }
} }
@ -33,7 +32,7 @@ func Test_Eval_Equal_Const_String_Fail(t *testing.T) {
Value: "name1", Value: "name1",
} }
if Evaluate(log.Log, ctx, condition) { if Evaluate(ctx, condition) {
t.Error("expected to fail") t.Error("expected to fail")
} }
} }
@ -47,7 +46,7 @@ func Test_Eval_NoEqual_Const_String_Pass(t *testing.T) {
Value: "name1", Value: "name1",
} }
if !Evaluate(log.Log, ctx, condition) { if !Evaluate(ctx, condition) {
t.Error("expected to pass") t.Error("expected to pass")
} }
} }
@ -61,7 +60,7 @@ func Test_Eval_NoEqual_Const_String_Fail(t *testing.T) {
Value: "name", Value: "name",
} }
if Evaluate(log.Log, ctx, condition) { if Evaluate(ctx, condition) {
t.Error("expected to fail") t.Error("expected to fail")
} }
} }
@ -77,7 +76,7 @@ func Test_Eval_Equal_Const_Bool_Pass(t *testing.T) {
Value: true, Value: true,
} }
if !Evaluate(log.Log, ctx, condition) { if !Evaluate(ctx, condition) {
t.Error("expected to pass") t.Error("expected to pass")
} }
} }
@ -91,7 +90,7 @@ func Test_Eval_Equal_Const_Bool_Fail(t *testing.T) {
Value: false, Value: false,
} }
if Evaluate(log.Log, ctx, condition) { if Evaluate(ctx, condition) {
t.Error("expected to fail") t.Error("expected to fail")
} }
} }
@ -105,7 +104,7 @@ func Test_Eval_NoEqual_Const_Bool_Pass(t *testing.T) {
Value: false, Value: false,
} }
if !Evaluate(log.Log, ctx, condition) { if !Evaluate(ctx, condition) {
t.Error("expected to pass") t.Error("expected to pass")
} }
} }
@ -119,7 +118,7 @@ func Test_Eval_NoEqual_Const_Bool_Fail(t *testing.T) {
Value: true, Value: true,
} }
if Evaluate(log.Log, ctx, condition) { if Evaluate(ctx, condition) {
t.Error("expected to fail") t.Error("expected to fail")
} }
} }
@ -134,7 +133,7 @@ func Test_Eval_Equal_Const_int_Pass(t *testing.T) {
Value: 1, Value: 1,
} }
if !Evaluate(log.Log, ctx, condition) { if !Evaluate(ctx, condition) {
t.Error("expected to pass") t.Error("expected to pass")
} }
} }
@ -148,7 +147,7 @@ func Test_Eval_Equal_Const_int_Fail(t *testing.T) {
Value: 2, Value: 2,
} }
if Evaluate(log.Log, ctx, condition) { if Evaluate(ctx, condition) {
t.Error("expected to fail") t.Error("expected to fail")
} }
} }
@ -162,7 +161,7 @@ func Test_Eval_NoEqual_Const_int_Pass(t *testing.T) {
Value: 2, Value: 2,
} }
if !Evaluate(log.Log, ctx, condition) { if !Evaluate(ctx, condition) {
t.Error("expected to pass") t.Error("expected to pass")
} }
} }
@ -176,7 +175,7 @@ func Test_Eval_NoEqual_Const_int_Fail(t *testing.T) {
Value: 1, Value: 1,
} }
if Evaluate(log.Log, ctx, condition) { if Evaluate(ctx, condition) {
t.Error("expected to fail") t.Error("expected to fail")
} }
} }
@ -191,7 +190,7 @@ func Test_Eval_Equal_Const_int64_Pass(t *testing.T) {
Value: int64(1), Value: int64(1),
} }
if !Evaluate(log.Log, ctx, condition) { if !Evaluate(ctx, condition) {
t.Error("expected to pass") t.Error("expected to pass")
} }
} }
@ -205,7 +204,7 @@ func Test_Eval_Equal_Const_int64_Fail(t *testing.T) {
Value: int64(2), Value: int64(2),
} }
if Evaluate(log.Log, ctx, condition) { if Evaluate(ctx, condition) {
t.Error("expected to fail") t.Error("expected to fail")
} }
} }
@ -219,7 +218,7 @@ func Test_Eval_NoEqual_Const_int64_Pass(t *testing.T) {
Value: int64(2), Value: int64(2),
} }
if !Evaluate(log.Log, ctx, condition) { if !Evaluate(ctx, condition) {
t.Error("expected to pass") t.Error("expected to pass")
} }
} }
@ -233,7 +232,7 @@ func Test_Eval_NoEqual_Const_int64_Fail(t *testing.T) {
Value: int64(1), Value: int64(1),
} }
if Evaluate(log.Log, ctx, condition) { if Evaluate(ctx, condition) {
t.Error("expected to fail") t.Error("expected to fail")
} }
} }
@ -249,7 +248,7 @@ func Test_Eval_Equal_Const_float64_Pass(t *testing.T) {
Value: 1.5, Value: 1.5,
} }
if !Evaluate(log.Log, ctx, condition) { if !Evaluate(ctx, condition) {
t.Error("expected to pass") t.Error("expected to pass")
} }
} }
@ -263,7 +262,7 @@ func Test_Eval_Equal_Const_float64_Fail(t *testing.T) {
Value: 1.6, Value: 1.6,
} }
if Evaluate(log.Log, ctx, condition) { if Evaluate(ctx, condition) {
t.Error("expected to fail") t.Error("expected to fail")
} }
} }
@ -277,7 +276,7 @@ func Test_Eval_NoEqual_Const_float64_Pass(t *testing.T) {
Value: 1.6, Value: 1.6,
} }
if !Evaluate(log.Log, ctx, condition) { if !Evaluate(ctx, condition) {
t.Error("expected to pass") t.Error("expected to pass")
} }
} }
@ -291,7 +290,7 @@ func Test_Eval_NoEqual_Const_float64_Fail(t *testing.T) {
Value: 1.5, Value: 1.5,
} }
if Evaluate(log.Log, ctx, condition) { if Evaluate(ctx, condition) {
t.Error("expected to fail") t.Error("expected to fail")
} }
} }
@ -321,7 +320,7 @@ func Test_Eval_Equal_Const_object_Pass(t *testing.T) {
Value: obj2, Value: obj2,
} }
if !Evaluate(log.Log, ctx, condition) { if !Evaluate(ctx, condition) {
t.Error("expected to pass") t.Error("expected to pass")
} }
} }
@ -349,7 +348,7 @@ func Test_Eval_Equal_Const_object_Fail(t *testing.T) {
Value: obj2, Value: obj2,
} }
if Evaluate(log.Log, ctx, condition) { if Evaluate(ctx, condition) {
t.Error("expected to fail") t.Error("expected to fail")
} }
} }
@ -377,7 +376,7 @@ func Test_Eval_NotEqual_Const_object_Pass(t *testing.T) {
Value: obj2, Value: obj2,
} }
if !Evaluate(log.Log, ctx, condition) { if !Evaluate(ctx, condition) {
t.Error("expected to pass") t.Error("expected to pass")
} }
} }
@ -405,7 +404,7 @@ func Test_Eval_NotEqual_Const_object_Fail(t *testing.T) {
Value: obj2, Value: obj2,
} }
if Evaluate(log.Log, ctx, condition) { if Evaluate(ctx, condition) {
t.Error("expected to fail") t.Error("expected to fail")
} }
} }
@ -435,7 +434,7 @@ func Test_Eval_Equal_Const_list_Pass(t *testing.T) {
Value: obj2, Value: obj2,
} }
if !Evaluate(log.Log, ctx, condition) { if !Evaluate(ctx, condition) {
t.Error("expected to pass") t.Error("expected to pass")
} }
} }
@ -461,7 +460,7 @@ func Test_Eval_Equal_Const_list_Fail(t *testing.T) {
Value: obj2, Value: obj2,
} }
if Evaluate(log.Log, ctx, condition) { if Evaluate(ctx, condition) {
t.Error("expected to fail") t.Error("expected to fail")
} }
} }
@ -487,7 +486,7 @@ func Test_Eval_NotEqual_Const_list_Pass(t *testing.T) {
Value: obj2, Value: obj2,
} }
if !Evaluate(log.Log, ctx, condition) { if !Evaluate(ctx, condition) {
t.Error("expected to pass") t.Error("expected to pass")
} }
} }
@ -513,7 +512,7 @@ func Test_Eval_NotEqual_Const_list_Fail(t *testing.T) {
Value: obj2, Value: obj2,
} }
if Evaluate(log.Log, ctx, condition) { if Evaluate(ctx, condition) {
t.Error("expected to fail") t.Error("expected to fail")
} }
} }
@ -546,7 +545,7 @@ func Test_Eval_Equal_Var_Pass(t *testing.T) {
Value: "temp", Value: "temp",
} }
if !Evaluate(log.Log, ctx, condition) { if !Evaluate(ctx, condition) {
t.Error("expected to pass") t.Error("expected to pass")
} }
} }
@ -577,7 +576,7 @@ func Test_Eval_Equal_Var_Fail(t *testing.T) {
Value: "temp1", Value: "temp1",
} }
if Evaluate(log.Log, ctx, condition) { if Evaluate(ctx, condition) {
t.Error("expected to fail") t.Error("expected to fail")
} }
} }

View file

@ -1,21 +1,19 @@
package operator package operator
import ( import (
"fmt"
"math" "math"
"reflect" "reflect"
"strconv" "strconv"
"github.com/go-logr/logr" "github.com/golang/glog"
"github.com/nirmata/kyverno/pkg/engine/context" "github.com/nirmata/kyverno/pkg/engine/context"
) )
//NewEqualHandler returns handler to manage Equal operations //NewEqualHandler returns handler to manage Equal operations
func NewEqualHandler(log logr.Logger, ctx context.EvalInterface, subHandler VariableSubstitutionHandler) OperatorHandler { func NewEqualHandler(ctx context.EvalInterface, subHandler VariableSubstitutionHandler) OperatorHandler {
return EqualHandler{ return EqualHandler{
ctx: ctx, ctx: ctx,
subHandler: subHandler, subHandler: subHandler,
log: log,
} }
} }
@ -23,7 +21,6 @@ func NewEqualHandler(log logr.Logger, ctx context.EvalInterface, subHandler Vari
type EqualHandler struct { type EqualHandler struct {
ctx context.EvalInterface ctx context.EvalInterface
subHandler VariableSubstitutionHandler subHandler VariableSubstitutionHandler
log logr.Logger
} }
//Evaluate evaluates expression with Equal Operator //Evaluate evaluates expression with Equal Operator
@ -31,14 +28,14 @@ func (eh EqualHandler) Evaluate(key, value interface{}) bool {
var err error var err error
//TODO: decouple variables from evaluation //TODO: decouple variables from evaluation
// substitute the variables // substitute the variables
if key, err = eh.subHandler(eh.log, eh.ctx, key); err != nil { if key, err = eh.subHandler(eh.ctx, key); err != nil {
// Failed to resolve the variable // Failed to resolve the variable
eh.log.Error(err, "Failed to resolve variable", "variable", key) glog.Infof("Failed to resolve variables in key: %s: %v", key, err)
return false return false
} }
if value, err = eh.subHandler(eh.log, eh.ctx, value); err != nil { if value, err = eh.subHandler(eh.ctx, value); err != nil {
// Failed to resolve the variable // Failed to resolve the variable
eh.log.Error(err, "Failed to resolve variable", "variable", value) glog.Infof("Failed to resolve variables in value: %s: %v", value, err)
return false return false
} }
@ -59,7 +56,7 @@ func (eh EqualHandler) Evaluate(key, value interface{}) bool {
case []interface{}: case []interface{}:
return eh.validateValueWithSlicePattern(typedKey, value) return eh.validateValueWithSlicePattern(typedKey, value)
default: default:
eh.log.Info("Unsupported type", "value", typedKey, "type", fmt.Sprintf("%T", typedKey)) glog.Errorf("Unsupported type %v", typedKey)
return false return false
} }
} }
@ -68,7 +65,7 @@ func (eh EqualHandler) validateValueWithSlicePattern(key []interface{}, value in
if val, ok := value.([]interface{}); ok { if val, ok := value.([]interface{}); ok {
return reflect.DeepEqual(key, val) return reflect.DeepEqual(key, val)
} }
eh.log.Info("Expected type []interface{}", "value", value, "type", fmt.Sprintf("%T", value)) glog.Warningf("Expected []interface{}, %v is of type %T", value, value)
return false return false
} }
@ -76,7 +73,7 @@ func (eh EqualHandler) validateValueWithMapPattern(key map[string]interface{}, v
if val, ok := value.(map[string]interface{}); ok { if val, ok := value.(map[string]interface{}); ok {
return reflect.DeepEqual(key, val) return reflect.DeepEqual(key, val)
} }
eh.log.Info("Expected type map[string]interface{}", "value", value, "type", fmt.Sprintf("%T", value)) glog.Warningf("Expected map[string]interface{}, %v is of type %T", value, value)
return false return false
} }
@ -84,8 +81,7 @@ func (eh EqualHandler) validateValuewithStringPattern(key string, value interfac
if val, ok := value.(string); ok { if val, ok := value.(string); ok {
return key == val return key == val
} }
glog.Warningf("Expected string, %v is of type %T", value, value)
eh.log.Info("Expected type string", "value", value, "type", fmt.Sprintf("%T", value))
return false return false
} }
@ -96,25 +92,25 @@ func (eh EqualHandler) validateValuewithFloatPattern(key float64, value interfac
if key == math.Trunc(key) { if key == math.Trunc(key) {
return int(key) == typedValue return int(key) == typedValue
} }
eh.log.Info("Expected type float, found int", "typedValue", typedValue) glog.Warningf("Expected float, found int: %d\n", typedValue)
case int64: case int64:
// check that float has not fraction // check that float has not fraction
if key == math.Trunc(key) { if key == math.Trunc(key) {
return int64(key) == typedValue return int64(key) == typedValue
} }
eh.log.Info("Expected type float, found int", "typedValue", typedValue) glog.Warningf("Expected float, found int: %d\n", typedValue)
case float64: case float64:
return typedValue == key return typedValue == key
case string: case string:
// extract float from string // extract float from string
float64Num, err := strconv.ParseFloat(typedValue, 64) float64Num, err := strconv.ParseFloat(typedValue, 64)
if err != nil { if err != nil {
eh.log.Error(err, "Failed to parse float64 from string") glog.Warningf("Failed to parse float64 from string: %v", err)
return false return false
} }
return float64Num == key return float64Num == key
default: default:
eh.log.Info("Expected type float", "value", value, "type", fmt.Sprintf("%T", value)) glog.Warningf("Expected float, found: %T\n", value)
return false return false
} }
return false return false
@ -123,7 +119,7 @@ func (eh EqualHandler) validateValuewithFloatPattern(key float64, value interfac
func (eh EqualHandler) validateValuewithBoolPattern(key bool, value interface{}) bool { func (eh EqualHandler) validateValuewithBoolPattern(key bool, value interface{}) bool {
typedValue, ok := value.(bool) typedValue, ok := value.(bool)
if !ok { if !ok {
eh.log.Info("Expected type bool", "value", value, "type", fmt.Sprintf("%T", value)) glog.Error("Expected bool, found %V", value)
return false return false
} }
return key == typedValue return key == typedValue
@ -140,18 +136,18 @@ func (eh EqualHandler) validateValuewithIntPattern(key int64, value interface{})
if typedValue == math.Trunc(typedValue) { if typedValue == math.Trunc(typedValue) {
return int64(typedValue) == key return int64(typedValue) == key
} }
eh.log.Info("Expected type int, found float", "value", typedValue, "type", fmt.Sprintf("%T", typedValue)) glog.Warningf("Expected int, found float: %f", typedValue)
return false return false
case string: case string:
// extract in64 from string // extract in64 from string
int64Num, err := strconv.ParseInt(typedValue, 10, 64) int64Num, err := strconv.ParseInt(typedValue, 10, 64)
if err != nil { if err != nil {
eh.log.Error(err, "Failed to parse int64 from string") glog.Warningf("Failed to parse int64 from string: %v", err)
return false return false
} }
return int64Num == key return int64Num == key
default: default:
eh.log.Info("Expected type int", "value", value, "type", fmt.Sprintf("%T", value)) glog.Warningf("Expected int, %v is of type %T", value, value)
return false return false
} }
} }

View file

@ -1,21 +1,19 @@
package operator package operator
import ( import (
"fmt"
"math" "math"
"reflect" "reflect"
"strconv" "strconv"
"github.com/go-logr/logr" "github.com/golang/glog"
"github.com/nirmata/kyverno/pkg/engine/context" "github.com/nirmata/kyverno/pkg/engine/context"
) )
//NewNotEqualHandler returns handler to manage NotEqual operations //NewNotEqualHandler returns handler to manage NotEqual operations
func NewNotEqualHandler(log logr.Logger, ctx context.EvalInterface, subHandler VariableSubstitutionHandler) OperatorHandler { func NewNotEqualHandler(ctx context.EvalInterface, subHandler VariableSubstitutionHandler) OperatorHandler {
return NotEqualHandler{ return NotEqualHandler{
ctx: ctx, ctx: ctx,
subHandler: subHandler, subHandler: subHandler,
log: log,
} }
} }
@ -23,7 +21,6 @@ func NewNotEqualHandler(log logr.Logger, ctx context.EvalInterface, subHandler V
type NotEqualHandler struct { type NotEqualHandler struct {
ctx context.EvalInterface ctx context.EvalInterface
subHandler VariableSubstitutionHandler subHandler VariableSubstitutionHandler
log logr.Logger
} }
//Evaluate evaluates expression with NotEqual Operator //Evaluate evaluates expression with NotEqual Operator
@ -31,14 +28,14 @@ func (neh NotEqualHandler) Evaluate(key, value interface{}) bool {
var err error var err error
//TODO: decouple variables from evaluation //TODO: decouple variables from evaluation
// substitute the variables // substitute the variables
if key, err = neh.subHandler(neh.log, neh.ctx, key); err != nil { if key, err = neh.subHandler(neh.ctx, key); err != nil {
// Failed to resolve the variable // Failed to resolve the variable
neh.log.Error(err, "Failed to resolve variable", "variable", key) glog.Infof("Failed to resolve variables in key: %s: %v", key, err)
return false return false
} }
if value, err = neh.subHandler(neh.log, neh.ctx, value); err != nil { if value, err = neh.subHandler(neh.ctx, value); err != nil {
// Failed to resolve the variable // Failed to resolve the variable
neh.log.Error(err, "Failed to resolve variable", "variable", value) glog.Infof("Failed to resolve variables in value: %s: %v", value, err)
return false return false
} }
// key and value need to be of same type // key and value need to be of same type
@ -58,7 +55,7 @@ func (neh NotEqualHandler) Evaluate(key, value interface{}) bool {
case []interface{}: case []interface{}:
return neh.validateValueWithSlicePattern(typedKey, value) return neh.validateValueWithSlicePattern(typedKey, value)
default: default:
neh.log.Info("Unsupported type", "value", typedKey, "type", fmt.Sprintf("%T", typedKey)) glog.Error("Unsupported type %V", typedKey)
return false return false
} }
} }
@ -67,7 +64,7 @@ func (neh NotEqualHandler) validateValueWithSlicePattern(key []interface{}, valu
if val, ok := value.([]interface{}); ok { if val, ok := value.([]interface{}); ok {
return !reflect.DeepEqual(key, val) return !reflect.DeepEqual(key, val)
} }
neh.log.Info("Expected type []interface{}", "value", value, "type", fmt.Sprintf("%T", value)) glog.Warningf("Expected []interface{}, %v is of type %T", value, value)
return false return false
} }
@ -75,7 +72,7 @@ func (neh NotEqualHandler) validateValueWithMapPattern(key map[string]interface{
if val, ok := value.(map[string]interface{}); ok { if val, ok := value.(map[string]interface{}); ok {
return !reflect.DeepEqual(key, val) return !reflect.DeepEqual(key, val)
} }
neh.log.Info("Expected type map[string]interface{}", "value", value, "type", fmt.Sprintf("%T", value)) glog.Warningf("Expected map[string]interface{}, %v is of type %T", value, value)
return false return false
} }
@ -83,7 +80,7 @@ func (neh NotEqualHandler) validateValuewithStringPattern(key string, value inte
if val, ok := value.(string); ok { if val, ok := value.(string); ok {
return key != val return key != val
} }
neh.log.Info("Expected type string", "value", value, "type", fmt.Sprintf("%T", value)) glog.Warningf("Expected string, %v is of type %T", value, value)
return false return false
} }
@ -94,25 +91,25 @@ func (neh NotEqualHandler) validateValuewithFloatPattern(key float64, value inte
if key == math.Trunc(key) { if key == math.Trunc(key) {
return int(key) != typedValue return int(key) != typedValue
} }
neh.log.Info("Expected type float, found int", "typedValue", typedValue) glog.Warningf("Expected float, found int: %d\n", typedValue)
case int64: case int64:
// check that float has not fraction // check that float has not fraction
if key == math.Trunc(key) { if key == math.Trunc(key) {
return int64(key) != typedValue return int64(key) != typedValue
} }
neh.log.Info("Expected type float, found int", "typedValue", typedValue) glog.Warningf("Expected float, found int: %d\n", typedValue)
case float64: case float64:
return typedValue != key return typedValue != key
case string: case string:
// extract float from string // extract float from string
float64Num, err := strconv.ParseFloat(typedValue, 64) float64Num, err := strconv.ParseFloat(typedValue, 64)
if err != nil { if err != nil {
neh.log.Error(err, "Failed to parse float64 from string") glog.Warningf("Failed to parse float64 from string: %v", err)
return false return false
} }
return float64Num != key return float64Num != key
default: default:
neh.log.Info("Expected type float", "value", value, "type", fmt.Sprintf("%T", value)) glog.Warningf("Expected float, found: %T\n", value)
return false return false
} }
return false return false
@ -121,7 +118,7 @@ func (neh NotEqualHandler) validateValuewithFloatPattern(key float64, value inte
func (neh NotEqualHandler) validateValuewithBoolPattern(key bool, value interface{}) bool { func (neh NotEqualHandler) validateValuewithBoolPattern(key bool, value interface{}) bool {
typedValue, ok := value.(bool) typedValue, ok := value.(bool)
if !ok { if !ok {
neh.log.Info("Expected type bool", "value", value, "type", fmt.Sprintf("%T", value)) glog.Error("Expected bool, found %V", value)
return false return false
} }
return key != typedValue return key != typedValue
@ -138,18 +135,18 @@ func (neh NotEqualHandler) validateValuewithIntPattern(key int64, value interfac
if typedValue == math.Trunc(typedValue) { if typedValue == math.Trunc(typedValue) {
return int64(typedValue) != key return int64(typedValue) != key
} }
neh.log.Info("Expected type int, found float", "value", typedValue, "type", fmt.Sprintf("%T", typedValue)) glog.Warningf("Expected int, found float: %f\n", typedValue)
return false return false
case string: case string:
// extract in64 from string // extract in64 from string
int64Num, err := strconv.ParseInt(typedValue, 10, 64) int64Num, err := strconv.ParseInt(typedValue, 10, 64)
if err != nil { if err != nil {
neh.log.Error(err, "Failed to parse int64 from string") glog.Warningf("Failed to parse int64 from string: %v", err)
return false return false
} }
return int64Num != key return int64Num != key
default: default:
neh.log.Info("Expected type int", "value", value, "type", fmt.Sprintf("%T", value)) glog.Warningf("Expected int, %v is of type %T", value, value)
return false return false
} }
} }

View file

@ -1,7 +1,7 @@
package operator package operator
import ( import (
"github.com/go-logr/logr" "github.com/golang/glog"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1" kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
"github.com/nirmata/kyverno/pkg/engine/context" "github.com/nirmata/kyverno/pkg/engine/context"
) )
@ -17,17 +17,17 @@ type OperatorHandler interface {
} }
//VariableSubstitutionHandler defines the handler function for variable substitution //VariableSubstitutionHandler defines the handler function for variable substitution
type VariableSubstitutionHandler = func(log logr.Logger, ctx context.EvalInterface, pattern interface{}) (interface{}, error) type VariableSubstitutionHandler = func(ctx context.EvalInterface, pattern interface{}) (interface{}, error)
//CreateOperatorHandler returns the operator handler based on the operator used in condition //CreateOperatorHandler returns the operator handler based on the operator used in condition
func CreateOperatorHandler(log logr.Logger, ctx context.EvalInterface, op kyverno.ConditionOperator, subHandler VariableSubstitutionHandler) OperatorHandler { func CreateOperatorHandler(ctx context.EvalInterface, op kyverno.ConditionOperator, subHandler VariableSubstitutionHandler) OperatorHandler {
switch op { switch op {
case kyverno.Equal: case kyverno.Equal:
return NewEqualHandler(log, ctx, subHandler) return NewEqualHandler(ctx, subHandler)
case kyverno.NotEqual: case kyverno.NotEqual:
return NewNotEqualHandler(log, ctx, subHandler) return NewNotEqualHandler(ctx, subHandler)
default: default:
log.Info("operator not supported", "operator", string(op)) glog.Errorf("unsupported operator: %s", string(op))
} }
return nil return nil
} }

View file

@ -7,7 +7,6 @@ import (
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1" kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
authenticationv1 "k8s.io/api/authentication/v1" authenticationv1 "k8s.io/api/authentication/v1"
"sigs.k8s.io/controller-runtime/pkg/log"
"github.com/nirmata/kyverno/pkg/engine/context" "github.com/nirmata/kyverno/pkg/engine/context"
) )
@ -85,7 +84,7 @@ func Test_variablesub1(t *testing.T) {
t.Error(err) t.Error(err)
} }
if _, err := SubstituteVars(log.Log, ctx, patternCopy); err != nil { if _, err := SubstituteVars(ctx, patternCopy); err != nil {
t.Error(err) t.Error(err)
} }
resultRaw, err := json.Marshal(patternCopy) resultRaw, err := json.Marshal(patternCopy)
@ -175,7 +174,7 @@ func Test_variablesub_multiple(t *testing.T) {
t.Error(err) t.Error(err)
} }
if _, err := SubstituteVars(log.Log, ctx, patternCopy); err != nil { if _, err := SubstituteVars(ctx, patternCopy); err != nil {
t.Error(err) t.Error(err)
} }
resultRaw, err := json.Marshal(patternCopy) resultRaw, err := json.Marshal(patternCopy)
@ -262,7 +261,7 @@ func Test_variablesubstitution(t *testing.T) {
t.Error(err) t.Error(err)
} }
if _, err := SubstituteVars(log.Log, ctx, patternCopy); err != nil { if _, err := SubstituteVars(ctx, patternCopy); err != nil {
t.Error(err) t.Error(err)
} }
resultRaw, err := json.Marshal(patternCopy) resultRaw, err := json.Marshal(patternCopy)
@ -323,7 +322,7 @@ func Test_variableSubstitutionValue(t *testing.T) {
t.Error(err) t.Error(err)
} }
if _, err := SubstituteVars(log.Log, ctx, patternCopy); err != nil { if _, err := SubstituteVars(ctx, patternCopy); err != nil {
t.Error(err) t.Error(err)
} }
resultRaw, err := json.Marshal(patternCopy) resultRaw, err := json.Marshal(patternCopy)
@ -381,7 +380,7 @@ func Test_variableSubstitutionValueOperatorNotEqual(t *testing.T) {
t.Error(err) t.Error(err)
} }
if _, err := SubstituteVars(log.Log, ctx, patternCopy); err != nil { if _, err := SubstituteVars(ctx, patternCopy); err != nil {
t.Error(err) t.Error(err)
} }
resultRaw, err := json.Marshal(patternCopy) resultRaw, err := json.Marshal(patternCopy)
@ -440,7 +439,7 @@ func Test_variableSubstitutionValueFail(t *testing.T) {
t.Error(err) t.Error(err)
} }
if _, err := SubstituteVars(log.Log, ctx, patternCopy); err == nil { if _, err := SubstituteVars(ctx, patternCopy); err == nil {
t.Log("expected to fails") t.Log("expected to fails")
t.Fail() t.Fail()
} }
@ -498,7 +497,7 @@ func Test_variableSubstitutionObject(t *testing.T) {
t.Error(err) t.Error(err)
} }
if _, err := SubstituteVars(log.Log, ctx, patternCopy); err != nil { if _, err := SubstituteVars(ctx, patternCopy); err != nil {
t.Error(err) t.Error(err)
} }
resultRaw, err := json.Marshal(patternCopy) resultRaw, err := json.Marshal(patternCopy)
@ -562,7 +561,7 @@ func Test_variableSubstitutionObjectOperatorNotEqualFail(t *testing.T) {
t.Error(err) t.Error(err)
} }
if _, err := SubstituteVars(log.Log, ctx, patternCopy); err == nil { if _, err := SubstituteVars(ctx, patternCopy); err == nil {
t.Error(err) t.Error(err)
} }
@ -621,7 +620,7 @@ func Test_variableSubstitutionMultipleObject(t *testing.T) {
t.Error(err) t.Error(err)
} }
if _, err := SubstituteVars(log.Log, ctx, patternCopy); err != nil { if _, err := SubstituteVars(ctx, patternCopy); err != nil {
t.Error(err) t.Error(err)
} }
resultRaw, err := json.Marshal(patternCopy) resultRaw, err := json.Marshal(patternCopy)

View file

@ -6,7 +6,7 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/go-logr/logr" "github.com/golang/glog"
"github.com/nirmata/kyverno/pkg/engine/context" "github.com/nirmata/kyverno/pkg/engine/context"
) )
@ -17,9 +17,9 @@ const (
//SubstituteVars replaces the variables with the values defined in the context //SubstituteVars replaces the variables with the values defined in the context
// - if any variable is invaid or has nil value, it is considered as a failed varable substitution // - if any variable is invaid or has nil value, it is considered as a failed varable substitution
func SubstituteVars(log logr.Logger, ctx context.EvalInterface, pattern interface{}) (interface{}, error) { func SubstituteVars(ctx context.EvalInterface, pattern interface{}) (interface{}, error) {
errs := []error{} errs := []error{}
pattern = subVars(log, ctx, pattern, "", &errs) pattern = subVars(ctx, pattern, "", &errs)
if len(errs) == 0 { if len(errs) == 0 {
// no error while parsing the pattern // no error while parsing the pattern
return pattern, nil return pattern, nil
@ -27,40 +27,40 @@ func SubstituteVars(log logr.Logger, ctx context.EvalInterface, pattern interfac
return pattern, fmt.Errorf("%v", errs) return pattern, fmt.Errorf("%v", errs)
} }
func subVars(log logr.Logger, ctx context.EvalInterface, pattern interface{}, path string, errs *[]error) interface{} { func subVars(ctx context.EvalInterface, pattern interface{}, path string, errs *[]error) interface{} {
switch typedPattern := pattern.(type) { switch typedPattern := pattern.(type) {
case map[string]interface{}: case map[string]interface{}:
return subMap(log, ctx, typedPattern, path, errs) return subMap(ctx, typedPattern, path, errs)
case []interface{}: case []interface{}:
return subArray(log, ctx, typedPattern, path, errs) return subArray(ctx, typedPattern, path, errs)
case string: case string:
return subValR(log, ctx, typedPattern, path, errs) return subValR(ctx, typedPattern, path, errs)
default: default:
return pattern return pattern
} }
} }
func subMap(log logr.Logger, ctx context.EvalInterface, patternMap map[string]interface{}, path string, errs *[]error) map[string]interface{} { func subMap(ctx context.EvalInterface, patternMap map[string]interface{}, path string, errs *[]error) map[string]interface{} {
for key, patternElement := range patternMap { for key, patternElement := range patternMap {
curPath := path + "/" + key curPath := path + "/" + key
value := subVars(log, ctx, patternElement, curPath, errs) value := subVars(ctx, patternElement, curPath, errs)
patternMap[key] = value patternMap[key] = value
} }
return patternMap return patternMap
} }
func subArray(log logr.Logger, ctx context.EvalInterface, patternList []interface{}, path string, errs *[]error) []interface{} { func subArray(ctx context.EvalInterface, patternList []interface{}, path string, errs *[]error) []interface{} {
for idx, patternElement := range patternList { for idx, patternElement := range patternList {
curPath := path + "/" + strconv.Itoa(idx) curPath := path + "/" + strconv.Itoa(idx)
value := subVars(log, ctx, patternElement, curPath, errs) value := subVars(ctx, patternElement, curPath, errs)
patternList[idx] = value patternList[idx] = value
} }
return patternList return patternList
} }
// subValR resolves the variables if defined // subValR resolves the variables if defined
func subValR(log logr.Logger, ctx context.EvalInterface, valuePattern string, path string, errs *[]error) interface{} { func subValR(ctx context.EvalInterface, valuePattern string, path string, errs *[]error) interface{} {
// variable values can be scalar values(string,int, float) or they can be obects(map,slice) // variable values can be scalar values(string,int, float) or they can be obects(map,slice)
// - {{variable}} // - {{variable}}
@ -73,7 +73,7 @@ func subValR(log logr.Logger, ctx context.EvalInterface, valuePattern string, pa
// since this might be a potential place for error, required better error reporting and handling // since this might be a potential place for error, required better error reporting and handling
// object values are only suported for single variable substitution // object values are only suported for single variable substitution
if ok, retVal := processIfSingleVariable(log, ctx, valuePattern, path, errs); ok { if ok, retVal := processIfSingleVariable(ctx, valuePattern, path, errs); ok {
return retVal return retVal
} }
// var emptyInterface interface{} // var emptyInterface interface{}
@ -82,7 +82,7 @@ func subValR(log logr.Logger, ctx context.EvalInterface, valuePattern string, pa
for { for {
valueStr := valuePattern valueStr := valuePattern
if len(failedVars) != 0 { if len(failedVars) != 0 {
log.Info("failed to resolve variablesl short-circuiting") glog.Info("some failed variables short-circuiting")
break break
} }
// get variables at this level // get variables at this level
@ -123,7 +123,7 @@ func subValR(log logr.Logger, ctx context.EvalInterface, valuePattern string, pa
continue continue
} }
// if type is not scalar then consider this as a failed variable // if type is not scalar then consider this as a failed variable
log.Info("variable resolves to non-scalar value. Non-Scalar values are not supported for nested variables", "variable", k, "value", v) glog.Infof("variable %s resolves to non-scalar value %v. Non-Scalar values are not supported for nested variables", k, v)
failedVars = append(failedVars, k) failedVars = append(failedVars, k)
} }
valuePattern = newVal valuePattern = newVal
@ -143,10 +143,10 @@ func subValR(log logr.Logger, ctx context.EvalInterface, valuePattern string, pa
// if the value can be evaluted return the value // if the value can be evaluted return the value
// -> return value can be scalar or object type // -> return value can be scalar or object type
// -> if the variable is not present in the context then add an error and dont process further // -> if the variable is not present in the context then add an error and dont process further
func processIfSingleVariable(log logr.Logger, ctx context.EvalInterface, valuePattern interface{}, path string, errs *[]error) (bool, interface{}) { func processIfSingleVariable(ctx context.EvalInterface, valuePattern interface{}, path string, errs *[]error) (bool, interface{}) {
valueStr, ok := valuePattern.(string) valueStr, ok := valuePattern.(string)
if !ok { if !ok {
log.Info("failed to convert to string", "pattern", valuePattern) glog.Infof("failed to convert %v to string", valuePattern)
return false, nil return false, nil
} }
// get variables at this level // get variables at this level

View file

@ -6,7 +6,6 @@ import (
"github.com/nirmata/kyverno/pkg/engine/context" "github.com/nirmata/kyverno/pkg/engine/context"
"gotest.tools/assert" "gotest.tools/assert"
"sigs.k8s.io/controller-runtime/pkg/log"
) )
func Test_subVars_success(t *testing.T) { func Test_subVars_success(t *testing.T) {
@ -65,7 +64,7 @@ func Test_subVars_success(t *testing.T) {
t.Error(err) t.Error(err)
} }
if _, err := SubstituteVars(log.Log, ctx, pattern); err != nil { if _, err := SubstituteVars(ctx, pattern); err != nil {
t.Error(err) t.Error(err)
} }
} }
@ -126,7 +125,7 @@ func Test_subVars_failed(t *testing.T) {
t.Error(err) t.Error(err)
} }
if _, err := SubstituteVars(log.Log, ctx, pattern); err == nil { if _, err := SubstituteVars(ctx, pattern); err == nil {
t.Error("error is expected") t.Error("error is expected")
} }
} }
@ -153,5 +152,5 @@ func Test_SubvarRecursive(t *testing.T) {
ctx := context.NewContext() ctx := context.NewContext()
assert.Assert(t, ctx.AddResource(resourceRaw)) assert.Assert(t, ctx.AddResource(resourceRaw))
errs := []error{} errs := []error{}
subValR(log.Log, ctx, string(patternRaw), "/", &errs) subValR(ctx, string(patternRaw), "/", &errs)
} }

View file

@ -3,7 +3,7 @@ package event
import ( import (
"time" "time"
"github.com/go-logr/logr" "github.com/golang/glog"
"github.com/nirmata/kyverno/pkg/client/clientset/versioned/scheme" "github.com/nirmata/kyverno/pkg/client/clientset/versioned/scheme"
kyvernoinformer "github.com/nirmata/kyverno/pkg/client/informers/externalversions/kyverno/v1" kyvernoinformer "github.com/nirmata/kyverno/pkg/client/informers/externalversions/kyverno/v1"
@ -17,7 +17,6 @@ import (
"k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/cache"
"k8s.io/client-go/tools/record" "k8s.io/client-go/tools/record"
"k8s.io/client-go/util/workqueue" "k8s.io/client-go/util/workqueue"
"k8s.io/klog"
) )
//Generator generate events //Generator generate events
@ -35,7 +34,6 @@ type Generator struct {
admissionCtrRecorder record.EventRecorder admissionCtrRecorder record.EventRecorder
// events generated at namespaced policy controller to process 'generate' rule // events generated at namespaced policy controller to process 'generate' rule
genPolicyRecorder record.EventRecorder genPolicyRecorder record.EventRecorder
log logr.Logger
} }
//Interface to generate event //Interface to generate event
@ -44,33 +42,32 @@ type Interface interface {
} }
//NewEventGenerator to generate a new event controller //NewEventGenerator to generate a new event controller
func NewEventGenerator(client *client.Client, pInformer kyvernoinformer.ClusterPolicyInformer, log logr.Logger) *Generator { func NewEventGenerator(client *client.Client, pInformer kyvernoinformer.ClusterPolicyInformer) *Generator {
gen := Generator{ gen := Generator{
client: client, client: client,
pLister: pInformer.Lister(), pLister: pInformer.Lister(),
queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), eventWorkQueueName), queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), eventWorkQueueName),
pSynced: pInformer.Informer().HasSynced, pSynced: pInformer.Informer().HasSynced,
policyCtrRecorder: initRecorder(client, PolicyController, log), policyCtrRecorder: initRecorder(client, PolicyController),
admissionCtrRecorder: initRecorder(client, AdmissionController, log), admissionCtrRecorder: initRecorder(client, AdmissionController),
genPolicyRecorder: initRecorder(client, GeneratePolicyController, log), genPolicyRecorder: initRecorder(client, GeneratePolicyController),
log: log,
} }
return &gen return &gen
} }
func initRecorder(client *client.Client, eventSource Source, log logr.Logger) record.EventRecorder { func initRecorder(client *client.Client, eventSource Source) record.EventRecorder {
// Initliaze Event Broadcaster // Initliaze Event Broadcaster
err := scheme.AddToScheme(scheme.Scheme) err := scheme.AddToScheme(scheme.Scheme)
if err != nil { if err != nil {
log.Error(err, "failed to add to scheme") glog.Error(err)
return nil return nil
} }
eventBroadcaster := record.NewBroadcaster() eventBroadcaster := record.NewBroadcaster()
eventBroadcaster.StartLogging(klog.Infof) eventBroadcaster.StartLogging(glog.V(4).Infof)
eventInterface, err := client.GetEventsInterface() eventInterface, err := client.GetEventsInterface()
if err != nil { if err != nil {
log.Error(err, "failed to get event interface for logging") glog.Error(err) // TODO: add more specific error
return nil return nil
} }
eventBroadcaster.StartRecordingToSink( eventBroadcaster.StartRecordingToSink(
@ -84,12 +81,11 @@ func initRecorder(client *client.Client, eventSource Source, log logr.Logger) re
//Add queues an event for generation //Add queues an event for generation
func (gen *Generator) Add(infos ...Info) { func (gen *Generator) Add(infos ...Info) {
logger := gen.log
for _, info := range infos { for _, info := range infos {
if info.Name == "" { if info.Name == "" {
// dont create event for resources with generateName // dont create event for resources with generateName
// as the name is not generated yet // as the name is not generated yet
logger.V(4).Info("not creating an event as the resource has not been assigned a name yet", "kind", info.Kind, "name", info.Name, "namespace", info.Namespace) glog.V(4).Infof("received info %v, not creating an event as the resource has not been assigned a name yet", info)
continue continue
} }
gen.queue.Add(info) gen.queue.Add(info)
@ -98,14 +94,12 @@ func (gen *Generator) Add(infos ...Info) {
// Run begins generator // Run begins generator
func (gen *Generator) Run(workers int, stopCh <-chan struct{}) { func (gen *Generator) Run(workers int, stopCh <-chan struct{}) {
logger := gen.log
defer utilruntime.HandleCrash() defer utilruntime.HandleCrash()
glog.Info("Starting event generator")
logger.Info("start") defer glog.Info("Shutting down event generator")
defer logger.Info("shutting down")
if !cache.WaitForCacheSync(stopCh, gen.pSynced) { if !cache.WaitForCacheSync(stopCh, gen.pSynced) {
logger.Info("failed to sync informer cache") glog.Error("event generator: failed to sync informer cache")
} }
for i := 0; i < workers; i++ { for i := 0; i < workers; i++ {
@ -120,25 +114,24 @@ func (gen *Generator) runWorker() {
} }
func (gen *Generator) handleErr(err error, key interface{}) { func (gen *Generator) handleErr(err error, key interface{}) {
logger := gen.log
if err == nil { if err == nil {
gen.queue.Forget(key) gen.queue.Forget(key)
return return
} }
// This controller retries if something goes wrong. After that, it stops trying. // This controller retries if something goes wrong. After that, it stops trying.
if gen.queue.NumRequeues(key) < workQueueRetryLimit { if gen.queue.NumRequeues(key) < workQueueRetryLimit {
logger.Error(err, "Error syncing events;re-queuing request,the resource might not have been created yet", "key", key) glog.Warningf("Error syncing events %v(re-queuing request, the resource might not have been created yet): %v", key, err)
// Re-enqueue the key rate limited. Based on the rate limiter on the // Re-enqueue the key rate limited. Based on the rate limiter on the
// queue and the re-enqueue history, the key will be processed later again. // queue and the re-enqueue history, the key will be processed later again.
gen.queue.AddRateLimited(key) gen.queue.AddRateLimited(key)
return return
} }
gen.queue.Forget(key) gen.queue.Forget(key)
logger.Error(err, "dropping the key out of queue", "key", key) glog.Error(err)
glog.Warningf("Dropping the key out of the queue: %v", err)
} }
func (gen *Generator) processNextWorkItem() bool { func (gen *Generator) processNextWorkItem() bool {
logger := gen.log
obj, shutdown := gen.queue.Get() obj, shutdown := gen.queue.Get()
if shutdown { if shutdown {
return false return false
@ -151,7 +144,7 @@ func (gen *Generator) processNextWorkItem() bool {
if key, ok = obj.(Info); !ok { if key, ok = obj.(Info); !ok {
gen.queue.Forget(obj) gen.queue.Forget(obj)
logger.Info("Incorrect type; expected type 'info'", "obj", obj) glog.Warningf("Expecting type info by got %v\n", obj)
return nil return nil
} }
err := gen.syncHandler(key) err := gen.syncHandler(key)
@ -159,14 +152,13 @@ func (gen *Generator) processNextWorkItem() bool {
return nil return nil
}(obj) }(obj)
if err != nil { if err != nil {
logger.Error(err, "failed to process next work item") glog.Error(err)
return true return true
} }
return true return true
} }
func (gen *Generator) syncHandler(key Info) error { func (gen *Generator) syncHandler(key Info) error {
logger := gen.log
var robj runtime.Object var robj runtime.Object
var err error var err error
switch key.Kind { switch key.Kind {
@ -174,13 +166,13 @@ func (gen *Generator) syncHandler(key Info) error {
//TODO: policy is clustered resource so wont need namespace //TODO: policy is clustered resource so wont need namespace
robj, err = gen.pLister.Get(key.Name) robj, err = gen.pLister.Get(key.Name)
if err != nil { if err != nil {
logger.Error(err, "failed to get policy", "name", key.Name) glog.V(4).Infof("Error creating event: unable to get policy %s, will retry ", key.Name)
return err return err
} }
default: default:
robj, err = gen.client.GetResource(key.Kind, key.Namespace, key.Name) robj, err = gen.client.GetResource(key.Kind, key.Namespace, key.Name)
if err != nil { if err != nil {
logger.Error(err, "failed to get resource", "kind", key.Kind, "name", key.Name, "namespace", key.Namespace) glog.V(4).Infof("Error creating event: unable to get resource %s/%s/%s, will retry ", key.Kind, key.Namespace, key.Name)
return err return err
} }
} }
@ -200,14 +192,13 @@ func (gen *Generator) syncHandler(key Info) error {
case GeneratePolicyController: case GeneratePolicyController:
gen.genPolicyRecorder.Event(robj, eventType, key.Reason, key.Message) gen.genPolicyRecorder.Event(robj, eventType, key.Reason, key.Message)
default: default:
logger.Info("info.source not defined for the request") glog.Info("info.source not defined for the event generator request")
} }
return nil return nil
} }
//NewEvent builds a event creation request //NewEvent builds a event creation request
func NewEvent( func NewEvent(
log logr.Logger,
rkind, rkind,
rapiVersion, rapiVersion,
rnamespace, rnamespace,
@ -218,7 +209,7 @@ func NewEvent(
args ...interface{}) Info { args ...interface{}) Info {
msgText, err := getEventMsg(message, args...) msgText, err := getEventMsg(message, args...)
if err != nil { if err != nil {
log.Error(err, "failed to get event message") glog.Error(err)
} }
return Info{ return Info{
Kind: rkind, Kind: rkind,

View file

@ -1,20 +1,19 @@
package cleanup package cleanup
import ( import (
"github.com/go-logr/logr" "github.com/golang/glog"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1" kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
dclient "github.com/nirmata/kyverno/pkg/dclient" dclient "github.com/nirmata/kyverno/pkg/dclient"
apierrors "k8s.io/apimachinery/pkg/api/errors" apierrors "k8s.io/apimachinery/pkg/api/errors"
) )
func (c *Controller) processGR(gr kyverno.GenerateRequest) error { func (c *Controller) processGR(gr kyverno.GenerateRequest) error {
logger := c.log.WithValues("kind", gr.Kind, "namespace", gr.Namespace, "name", gr.Name)
// 1- Corresponding policy has been deleted // 1- Corresponding policy has been deleted
// then we dont delete the generated resources // then we dont delete the generated resources
// 2- The trigger resource is deleted, then delete the generated resources // 2- The trigger resource is deleted, then delete the generated resources
if !ownerResourceExists(logger, c.client, gr) { if !ownerResourceExists(c.client, gr) {
if err := deleteGeneratedResources(logger, c.client, gr); err != nil { if err := deleteGeneratedResources(c.client, gr); err != nil {
return err return err
} }
// - trigger-resource is deleted // - trigger-resource is deleted
@ -25,25 +24,25 @@ func (c *Controller) processGR(gr kyverno.GenerateRequest) error {
return nil return nil
} }
func ownerResourceExists(log logr.Logger, client *dclient.Client, gr kyverno.GenerateRequest) bool { func ownerResourceExists(client *dclient.Client, gr kyverno.GenerateRequest) bool {
_, err := client.GetResource(gr.Spec.Resource.Kind, gr.Spec.Resource.Namespace, gr.Spec.Resource.Name) _, err := client.GetResource(gr.Spec.Resource.Kind, gr.Spec.Resource.Namespace, gr.Spec.Resource.Name)
// trigger resources has been deleted // trigger resources has been deleted
if apierrors.IsNotFound(err) { if apierrors.IsNotFound(err) {
return false return false
} }
if err != nil { if err != nil {
log.Error(err, "failed to get resource", "genKind", gr.Spec.Resource.Kind, "genNamespace", gr.Spec.Resource.Namespace, "genName", gr.Spec.Resource.Name) glog.V(4).Infof("Failed to get resource %s/%s/%s: error : %s", gr.Spec.Resource.Kind, gr.Spec.Resource.Namespace, gr.Spec.Resource.Name, err)
} }
// if there was an error while querying the resources we dont delete the generated resources // if there was an error while querying the resources we dont delete the generated resources
// but expect the deletion in next reconciliation loop // but expect the deletion in next reconciliation loop
return true return true
} }
func deleteGeneratedResources(log logr.Logger, client *dclient.Client, gr kyverno.GenerateRequest) error { func deleteGeneratedResources(client *dclient.Client, gr kyverno.GenerateRequest) error {
for _, genResource := range gr.Status.GeneratedResources { for _, genResource := range gr.Status.GeneratedResources {
err := client.DeleteResource(genResource.Kind, genResource.Namespace, genResource.Name, false) err := client.DeleteResource(genResource.Kind, genResource.Namespace, genResource.Name, false)
if apierrors.IsNotFound(err) { if apierrors.IsNotFound(err) {
log.Error(err, "resource not foundl will not delete", "genKind", gr.Spec.Resource.Kind, "genNamespace", gr.Spec.Resource.Namespace, "genName", gr.Spec.Resource.Name) glog.V(4).Infof("resource %s/%s/%s not found, will no delete", genResource.Kind, genResource.Namespace, genResource.Name)
continue continue
} }
if err != nil { if err != nil {

View file

@ -1,9 +1,11 @@
package cleanup package cleanup
import ( import (
"fmt"
"time" "time"
"github.com/go-logr/logr" "github.com/golang/glog"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1" kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
kyvernoclient "github.com/nirmata/kyverno/pkg/client/clientset/versioned" kyvernoclient "github.com/nirmata/kyverno/pkg/client/clientset/versioned"
kyvernoinformer "github.com/nirmata/kyverno/pkg/client/informers/externalversions/kyverno/v1" kyvernoinformer "github.com/nirmata/kyverno/pkg/client/informers/externalversions/kyverno/v1"
@ -51,7 +53,6 @@ type Controller struct {
//TODO: list of generic informers //TODO: list of generic informers
// only support Namespaces for deletion of resource // only support Namespaces for deletion of resource
nsInformer informers.GenericInformer nsInformer informers.GenericInformer
log logr.Logger
} }
//NewController returns a new controller instance to manage generate-requests //NewController returns a new controller instance to manage generate-requests
@ -61,7 +62,6 @@ func NewController(
pInformer kyvernoinformer.ClusterPolicyInformer, pInformer kyvernoinformer.ClusterPolicyInformer,
grInformer kyvernoinformer.GenerateRequestInformer, grInformer kyvernoinformer.GenerateRequestInformer,
dynamicInformer dynamicinformer.DynamicSharedInformerFactory, dynamicInformer dynamicinformer.DynamicSharedInformerFactory,
log logr.Logger,
) *Controller { ) *Controller {
c := Controller{ c := Controller{
kyvernoClient: kyvernoclient, kyvernoClient: kyvernoclient,
@ -70,7 +70,6 @@ func NewController(
// as we dont want a deleted GR to be re-queue // as we dont want a deleted GR to be re-queue
queue: workqueue.NewNamedRateLimitingQueue(workqueue.NewItemExponentialFailureRateLimiter(1, 30), "generate-request-cleanup"), queue: workqueue.NewNamedRateLimitingQueue(workqueue.NewItemExponentialFailureRateLimiter(1, 30), "generate-request-cleanup"),
dynamicInformer: dynamicInformer, dynamicInformer: dynamicInformer,
log: log,
} }
c.control = Control{client: kyvernoclient} c.control = Control{client: kyvernoclient}
c.enqueueGR = c.enqueue c.enqueueGR = c.enqueue
@ -103,11 +102,10 @@ func NewController(
} }
func (c *Controller) deleteGenericResource(obj interface{}) { func (c *Controller) deleteGenericResource(obj interface{}) {
logger := c.log
r := obj.(*unstructured.Unstructured) r := obj.(*unstructured.Unstructured)
grs, err := c.grLister.GetGenerateRequestsForResource(r.GetKind(), r.GetNamespace(), r.GetName()) grs, err := c.grLister.GetGenerateRequestsForResource(r.GetKind(), r.GetNamespace(), r.GetName())
if err != nil { if err != nil {
logger.Error(err, "failed to get generate request CR for resource", "kind", r.GetKind(), "namespace", r.GetNamespace(), "name", r.GetName()) glog.Errorf("failed to Generate Requests for resource %s/%s/%s: %v", r.GetKind(), r.GetNamespace(), r.GetName(), err)
return return
} }
// re-evaluate the GR as the resource was deleted // re-evaluate the GR as the resource was deleted
@ -117,27 +115,26 @@ func (c *Controller) deleteGenericResource(obj interface{}) {
} }
func (c *Controller) deletePolicy(obj interface{}) { func (c *Controller) deletePolicy(obj interface{}) {
logger := c.log
p, ok := obj.(*kyverno.ClusterPolicy) p, ok := obj.(*kyverno.ClusterPolicy)
if !ok { if !ok {
tombstone, ok := obj.(cache.DeletedFinalStateUnknown) tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
if !ok { if !ok {
logger.Info("ouldn't get object from tombstone", "obj", obj) glog.Info(fmt.Errorf("Couldn't get object from tombstone %#v", obj))
return return
} }
_, ok = tombstone.Obj.(*kyverno.ClusterPolicy) _, ok = tombstone.Obj.(*kyverno.ClusterPolicy)
if !ok { if !ok {
logger.Info("Tombstone contained object that is not a Generate Request", "obj", obj) glog.Info(fmt.Errorf("Tombstone contained object that is not a Generate Request %#v", obj))
return return
} }
} }
logger.V(4).Info("deleting policy", "name", p.Name) glog.V(4).Infof("Deleting Policy %s", p.Name)
// clean up the GR // clean up the GR
// Get the corresponding GR // Get the corresponding GR
// get the list of GR for the current Policy version // get the list of GR for the current Policy version
grs, err := c.grLister.GetGenerateRequestsForClusterPolicy(p.Name) grs, err := c.grLister.GetGenerateRequestsForClusterPolicy(p.Name)
if err != nil { if err != nil {
logger.Error(err, "failed to generate request CR for the policy", "name", p.Name) glog.Errorf("failed to Generate Requests for policy %s: %v", p.Name, err)
return return
} }
for _, gr := range grs { for _, gr := range grs {
@ -156,46 +153,44 @@ func (c *Controller) updateGR(old, cur interface{}) {
} }
func (c *Controller) deleteGR(obj interface{}) { func (c *Controller) deleteGR(obj interface{}) {
logger := c.log
gr, ok := obj.(*kyverno.GenerateRequest) gr, ok := obj.(*kyverno.GenerateRequest)
if !ok { if !ok {
tombstone, ok := obj.(cache.DeletedFinalStateUnknown) tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
if !ok { if !ok {
logger.Info("Couldn't get object from tombstone", "obj", obj) glog.Info(fmt.Errorf("Couldn't get object from tombstone %#v", obj))
return return
} }
_, ok = tombstone.Obj.(*kyverno.GenerateRequest) _, ok = tombstone.Obj.(*kyverno.GenerateRequest)
if !ok { if !ok {
logger.Info("ombstone contained object that is not a Generate Request", "obj", obj) glog.Info(fmt.Errorf("Tombstone contained object that is not a Generate Request %#v", obj))
return return
} }
} }
logger.V(4).Info("deleting Generate Request CR", "name", gr.Name) glog.V(4).Infof("Deleting GR %s", gr.Name)
// sync Handler will remove it from the queue // sync Handler will remove it from the queue
c.enqueueGR(gr) c.enqueueGR(gr)
} }
func (c *Controller) enqueue(gr *kyverno.GenerateRequest) { func (c *Controller) enqueue(gr *kyverno.GenerateRequest) {
logger := c.log
key, err := cache.MetaNamespaceKeyFunc(gr) key, err := cache.MetaNamespaceKeyFunc(gr)
if err != nil { if err != nil {
logger.Error(err, "failed to extract key") glog.Error(err)
return return
} }
logger.V(4).Info("eneque generate request", "name", gr.Name) glog.V(4).Infof("cleanup enqueu: %v", gr.Name)
c.queue.Add(key) c.queue.Add(key)
} }
//Run starts the generate-request re-conciliation loop //Run starts the generate-request re-conciliation loop
func (c *Controller) Run(workers int, stopCh <-chan struct{}) { func (c *Controller) Run(workers int, stopCh <-chan struct{}) {
logger := c.log
defer utilruntime.HandleCrash() defer utilruntime.HandleCrash()
defer c.queue.ShutDown() defer c.queue.ShutDown()
logger.Info("starting")
defer logger.Info("shutting down") glog.Info("Starting generate-policy-cleanup controller")
defer glog.Info("Shutting down generate-policy-cleanup controller")
if !cache.WaitForCacheSync(stopCh, c.pSynced, c.grSynced) { if !cache.WaitForCacheSync(stopCh, c.pSynced, c.grSynced) {
logger.Info("failed to sync informer cache") glog.Error("generate-policy-cleanup controller: failed to sync informer cache")
return return
} }
for i := 0; i < workers; i++ { for i := 0; i < workers; i++ {
@ -224,33 +219,31 @@ func (c *Controller) processNextWorkItem() bool {
} }
func (c *Controller) handleErr(err error, key interface{}) { func (c *Controller) handleErr(err error, key interface{}) {
logger := c.log
if err == nil { if err == nil {
c.queue.Forget(key) c.queue.Forget(key)
return return
} }
if c.queue.NumRequeues(key) < maxRetries { if c.queue.NumRequeues(key) < maxRetries {
logger.Error(err, "failed to sync generate request", "key", key) glog.Errorf("Error syncing Generate Request %v: %v", key, err)
c.queue.AddRateLimited(key) c.queue.AddRateLimited(key)
return return
} }
utilruntime.HandleError(err) utilruntime.HandleError(err)
logger.Error(err, "dropping generate request out of the queue", "key", key) glog.Infof("Dropping generate request %q out of the queue: %v", key, err)
c.queue.Forget(key) c.queue.Forget(key)
} }
func (c *Controller) syncGenerateRequest(key string) error { func (c *Controller) syncGenerateRequest(key string) error {
logger := c.log.WithValues("key", key)
var err error var err error
startTime := time.Now() startTime := time.Now()
logger.Info("started syncing generate request", "startTime", startTime) glog.V(4).Infof("Started syncing GR %q (%v)", key, startTime)
defer func() { defer func() {
logger.V(4).Info("finished syncying generate request", "processingTIme", time.Since(startTime)) glog.V(4).Infof("Finished syncing GR %q (%v)", key, time.Since(startTime))
}() }()
_, grName, err := cache.SplitMetaNamespaceKey(key) _, grName, err := cache.SplitMetaNamespaceKey(key)
if errors.IsNotFound(err) { if errors.IsNotFound(err) {
logger.Info("generate request has been deleted") glog.Infof("Generate Request %s has been deleted", key)
return nil return nil
} }
if err != nil { if err != nil {

View file

@ -1,9 +1,10 @@
package generate package generate
import ( import (
"fmt"
"time" "time"
"github.com/go-logr/logr" "github.com/golang/glog"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1" kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
kyvernoclient "github.com/nirmata/kyverno/pkg/client/clientset/versioned" kyvernoclient "github.com/nirmata/kyverno/pkg/client/clientset/versioned"
kyvernoinformer "github.com/nirmata/kyverno/pkg/client/informers/externalversions/kyverno/v1" kyvernoinformer "github.com/nirmata/kyverno/pkg/client/informers/externalversions/kyverno/v1"
@ -56,9 +57,9 @@ type Controller struct {
dynamicInformer dynamicinformer.DynamicSharedInformerFactory dynamicInformer dynamicinformer.DynamicSharedInformerFactory
//TODO: list of generic informers //TODO: list of generic informers
// only support Namespaces for re-evalutation on resource updates // only support Namespaces for re-evalutation on resource updates
nsInformer informers.GenericInformer nsInformer informers.GenericInformer
policyStatusListener policystatus.Listener policyStatusListener policystatus.Listener
log logr.Logger
} }
//NewController returns an instance of the Generate-Request Controller //NewController returns an instance of the Generate-Request Controller
@ -71,7 +72,6 @@ func NewController(
pvGenerator policyviolation.GeneratorInterface, pvGenerator policyviolation.GeneratorInterface,
dynamicInformer dynamicinformer.DynamicSharedInformerFactory, dynamicInformer dynamicinformer.DynamicSharedInformerFactory,
policyStatus policystatus.Listener, policyStatus policystatus.Listener,
log logr.Logger,
) *Controller { ) *Controller {
c := Controller{ c := Controller{
client: client, client: client,
@ -82,7 +82,6 @@ func NewController(
// as we dont want a deleted GR to be re-queue // as we dont want a deleted GR to be re-queue
queue: workqueue.NewNamedRateLimitingQueue(workqueue.NewItemExponentialFailureRateLimiter(1, 30), "generate-request"), queue: workqueue.NewNamedRateLimitingQueue(workqueue.NewItemExponentialFailureRateLimiter(1, 30), "generate-request"),
dynamicInformer: dynamicInformer, dynamicInformer: dynamicInformer,
log: log,
policyStatusListener: policyStatus, policyStatusListener: policyStatus,
} }
c.statusControl = StatusControl{client: kyvernoclient} c.statusControl = StatusControl{client: kyvernoclient}
@ -118,12 +117,11 @@ func NewController(
} }
func (c *Controller) updateGenericResource(old, cur interface{}) { func (c *Controller) updateGenericResource(old, cur interface{}) {
logger := c.log
curR := cur.(*unstructured.Unstructured) curR := cur.(*unstructured.Unstructured)
grs, err := c.grLister.GetGenerateRequestsForResource(curR.GetKind(), curR.GetNamespace(), curR.GetName()) grs, err := c.grLister.GetGenerateRequestsForResource(curR.GetKind(), curR.GetNamespace(), curR.GetName())
if err != nil { if err != nil {
logger.Error(err, "failed to get generate request CR for the resoource", "kind", curR.GetKind(), "name", curR.GetName(), "namespace", curR.GetNamespace()) glog.Errorf("failed to Generate Requests for resource %s/%s/%s: %v", curR.GetKind(), curR.GetNamespace(), curR.GetName(), err)
return return
} }
// re-evaluate the GR as the resource was updated // re-evaluate the GR as the resource was updated
@ -136,14 +134,13 @@ func (c *Controller) updateGenericResource(old, cur interface{}) {
func (c *Controller) enqueue(gr *kyverno.GenerateRequest) { func (c *Controller) enqueue(gr *kyverno.GenerateRequest) {
key, err := cache.MetaNamespaceKeyFunc(gr) key, err := cache.MetaNamespaceKeyFunc(gr)
if err != nil { if err != nil {
c.log.Error(err, "failed to extract name") glog.Error(err)
return return
} }
c.queue.Add(key) c.queue.Add(key)
} }
func (c *Controller) updatePolicy(old, cur interface{}) { func (c *Controller) updatePolicy(old, cur interface{}) {
logger := c.log
oldP := old.(*kyverno.ClusterPolicy) oldP := old.(*kyverno.ClusterPolicy)
curP := cur.(*kyverno.ClusterPolicy) curP := cur.(*kyverno.ClusterPolicy)
if oldP.ResourceVersion == curP.ResourceVersion { if oldP.ResourceVersion == curP.ResourceVersion {
@ -151,11 +148,11 @@ func (c *Controller) updatePolicy(old, cur interface{}) {
// Two different versions of the same replica set will always have different RVs. // Two different versions of the same replica set will always have different RVs.
return return
} }
logger.V(4).Info("updating policy", "name", oldP.Name) glog.V(4).Infof("Updating Policy %s", oldP.Name)
// get the list of GR for the current Policy version // get the list of GR for the current Policy version
grs, err := c.grLister.GetGenerateRequestsForClusterPolicy(curP.Name) grs, err := c.grLister.GetGenerateRequestsForClusterPolicy(curP.Name)
if err != nil { if err != nil {
logger.Error(err, "failed to generate request for policy", "name", curP.Name) glog.Errorf("failed to Generate Requests for policy %s: %v", curP.Name, err)
return return
} }
// re-evaluate the GR as the policy was updated // re-evaluate the GR as the policy was updated
@ -186,36 +183,34 @@ func (c *Controller) updateGR(old, cur interface{}) {
} }
func (c *Controller) deleteGR(obj interface{}) { func (c *Controller) deleteGR(obj interface{}) {
logger := c.log
gr, ok := obj.(*kyverno.GenerateRequest) gr, ok := obj.(*kyverno.GenerateRequest)
if !ok { if !ok {
tombstone, ok := obj.(cache.DeletedFinalStateUnknown) tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
if !ok { if !ok {
logger.Info("Couldn't get object from tombstone", "obj", obj) glog.Info(fmt.Errorf("Couldn't get object from tombstone %#v", obj))
return return
} }
_, ok = tombstone.Obj.(*kyverno.GenerateRequest) _, ok = tombstone.Obj.(*kyverno.GenerateRequest)
if !ok { if !ok {
logger.Info("tombstone contained object that is not a Generate Request CR", "obj", obj) glog.Info(fmt.Errorf("Tombstone contained object that is not a Generate Request %#v", obj))
return return
} }
} }
logger.Info("deleting generate request", "name", gr.Name) glog.V(4).Infof("Deleting GR %s", gr.Name)
// sync Handler will remove it from the queue // sync Handler will remove it from the queue
c.enqueueGR(gr) c.enqueueGR(gr)
} }
//Run ... //Run ...
func (c *Controller) Run(workers int, stopCh <-chan struct{}) { func (c *Controller) Run(workers int, stopCh <-chan struct{}) {
logger := c.log
defer utilruntime.HandleCrash() defer utilruntime.HandleCrash()
defer c.queue.ShutDown() defer c.queue.ShutDown()
logger.Info("starting") glog.Info("Starting generate-policy controller")
defer logger.Info("shutting down") defer glog.Info("Shutting down generate-policy controller")
if !cache.WaitForCacheSync(stopCh, c.pSynced, c.grSynced) { if !cache.WaitForCacheSync(stopCh, c.pSynced, c.grSynced) {
logger.Info("failed to sync informer cache") glog.Error("generate-policy controller: failed to sync informer cache")
return return
} }
for i := 0; i < workers; i++ { for i := 0; i < workers; i++ {
@ -244,29 +239,27 @@ func (c *Controller) processNextWorkItem() bool {
} }
func (c *Controller) handleErr(err error, key interface{}) { func (c *Controller) handleErr(err error, key interface{}) {
logger := c.log
if err == nil { if err == nil {
c.queue.Forget(key) c.queue.Forget(key)
return return
} }
if c.queue.NumRequeues(key) < maxRetries { if c.queue.NumRequeues(key) < maxRetries {
logger.Error(err, "failed to sync generate request", "key", key) glog.Errorf("Error syncing Generate Request %v: %v", key, err)
c.queue.AddRateLimited(key) c.queue.AddRateLimited(key)
return return
} }
utilruntime.HandleError(err) utilruntime.HandleError(err)
logger.Error(err, "Dropping generate request from the queue", "key", key) glog.Infof("Dropping generate request %q out of the queue: %v", key, err)
c.queue.Forget(key) c.queue.Forget(key)
} }
func (c *Controller) syncGenerateRequest(key string) error { func (c *Controller) syncGenerateRequest(key string) error {
logger := c.log
var err error var err error
startTime := time.Now() startTime := time.Now()
logger.Info("started sync", "key", key, "startTime", startTime) glog.V(4).Infof("Started syncing GR %q (%v)", key, startTime)
defer func() { defer func() {
logger.V(4).Info("finished sync", "key", key, "processingTime", time.Since(startTime)) glog.V(4).Infof("Finished syncing GR %q (%v)", key, time.Since(startTime))
}() }()
_, grName, err := cache.SplitMetaNamespaceKey(key) _, grName, err := cache.SplitMetaNamespaceKey(key)
if err != nil { if err != nil {
@ -275,7 +268,7 @@ func (c *Controller) syncGenerateRequest(key string) error {
gr, err := c.grLister.Get(grName) gr, err := c.grLister.Get(grName)
if err != nil { if err != nil {
logger.Error(err, "failed to list generate requests") glog.V(4).Info(err)
return err return err
} }
return c.processGR(gr) return c.processGR(gr)

View file

@ -5,7 +5,7 @@ import (
"fmt" "fmt"
"time" "time"
"github.com/go-logr/logr" "github.com/golang/glog"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1" kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
dclient "github.com/nirmata/kyverno/pkg/dclient" dclient "github.com/nirmata/kyverno/pkg/dclient"
"github.com/nirmata/kyverno/pkg/engine" "github.com/nirmata/kyverno/pkg/engine"
@ -17,7 +17,6 @@ import (
) )
func (c *Controller) processGR(gr *kyverno.GenerateRequest) error { func (c *Controller) processGR(gr *kyverno.GenerateRequest) error {
logger := c.log.WithValues("name", gr.Name, "policy", gr.Spec.Policy, "kind", gr.Spec.Resource.Kind, "namespace", gr.Spec.Resource.Namespace, "name", gr.Spec.Resource.Name)
var err error var err error
var resource *unstructured.Unstructured var resource *unstructured.Unstructured
var genResources []kyverno.ResourceSpec var genResources []kyverno.ResourceSpec
@ -25,46 +24,45 @@ func (c *Controller) processGR(gr *kyverno.GenerateRequest) error {
resource, err = getResource(c.client, gr.Spec.Resource) resource, err = getResource(c.client, gr.Spec.Resource)
if err != nil { if err != nil {
// Dont update status // Dont update status
logger.Error(err, "resource does not exist or is yet to be created, requeueing") glog.V(4).Infof("resource does not exist or is yet to be created, requeuing: %v", err)
return err return err
} }
// 2 - Apply the generate policy on the resource // 2 - Apply the generate policy on the resource
genResources, err = c.applyGenerate(*resource, *gr) genResources, err = c.applyGenerate(*resource, *gr)
// 3 - Report Events // 3 - Report Events
reportEvents(logger, err, c.eventGen, *gr, *resource) reportEvents(err, c.eventGen, *gr, *resource)
// 4 - Update Status // 4 - Update Status
return updateStatus(c.statusControl, *gr, err, genResources) return updateStatus(c.statusControl, *gr, err, genResources)
} }
func (c *Controller) applyGenerate(resource unstructured.Unstructured, gr kyverno.GenerateRequest) ([]kyverno.ResourceSpec, error) { func (c *Controller) applyGenerate(resource unstructured.Unstructured, gr kyverno.GenerateRequest) ([]kyverno.ResourceSpec, error) {
logger := c.log.WithValues("name", gr.Name, "policy", gr.Spec.Policy, "kind", gr.Spec.Resource.Kind, "namespace", gr.Spec.Resource.Namespace, "name", gr.Spec.Resource.Name)
// Get the list of rules to be applied // Get the list of rules to be applied
// get policy // get policy
policy, err := c.pLister.Get(gr.Spec.Policy) policy, err := c.pLister.Get(gr.Spec.Policy)
if err != nil { if err != nil {
logger.Error(err, "policy not found") glog.V(4).Infof("policy %s not found: %v", gr.Spec.Policy, err)
return nil, nil return nil, nil
} }
// build context // build context
ctx := context.NewContext() ctx := context.NewContext()
resourceRaw, err := resource.MarshalJSON() resourceRaw, err := resource.MarshalJSON()
if err != nil { if err != nil {
logger.Error(err, "failed to marshal resource") glog.V(4).Infof("failed to marshal resource: %v", err)
return nil, err return nil, err
} }
err = ctx.AddResource(resourceRaw) err = ctx.AddResource(resourceRaw)
if err != nil { if err != nil {
logger.Error(err, "failed to load resource in context") glog.Infof("Failed to load resource in context: %v", err)
return nil, err return nil, err
} }
err = ctx.AddUserInfo(gr.Spec.Context.UserRequestInfo) err = ctx.AddUserInfo(gr.Spec.Context.UserRequestInfo)
if err != nil { if err != nil {
logger.Error(err, "failed to load SA in context") glog.Infof("Failed to load userInfo in context: %v", err)
return nil, err return nil, err
} }
err = ctx.AddSA(gr.Spec.Context.UserRequestInfo.AdmissionUserInfo.Username) err = ctx.AddSA(gr.Spec.Context.UserRequestInfo.AdmissionUserInfo.Username)
if err != nil { if err != nil {
logger.Error(err, "failed to load UserInfo in context") glog.Infof("Failed to load serviceAccount in context: %v", err)
return nil, err return nil, err
} }
@ -78,12 +76,12 @@ func (c *Controller) applyGenerate(resource unstructured.Unstructured, gr kyvern
// check if the policy still applies to the resource // check if the policy still applies to the resource
engineResponse := engine.Generate(policyContext) engineResponse := engine.Generate(policyContext)
if len(engineResponse.PolicyResponse.Rules) == 0 { if len(engineResponse.PolicyResponse.Rules) == 0 {
logger.V(4).Info("policy does not apply to resource") glog.V(4).Infof("policy %s, dont not apply to resource %v", gr.Spec.Policy, gr.Spec.Resource)
return nil, fmt.Errorf("policy %s, dont not apply to resource %v", gr.Spec.Policy, gr.Spec.Resource) return nil, fmt.Errorf("policy %s, dont not apply to resource %v", gr.Spec.Policy, gr.Spec.Resource)
} }
// Apply the generate rule on resource // Apply the generate rule on resource
return c.applyGeneratePolicy(logger, policyContext, gr) return c.applyGeneratePolicy(policyContext, gr)
} }
func updateStatus(statusControl StatusControlInterface, gr kyverno.GenerateRequest, err error, genResources []kyverno.ResourceSpec) error { func updateStatus(statusControl StatusControlInterface, gr kyverno.GenerateRequest, err error, genResources []kyverno.ResourceSpec) error {
@ -95,7 +93,7 @@ func updateStatus(statusControl StatusControlInterface, gr kyverno.GenerateReque
return statusControl.Success(gr, genResources) return statusControl.Success(gr, genResources)
} }
func (c *Controller) applyGeneratePolicy(log logr.Logger, policyContext engine.PolicyContext, gr kyverno.GenerateRequest) ([]kyverno.ResourceSpec, error) { func (c *Controller) applyGeneratePolicy(policyContext engine.PolicyContext, gr kyverno.GenerateRequest) ([]kyverno.ResourceSpec, error) {
// List of generatedResources // List of generatedResources
var genResources []kyverno.ResourceSpec var genResources []kyverno.ResourceSpec
// Get the response as the actions to be performed on the resource // Get the response as the actions to be performed on the resource
@ -115,8 +113,9 @@ func (c *Controller) applyGeneratePolicy(log logr.Logger, policyContext engine.P
if !rule.HasGenerate() { if !rule.HasGenerate() {
continue continue
} }
startTime := time.Now() startTime := time.Now()
genResource, err := applyRule(log, c.client, rule, resource, ctx, processExisting) genResource, err := applyRule(c.client, rule, resource, ctx, processExisting)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -173,7 +172,7 @@ func updateGenerateExecutionTime(newTime time.Duration, oldAverageTimeString str
return time.Duration(newAverageTimeInNanoSeconds) * time.Nanosecond return time.Duration(newAverageTimeInNanoSeconds) * time.Nanosecond
} }
func applyRule(log logr.Logger, client *dclient.Client, rule kyverno.Rule, resource unstructured.Unstructured, ctx context.EvalInterface, processExisting bool) (kyverno.ResourceSpec, error) { func applyRule(client *dclient.Client, rule kyverno.Rule, resource unstructured.Unstructured, ctx context.EvalInterface, processExisting bool) (kyverno.ResourceSpec, error) {
var rdata map[string]interface{} var rdata map[string]interface{}
var err error var err error
var mode ResourceMode var mode ResourceMode
@ -188,7 +187,7 @@ func applyRule(log logr.Logger, client *dclient.Client, rule kyverno.Rule, resou
// format : {{<variable_name}} // format : {{<variable_name}}
// - if there is variables that are not defined the context -> results in error and rule is not applied // - if there is variables that are not defined the context -> results in error and rule is not applied
// - valid variables are replaced with the values // - valid variables are replaced with the values
if _, err := variables.SubstituteVars(log, ctx, genUnst.Object); err != nil { if _, err := variables.SubstituteVars(ctx, genUnst.Object); err != nil {
return noGenResource, err return noGenResource, err
} }
genKind, _, err := unstructured.NestedString(genUnst.Object, "kind") genKind, _, err := unstructured.NestedString(genUnst.Object, "kind")
@ -220,9 +219,9 @@ func applyRule(log logr.Logger, client *dclient.Client, rule kyverno.Rule, resou
} }
if genData != nil { if genData != nil {
rdata, mode, err = manageData(log, genKind, genNamespace, genName, genData, client, resource) rdata, mode, err = manageData(genKind, genNamespace, genName, genData, client, resource)
} else { } else {
rdata, mode, err = manageClone(log, genKind, genNamespace, genName, genCopy, client, resource) rdata, mode, err = manageClone(genKind, genNamespace, genName, genCopy, client, resource)
} }
if err != nil { if err != nil {
return noGenResource, err return noGenResource, err
@ -249,38 +248,38 @@ func applyRule(log logr.Logger, client *dclient.Client, rule kyverno.Rule, resou
// - app.kubernetes.io/managed-by: kyverno // - app.kubernetes.io/managed-by: kyverno
// - kyverno.io/generated-by: kind/namespace/name (trigger resource) // - kyverno.io/generated-by: kind/namespace/name (trigger resource)
manageLabels(newResource, resource) manageLabels(newResource, resource)
logger := log.WithValues("genKind", genKind, "genNamespace", genNamespace, "genName", genName)
if mode == Create { if mode == Create {
// Reset resource version // Reset resource version
newResource.SetResourceVersion("") newResource.SetResourceVersion("")
// Create the resource // Create the resource
logger.V(4).Info("creating new resource") glog.V(4).Infof("Creating new resource %s/%s/%s", genKind, genNamespace, genName)
_, err = client.CreateResource(genKind, genNamespace, newResource, false) _, err = client.CreateResource(genKind, genNamespace, newResource, false)
if err != nil { if err != nil {
// Failed to create resource // Failed to create resource
return noGenResource, err return noGenResource, err
} }
logger.V(4).Info("created new resource") glog.V(4).Infof("Created new resource %s/%s/%s", genKind, genNamespace, genName)
} else if mode == Update { } else if mode == Update {
logger.V(4).Info("updating existing resource") glog.V(4).Infof("Updating existing resource %s/%s/%s", genKind, genNamespace, genName)
// Update the resource // Update the resource
_, err := client.UpdateResource(genKind, genNamespace, newResource, false) _, err := client.UpdateResource(genKind, genNamespace, newResource, false)
if err != nil { if err != nil {
// Failed to update resource // Failed to update resource
return noGenResource, err return noGenResource, err
} }
logger.V(4).Info("updated new resource") glog.V(4).Infof("Updated existing resource %s/%s/%s", genKind, genNamespace, genName)
} }
return newGenResource, nil return newGenResource, nil
} }
func manageData(log logr.Logger, kind, namespace, name string, data map[string]interface{}, client *dclient.Client, resource unstructured.Unstructured) (map[string]interface{}, ResourceMode, error) { func manageData(kind, namespace, name string, data map[string]interface{}, client *dclient.Client, resource unstructured.Unstructured) (map[string]interface{}, ResourceMode, error) {
// check if resource to be generated exists // check if resource to be generated exists
obj, err := client.GetResource(kind, namespace, name) obj, err := client.GetResource(kind, namespace, name)
if apierrors.IsNotFound(err) { if apierrors.IsNotFound(err) {
log.Error(err, "resource does not exist, will try to create", "genKind", kind, "genNamespace", namespace, "genName", name) glog.V(4).Infof("Resource %s/%s/%s does not exists, will try to create", kind, namespace, name)
return data, Create, nil return data, Create, nil
} }
if err != nil { if err != nil {
@ -289,17 +288,18 @@ func manageData(log logr.Logger, kind, namespace, name string, data map[string]i
return nil, Skip, err return nil, Skip, err
} }
// Resource exists; verfiy the content of the resource // Resource exists; verfiy the content of the resource
err = checkResource(log, data, obj) err = checkResource(data, obj)
if err == nil { if err == nil {
// Existing resource does contain the mentioned configuration in spec, skip processing the resource as it is already in expected state // Existing resource does contain the mentioned configuration in spec, skip processing the resource as it is already in expected state
return nil, Skip, nil return nil, Skip, nil
} }
log.Info("to be generated resoruce already exists, but is missing the specifeid configurations, will try to update", "genKind", kind, "genNamespace", namespace, "genName", name)
glog.V(4).Infof("Resource %s/%s/%s exists but missing required configuration, will try to update", kind, namespace, name)
return data, Update, nil return data, Update, nil
} }
func manageClone(log logr.Logger, kind, namespace, name string, clone map[string]interface{}, client *dclient.Client, resource unstructured.Unstructured) (map[string]interface{}, ResourceMode, error) { func manageClone(kind, namespace, name string, clone map[string]interface{}, client *dclient.Client, resource unstructured.Unstructured) (map[string]interface{}, ResourceMode, error) {
// check if resource to be generated exists // check if resource to be generated exists
_, err := client.GetResource(kind, namespace, name) _, err := client.GetResource(kind, namespace, name)
if err == nil { if err == nil {
@ -308,7 +308,6 @@ func manageClone(log logr.Logger, kind, namespace, name string, clone map[string
} }
//TODO: check this //TODO: check this
if !apierrors.IsNotFound(err) { if !apierrors.IsNotFound(err) {
log.Error(err, "reference/clone resource is not found", "genKind", kind, "genNamespace", namespace, "genName", name)
//something wrong while fetching resource //something wrong while fetching resource
return nil, Skip, err return nil, Skip, err
} }
@ -326,6 +325,8 @@ func manageClone(log logr.Logger, kind, namespace, name string, clone map[string
// attempting to clone it self, this will fail -> short-ciruit it // attempting to clone it self, this will fail -> short-ciruit it
return nil, Skip, nil return nil, Skip, nil
} }
glog.V(4).Infof("check if resource %s/%s/%s exists", kind, newRNs, newRName)
// check if the resource as reference in clone exists? // check if the resource as reference in clone exists?
obj, err := client.GetResource(kind, newRNs, newRName) obj, err := client.GetResource(kind, newRNs, newRName)
if err != nil { if err != nil {
@ -348,10 +349,10 @@ const (
Update = "UPDATE" Update = "UPDATE"
) )
func checkResource(log logr.Logger, newResourceSpec interface{}, resource *unstructured.Unstructured) error { func checkResource(newResourceSpec interface{}, resource *unstructured.Unstructured) error {
// check if the resource spec if a subset of the resource // check if the resource spec if a subset of the resource
if path, err := validate.ValidateResourceWithPattern(log, resource.Object, newResourceSpec); err != nil { if path, err := validate.ValidateResourceWithPattern(resource.Object, newResourceSpec); err != nil {
log.Error(err, "Failed to match the resource ", "path", path) glog.V(4).Infof("Failed to match the resource at path %s: err %v", path, err)
return err return err
} }
return nil return nil

View file

@ -3,8 +3,8 @@ package generate
import ( import (
"fmt" "fmt"
"github.com/golang/glog"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"sigs.k8s.io/controller-runtime/pkg/log"
) )
func manageLabels(unstr *unstructured.Unstructured, triggerResource unstructured.Unstructured) { func manageLabels(unstr *unstructured.Unstructured, triggerResource unstructured.Unstructured) {
@ -30,7 +30,7 @@ func managedBy(labels map[string]string) {
val, ok := labels[key] val, ok := labels[key]
if ok { if ok {
if val != value { if val != value {
log.Log.Info(fmt.Sprintf("resource managed by %s, kyverno wont over-ride the label", val)) glog.Infof("resource managed by %s, kyverno wont over-ride the label", val)
return return
} }
} }
@ -46,7 +46,7 @@ func generatedBy(labels map[string]string, triggerResource unstructured.Unstruct
val, ok := labels[key] val, ok := labels[key]
if ok { if ok {
if val != value { if val != value {
log.Log.Info(fmt.Sprintf("resource generated by %s, kyverno wont over-ride the label", val)) glog.Infof("resource generated by %s, kyverno wont over-ride the label", val)
return return
} }
} }

View file

@ -3,13 +3,13 @@ package generate
import ( import (
"fmt" "fmt"
"github.com/go-logr/logr" "github.com/golang/glog"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1" kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
"github.com/nirmata/kyverno/pkg/event" "github.com/nirmata/kyverno/pkg/event"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
) )
func reportEvents(log logr.Logger, err error, eventGen event.Interface, gr kyverno.GenerateRequest, resource unstructured.Unstructured) { func reportEvents(err error, eventGen event.Interface, gr kyverno.GenerateRequest, resource unstructured.Unstructured) {
if err == nil { if err == nil {
// Success Events // Success Events
// - resource -> policy rule applied successfully // - resource -> policy rule applied successfully
@ -18,6 +18,7 @@ func reportEvents(log logr.Logger, err error, eventGen event.Interface, gr kyver
eventGen.Add(events...) eventGen.Add(events...)
return return
} }
glog.V(4).Infof("reporing events for %v", err)
events := failedEvents(err, gr, resource) events := failedEvents(err, gr, resource)
eventGen.Add(events...) eventGen.Add(events...)
} }

View file

@ -1,9 +1,9 @@
package generate package generate
import ( import (
"github.com/golang/glog"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1" kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
kyvernoclient "github.com/nirmata/kyverno/pkg/client/clientset/versioned" kyvernoclient "github.com/nirmata/kyverno/pkg/client/clientset/versioned"
"sigs.k8s.io/controller-runtime/pkg/log"
) )
//StatusControlInterface provides interface to update status subresource //StatusControlInterface provides interface to update status subresource
@ -25,10 +25,10 @@ func (sc StatusControl) Failed(gr kyverno.GenerateRequest, message string, genRe
gr.Status.GeneratedResources = genResources gr.Status.GeneratedResources = genResources
_, err := sc.client.KyvernoV1().GenerateRequests("kyverno").UpdateStatus(&gr) _, err := sc.client.KyvernoV1().GenerateRequests("kyverno").UpdateStatus(&gr)
if err != nil { if err != nil {
log.Log.Error(err, "failed to update generate request status", "name", gr.Name) glog.V(4).Infof("FAILED: updated gr %s status to %s", gr.Name, string(kyverno.Failed))
return err return err
} }
log.Log.Info("updated generate request status", "name", gr.Name, "status", string(kyverno.Failed)) glog.V(4).Infof("updated gr %s status to %s", gr.Name, string(kyverno.Failed))
return nil return nil
} }
@ -41,9 +41,9 @@ func (sc StatusControl) Success(gr kyverno.GenerateRequest, genResources []kyver
_, err := sc.client.KyvernoV1().GenerateRequests("kyverno").UpdateStatus(&gr) _, err := sc.client.KyvernoV1().GenerateRequests("kyverno").UpdateStatus(&gr)
if err != nil { if err != nil {
log.Log.Error(err, "failed to update generate request status", "name", gr.Name) glog.V(4).Infof("FAILED: updated gr %s status to %s", gr.Name, string(kyverno.Completed))
return err return err
} }
log.Log.Info("updated generate request status", "name", gr.Name, "status", string(kyverno.Completed)) glog.V(4).Infof("updated gr %s status to %s", gr.Name, string(kyverno.Completed))
return nil return nil
} }

View file

@ -13,6 +13,8 @@ import (
policy2 "github.com/nirmata/kyverno/pkg/policy" policy2 "github.com/nirmata/kyverno/pkg/policy"
"github.com/golang/glog"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/discovery" "k8s.io/client-go/discovery"
@ -32,7 +34,6 @@ import (
yamlv2 "gopkg.in/yaml.v2" yamlv2 "gopkg.in/yaml.v2"
"k8s.io/cli-runtime/pkg/genericclioptions" "k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/kubernetes/scheme"
log "sigs.k8s.io/controller-runtime/pkg/log"
) )
func Command() *cobra.Command { func Command() *cobra.Command {
@ -50,7 +51,7 @@ func Command() *cobra.Command {
defer func() { defer func() {
if err != nil { if err != nil {
if !sanitizedError.IsErrorSanitized(err) { if !sanitizedError.IsErrorSanitized(err) {
log.Log.Error(err, "failed to sanitize") glog.V(4).Info(err)
err = fmt.Errorf("Internal error") err = fmt.Errorf("Internal error")
} }
} }
@ -70,7 +71,7 @@ func Command() *cobra.Command {
} }
for _, policy := range policies { for _, policy := range policies {
err := policy2.Validate(utils.MarshalPolicy(*policy), nil, true) err := policy2.Validate(utils.MarshalPolicy(*policy))
if err != nil { if err != nil {
return sanitizedError.New(fmt.Sprintf("Policy %v is not valid", policy.Name)) return sanitizedError.New(fmt.Sprintf("Policy %v is not valid", policy.Name))
} }

View file

@ -9,9 +9,6 @@ import (
"github.com/nirmata/kyverno/pkg/kyverno/apply" "github.com/nirmata/kyverno/pkg/kyverno/apply"
"github.com/nirmata/kyverno/pkg/kyverno/version" "github.com/nirmata/kyverno/pkg/kyverno/version"
"k8s.io/klog"
"k8s.io/klog/klogr"
log "sigs.k8s.io/controller-runtime/pkg/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -22,7 +19,7 @@ func CLI() {
Short: "kyverno manages native policies of Kubernetes", Short: "kyverno manages native policies of Kubernetes",
} }
configurelog(cli) configureGlog(cli)
commands := []*cobra.Command{ commands := []*cobra.Command{
version.Command(), version.Command(),
@ -39,9 +36,9 @@ func CLI() {
} }
} }
func configurelog(cli *cobra.Command) { func configureGlog(cli *cobra.Command) {
klog.InitFlags(nil) flag.Parse()
log.SetLogger(klogr.New()) _ = flag.Set("logtostderr", "true")
cli.PersistentFlags().AddGoFlagSet(flag.CommandLine) cli.PersistentFlags().AddGoFlagSet(flag.CommandLine)
_ = cli.PersistentFlags().MarkHidden("alsologtostderr") _ = cli.PersistentFlags().MarkHidden("alsologtostderr")

View file

@ -11,12 +11,13 @@ import (
"github.com/nirmata/kyverno/pkg/kyverno/sanitizedError" "github.com/nirmata/kyverno/pkg/kyverno/sanitizedError"
"github.com/golang/glog"
policyvalidate "github.com/nirmata/kyverno/pkg/policy" policyvalidate "github.com/nirmata/kyverno/pkg/policy"
v1 "github.com/nirmata/kyverno/pkg/api/kyverno/v1" v1 "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/util/yaml" "k8s.io/apimachinery/pkg/util/yaml"
log "sigs.k8s.io/controller-runtime/pkg/log"
) )
func Command() *cobra.Command { func Command() *cobra.Command {
@ -28,7 +29,7 @@ func Command() *cobra.Command {
defer func() { defer func() {
if err != nil { if err != nil {
if !sanitizedError.IsErrorSanitized(err) { if !sanitizedError.IsErrorSanitized(err) {
log.Log.Error(err, "failed to sanitize") glog.V(4).Info(err)
err = fmt.Errorf("Internal error") err = fmt.Errorf("Internal error")
} }
} }
@ -44,7 +45,7 @@ func Command() *cobra.Command {
} }
for _, policy := range policies { for _, policy := range policies {
err = policyvalidate.Validate(utils.MarshalPolicy(*policy), nil, true) err = policyvalidate.Validate(utils.MarshalPolicy(*policy))
if err != nil { if err != nil {
fmt.Println("Policy " + policy.Name + " is invalid") fmt.Println("Policy " + policy.Name + " is invalid")
} else { } else {

View file

@ -6,12 +6,13 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"github.com/golang/glog"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
"github.com/googleapis/gnostic/compiler" "github.com/googleapis/gnostic/compiler"
openapi_v2 "github.com/googleapis/gnostic/OpenAPIv2" openapi_v2 "github.com/googleapis/gnostic/OpenAPIv2"
log "sigs.k8s.io/controller-runtime/pkg/log"
client "github.com/nirmata/kyverno/pkg/dclient" client "github.com/nirmata/kyverno/pkg/dclient"
"k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/util/wait"
@ -43,12 +44,12 @@ func NewCRDSync(client *client.Client) *crdSync {
func (c *crdSync) Run(workers int, stopCh <-chan struct{}) { func (c *crdSync) Run(workers int, stopCh <-chan struct{}) {
newDoc, err := c.client.DiscoveryClient.OpenAPISchema() newDoc, err := c.client.DiscoveryClient.OpenAPISchema()
if err != nil { if err != nil {
log.Log.Error(err, "cannot get openapi schema") glog.V(4).Infof("cannot get openapi schema: %v", err)
} }
err = useOpenApiDocument(newDoc) err = useOpenApiDocument(newDoc)
if err != nil { if err != nil {
log.Log.Error(err, "Could not set custom OpenApi document") glog.V(4).Infof("Could not set custom OpenApi document: %v\n", err)
} }
// Sync CRD before kyverno starts // Sync CRD before kyverno starts
@ -62,7 +63,7 @@ func (c *crdSync) Run(workers int, stopCh <-chan struct{}) {
func (c *crdSync) sync() { func (c *crdSync) sync() {
crds, err := c.client.ListResource("CustomResourceDefinition", "", nil) crds, err := c.client.ListResource("CustomResourceDefinition", "", nil)
if err != nil { if err != nil {
log.Log.Error(err, "could not fetch crd's from server") glog.V(4).Infof("could not fetch crd's from server: %v", err)
return return
} }
@ -92,7 +93,7 @@ func parseCRD(crd unstructured.Unstructured) {
crdName := crdDefinition.Spec.Names.Kind crdName := crdDefinition.Spec.Names.Kind
if len(crdDefinition.Spec.Versions) < 1 { if len(crdDefinition.Spec.Versions) < 1 {
log.Log.V(4).Info("could not parse crd schema, no versions present") glog.V(4).Infof("could not parse crd schema, no versions present")
return return
} }
@ -103,7 +104,7 @@ func parseCRD(crd unstructured.Unstructured) {
parsedSchema, err := openapi_v2.NewSchema(schema, compiler.NewContext("schema", nil)) parsedSchema, err := openapi_v2.NewSchema(schema, compiler.NewContext("schema", nil))
if err != nil { if err != nil {
log.Log.Error(err, "could not parse crd schema:") glog.V(4).Infof("could not parse crd schema:%v", err)
return return
} }

View file

@ -8,9 +8,12 @@ import (
"strings" "strings"
"sync" "sync"
data "github.com/nirmata/kyverno/api"
"github.com/nirmata/kyverno/pkg/engine/utils" "github.com/nirmata/kyverno/pkg/engine/utils"
"github.com/nirmata/kyverno/data"
"github.com/golang/glog"
"github.com/nirmata/kyverno/pkg/engine" "github.com/nirmata/kyverno/pkg/engine"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@ -20,7 +23,6 @@ import (
"github.com/googleapis/gnostic/compiler" "github.com/googleapis/gnostic/compiler"
"k8s.io/kube-openapi/pkg/util/proto" "k8s.io/kube-openapi/pkg/util/proto"
"k8s.io/kube-openapi/pkg/util/proto/validation" "k8s.io/kube-openapi/pkg/util/proto/validation"
log "sigs.k8s.io/controller-runtime/pkg/log"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
) )
@ -118,7 +120,7 @@ func validatePolicyMutation(policy v1.ClusterPolicy) error {
newPolicy.Spec.Rules = rules newPolicy.Spec.Rules = rules
resource, _ := generateEmptyResource(openApiGlobalState.definitions[openApiGlobalState.kindToDefinitionName[kind]]).(map[string]interface{}) resource, _ := generateEmptyResource(openApiGlobalState.definitions[openApiGlobalState.kindToDefinitionName[kind]]).(map[string]interface{})
if resource == nil { if resource == nil {
log.Log.V(4).Info(fmt.Sprintf("Cannot Validate policy: openApi definition now found for %v", kind)) glog.V(4).Infof("Cannot Validate policy: openApi definition now found for %v", kind)
return nil return nil
} }
newResource := unstructured.Unstructured{Object: resource} newResource := unstructured.Unstructured{Object: resource}

View file

@ -1,61 +0,0 @@
package policy
import (
"fmt"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
dclient "github.com/nirmata/kyverno/pkg/dclient"
"github.com/nirmata/kyverno/pkg/policy/generate"
"github.com/nirmata/kyverno/pkg/policy/mutate"
"github.com/nirmata/kyverno/pkg/policy/validate"
"sigs.k8s.io/controller-runtime/pkg/log"
)
//Validation provides methods to validate a rule
type Validation interface {
Validate() (string, error)
}
//validateAction performs validation on the rule actions
// - Mutate
// - Validation
// - Generate
func validateActions(idx int, rule kyverno.Rule, client *dclient.Client, mock bool) error {
var checker Validation
// Mutate
if rule.HasMutate() {
checker = mutate.NewMutateFactory(rule.Mutation)
if path, err := checker.Validate(); err != nil {
return fmt.Errorf("path: spec.rules[%d].mutate.%s.: %v", idx, path, err)
}
}
// Validate
if rule.HasValidate() {
checker = validate.NewValidateFactory(rule.Validation)
if path, err := checker.Validate(); err != nil {
return fmt.Errorf("path: spec.rules[%d].validate.%s.: %v", idx, path, err)
}
}
// Generate
if rule.HasGenerate() {
//TODO: this check is there to support offline validations
// generate uses selfSubjectReviews to verify actions
// this need to modified to use different implementation for online and offline mode
if mock {
checker = generate.NewFakeGenerate(rule.Generation)
if path, err := checker.Validate(); err != nil {
return fmt.Errorf("path: spec.rules[%d].generate.%s.: %v", idx, path, err)
}
} else {
checker = generate.NewGenerateFactory(client, rule.Generation, log.Log)
if path, err := checker.Validate(); err != nil {
return fmt.Errorf("path: spec.rules[%d].generate.%s.: %v", idx, path, err)
}
}
}
return nil
}

View file

@ -8,7 +8,7 @@ import (
"time" "time"
jsonpatch "github.com/evanphx/json-patch" jsonpatch "github.com/evanphx/json-patch"
"github.com/go-logr/logr" "github.com/golang/glog"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1" kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
"github.com/nirmata/kyverno/pkg/engine" "github.com/nirmata/kyverno/pkg/engine"
"github.com/nirmata/kyverno/pkg/engine/context" "github.com/nirmata/kyverno/pkg/engine/context"
@ -19,12 +19,12 @@ import (
// applyPolicy applies policy on a resource // applyPolicy applies policy on a resource
//TODO: generation rules //TODO: generation rules
func applyPolicy(policy kyverno.ClusterPolicy, resource unstructured.Unstructured, logger logr.Logger) (responses []response.EngineResponse) { func applyPolicy(policy kyverno.ClusterPolicy, resource unstructured.Unstructured) (responses []response.EngineResponse) {
startTime := time.Now() startTime := time.Now()
logger.Info("start applying policy", "startTime", startTime) glog.V(4).Infof("Started apply policy %s on resource %s/%s/%s (%v)", policy.Name, resource.GetKind(), resource.GetNamespace(), resource.GetName(), startTime)
defer func() { defer func() {
logger.Info("finisnhed applying policy", "processingTime", time.Since(startTime)) glog.V(4).Infof("Finished applying %s on resource %s/%s/%s (%v)", policy.Name, resource.GetKind(), resource.GetNamespace(), resource.GetName(), time.Since(startTime))
}() }()
var engineResponses []response.EngineResponse var engineResponses []response.EngineResponse
@ -32,15 +32,13 @@ func applyPolicy(policy kyverno.ClusterPolicy, resource unstructured.Unstructure
var err error var err error
// build context // build context
ctx := context.NewContext() ctx := context.NewContext()
err = ctx.AddResource(transformResource(resource)) ctx.AddResource(transformResource(resource))
if err != nil {
logger.Error(err, "enable to add transform resource to ctx")
}
//MUTATION //MUTATION
engineResponse, err = mutation(policy, resource, ctx, logger) engineResponse, err = mutation(policy, resource, ctx)
engineResponses = append(engineResponses, engineResponse) engineResponses = append(engineResponses, engineResponse)
if err != nil { if err != nil {
logger.Error(err, "failed to process mutation rule") glog.Errorf("unable to process mutation rules: %v", err)
} }
//VALIDATION //VALIDATION
@ -50,52 +48,52 @@ func applyPolicy(policy kyverno.ClusterPolicy, resource unstructured.Unstructure
//TODO: GENERATION //TODO: GENERATION
return engineResponses return engineResponses
} }
func mutation(policy kyverno.ClusterPolicy, resource unstructured.Unstructured, ctx context.EvalInterface, log logr.Logger) (response.EngineResponse, error) { func mutation(policy kyverno.ClusterPolicy, resource unstructured.Unstructured, ctx context.EvalInterface) (response.EngineResponse, error) {
engineResponse := engine.Mutate(engine.PolicyContext{Policy: policy, NewResource: resource, Context: ctx}) engineResponse := engine.Mutate(engine.PolicyContext{Policy: policy, NewResource: resource, Context: ctx})
if !engineResponse.IsSuccesful() { if !engineResponse.IsSuccesful() {
log.V(4).Info("failed to apply mutation rules; reporting them") glog.V(4).Infof("mutation had errors reporting them")
return engineResponse, nil return engineResponse, nil
} }
// Verify if the JSON pathes returned by the Mutate are already applied to the resource // Verify if the JSON pathes returned by the Mutate are already applied to the resource
if reflect.DeepEqual(resource, engineResponse.PatchedResource) { if reflect.DeepEqual(resource, engineResponse.PatchedResource) {
// resources matches // resources matches
log.V(4).Info("resource already satisfys the policy") glog.V(4).Infof("resource %s/%s/%s satisfies policy %s", engineResponse.PolicyResponse.Resource.Kind, engineResponse.PolicyResponse.Resource.Namespace, engineResponse.PolicyResponse.Resource.Name, engineResponse.PolicyResponse.Policy)
return engineResponse, nil return engineResponse, nil
} }
return getFailedOverallRuleInfo(resource, engineResponse, log) return getFailedOverallRuleInfo(resource, engineResponse)
} }
// getFailedOverallRuleInfo gets detailed info for over-all mutation failure // getFailedOverallRuleInfo gets detailed info for over-all mutation failure
func getFailedOverallRuleInfo(resource unstructured.Unstructured, engineResponse response.EngineResponse, log logr.Logger) (response.EngineResponse, error) { func getFailedOverallRuleInfo(resource unstructured.Unstructured, engineResponse response.EngineResponse) (response.EngineResponse, error) {
rawResource, err := resource.MarshalJSON() rawResource, err := resource.MarshalJSON()
if err != nil { if err != nil {
log.Error(err, "faield to marshall resource") glog.V(4).Infof("unable to marshal resource: %v\n", err)
return response.EngineResponse{}, err return response.EngineResponse{}, err
} }
// resource does not match so there was a mutation rule violated // resource does not match so there was a mutation rule violated
for index, rule := range engineResponse.PolicyResponse.Rules { for index, rule := range engineResponse.PolicyResponse.Rules {
log.V(4).Info("veriying if policy rule was applied before", "rule", rule.Name) glog.V(4).Infof("veriying if policy %s rule %s was applied before to resource %s/%s/%s", engineResponse.PolicyResponse.Policy, rule.Name, engineResponse.PolicyResponse.Resource.Kind, engineResponse.PolicyResponse.Resource.Namespace, engineResponse.PolicyResponse.Resource.Name)
if len(rule.Patches) == 0 { if len(rule.Patches) == 0 {
continue continue
} }
patch, err := jsonpatch.DecodePatch(utils.JoinPatches(rule.Patches)) patch, err := jsonpatch.DecodePatch(utils.JoinPatches(rule.Patches))
if err != nil { if err != nil {
log.Error(err, "failed to decode JSON patch", "patches", rule.Patches) glog.V(4).Infof("unable to decode patch %s: %v", rule.Patches, err)
return response.EngineResponse{}, err return response.EngineResponse{}, err
} }
// apply the patches returned by mutate to the original resource // apply the patches returned by mutate to the original resource
patchedResource, err := patch.Apply(rawResource) patchedResource, err := patch.Apply(rawResource)
if err != nil { if err != nil {
log.Error(err, "failed to apply JSON patch", "patches", rule.Patches) glog.V(4).Infof("unable to apply patch %s: %v", rule.Patches, err)
return response.EngineResponse{}, err return response.EngineResponse{}, err
} }
if !jsonpatch.Equal(patchedResource, rawResource) { if !jsonpatch.Equal(patchedResource, rawResource) {
log.V(4).Info("policy rule conditions not satisfied by resource", "rule", rule.Name) glog.V(4).Infof("policy %s rule %s condition not satisfied by existing resource", engineResponse.PolicyResponse.Policy, rule.Name)
engineResponse.PolicyResponse.Rules[index].Success = false engineResponse.PolicyResponse.Rules[index].Success = false
engineResponse.PolicyResponse.Rules[index].Message = fmt.Sprintf("mutation json patches not found at resource path %s", extractPatchPath(rule.Patches, log)) engineResponse.PolicyResponse.Rules[index].Message = fmt.Sprintf("mutation json patches not found at resource path %s", extractPatchPath(rule.Patches))
} }
} }
return engineResponse, nil return engineResponse, nil
@ -107,14 +105,14 @@ type jsonPatch struct {
Value interface{} `json:"value"` Value interface{} `json:"value"`
} }
func extractPatchPath(patches [][]byte, log logr.Logger) string { func extractPatchPath(patches [][]byte) string {
var resultPath []string var resultPath []string
// extract the patch path and value // extract the patch path and value
for _, patch := range patches { for _, patch := range patches {
log.V(4).Info("expected json patch not found in resource", "patch", string(patch)) glog.V(4).Infof("expected json patch not found in resource: %s", string(patch))
var data jsonPatch var data jsonPatch
if err := json.Unmarshal(patch, &data); err != nil { if err := json.Unmarshal(patch, &data); err != nil {
log.Error(err, "failed to decode the generate patch", "patch", string(patch)) glog.V(4).Infof("Failed to decode the generated patch %v: Error %v", string(patch), err)
continue continue
} }
resultPath = append(resultPath, data.Path) resultPath = append(resultPath, data.Path)

View file

@ -6,7 +6,6 @@ import (
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1" kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
"github.com/nirmata/kyverno/pkg/engine/context" "github.com/nirmata/kyverno/pkg/engine/context"
"github.com/nirmata/kyverno/pkg/engine/variables" "github.com/nirmata/kyverno/pkg/engine/variables"
"sigs.k8s.io/controller-runtime/pkg/log"
) )
//ContainsUserInfo returns error is userInfo is defined //ContainsUserInfo returns error is userInfo is defined
@ -36,23 +35,23 @@ func ContainsUserInfo(policy kyverno.ClusterPolicy) error {
filterVars := []string{"request.userInfo*", "serviceAccountName", "serviceAccountNamespace"} filterVars := []string{"request.userInfo*", "serviceAccountName", "serviceAccountNamespace"}
ctx := context.NewContext(filterVars...) ctx := context.NewContext(filterVars...)
for condIdx, condition := range rule.Conditions { for condIdx, condition := range rule.Conditions {
if condition.Key, err = variables.SubstituteVars(log.Log, ctx, condition.Key); err != nil { if condition.Key, err = variables.SubstituteVars(ctx, condition.Key); err != nil {
return fmt.Errorf("userInfo variable used at spec/rules[%d]/condition[%d]/key", idx, condIdx) return fmt.Errorf("userInfo variable used at spec/rules[%d]/condition[%d]/key", idx, condIdx)
} }
if condition.Value, err = variables.SubstituteVars(log.Log, ctx, condition.Value); err != nil { if condition.Value, err = variables.SubstituteVars(ctx, condition.Value); err != nil {
return fmt.Errorf("userInfo variable used at spec/rules[%d]/condition[%d]/value", idx, condIdx) return fmt.Errorf("userInfo variable used at spec/rules[%d]/condition[%d]/value", idx, condIdx)
} }
} }
if rule.Mutation.Overlay, err = variables.SubstituteVars(log.Log, ctx, rule.Mutation.Overlay); err != nil { if rule.Mutation.Overlay, err = variables.SubstituteVars(ctx, rule.Mutation.Overlay); err != nil {
return fmt.Errorf("userInfo variable used at spec/rules[%d]/mutate/overlay", idx) return fmt.Errorf("userInfo variable used at spec/rules[%d]/mutate/overlay", idx)
} }
if rule.Validation.Pattern, err = variables.SubstituteVars(log.Log, ctx, rule.Validation.Pattern); err != nil { if rule.Validation.Pattern, err = variables.SubstituteVars(ctx, rule.Validation.Pattern); err != nil {
return fmt.Errorf("userInfo variable used at spec/rules[%d]/validate/pattern", idx) return fmt.Errorf("userInfo variable used at spec/rules[%d]/validate/pattern", idx)
} }
for idx2, pattern := range rule.Validation.AnyPattern { for idx2, pattern := range rule.Validation.AnyPattern {
if rule.Validation.AnyPattern[idx2], err = variables.SubstituteVars(log.Log, ctx, pattern); err != nil { if rule.Validation.AnyPattern[idx2], err = variables.SubstituteVars(ctx, pattern); err != nil {
return fmt.Errorf("userInfo variable used at spec/rules[%d]/validate/anyPattern[%d]", idx, idx2) return fmt.Errorf("userInfo variable used at spec/rules[%d]/validate/anyPattern[%d]", idx, idx2)
} }
} }

View file

@ -4,71 +4,57 @@ import (
"fmt" "fmt"
"reflect" "reflect"
"github.com/go-logr/logr" "github.com/golang/glog"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1" kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
kyvernolister "github.com/nirmata/kyverno/pkg/client/listers/kyverno/v1" kyvernolister "github.com/nirmata/kyverno/pkg/client/listers/kyverno/v1"
"github.com/nirmata/kyverno/pkg/engine/response" "github.com/nirmata/kyverno/pkg/engine/response"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
) )
func (pc *PolicyController) cleanUp(ers []response.EngineResponse) {
for _, er := range ers {
if !er.IsSuccesful() {
continue
}
if len(er.PolicyResponse.Rules) == 0 {
continue
}
// clean up after the policy has been corrected
pc.cleanUpPolicyViolation(er.PolicyResponse)
}
}
func (pc *PolicyController) cleanUpPolicyViolation(pResponse response.PolicyResponse) { func (pc *PolicyController) cleanUpPolicyViolation(pResponse response.PolicyResponse) {
logger := pc.log
// - check if there is violation on resource (label:Selector) // - check if there is violation on resource (label:Selector)
if pResponse.Resource.Namespace == "" { if pResponse.Resource.Namespace == "" {
pv, err := getClusterPV(pc.cpvLister, pResponse.Policy, pResponse.Resource.Kind, pResponse.Resource.Name, logger) pv, err := getClusterPV(pc.cpvLister, pResponse.Policy, pResponse.Resource.Kind, pResponse.Resource.Name)
if err != nil { if err != nil {
logger.Error(err, "failed to get cluster policy violation on policy and resource", "policy", pResponse.Policy, "kind", pResponse.Resource.Kind, "name", pResponse.Resource.Name) glog.Errorf("failed to cleanUp violations: %v", err)
return return
} }
if reflect.DeepEqual(pv, kyverno.ClusterPolicyViolation{}) { if reflect.DeepEqual(pv, kyverno.ClusterPolicyViolation{}) {
return return
} }
glog.V(4).Infof("cleanup cluster violation %s on %s", pv.Name, pv.Spec.ResourceSpec.ToKey())
if err := pc.pvControl.DeleteClusterPolicyViolation(pv.Name); err != nil { if err := pc.pvControl.DeleteClusterPolicyViolation(pv.Name); err != nil {
logger.Error(err, "failed to delete cluster policy violation", "name", pv.Name) glog.Errorf("failed to delete cluster policy violation %s on %s: %v", pv.Name, pv.Spec.ResourceSpec.ToKey(), err)
} else {
logger.Info("deleted cluster policy violation", "name", pv.Name)
} }
return return
} }
// namespace policy violation // namespace policy violation
nspv, err := getNamespacedPV(pc.nspvLister, pResponse.Policy, pResponse.Resource.Kind, pResponse.Resource.Namespace, pResponse.Resource.Name, logger) nspv, err := getNamespacedPV(pc.nspvLister, pResponse.Policy, pResponse.Resource.Kind, pResponse.Resource.Namespace, pResponse.Resource.Name)
if err != nil { if err != nil {
logger.Error(err, "failed to get namespaced policy violation on policy and resource", "policy", pResponse.Policy, "kind", pResponse.Resource.Kind, "namespace", pResponse.Resource.Namespace, "name", pResponse.Resource.Name) glog.Error(err)
return return
} }
if reflect.DeepEqual(nspv, kyverno.PolicyViolation{}) { if reflect.DeepEqual(nspv, kyverno.PolicyViolation{}) {
return return
} }
glog.V(4).Infof("cleanup namespaced violation %s on %s.%s", nspv.Name, pResponse.Resource.Namespace, nspv.Spec.ResourceSpec.ToKey())
if err := pc.pvControl.DeleteNamespacedPolicyViolation(nspv.Namespace, nspv.Name); err != nil { if err := pc.pvControl.DeleteNamespacedPolicyViolation(nspv.Namespace, nspv.Name); err != nil {
logger.Error(err, "failed to delete cluster policy violation", "name", nspv.Name, "namespace", nspv.Namespace) glog.Errorf("failed to delete namespaced policy violation %s on %s: %v", nspv.Name, nspv.Spec.ResourceSpec.ToKey(), err)
} else {
logger.Info("deleted namespaced policy violation", "name", nspv.Name, "namespace", nspv.Namespace)
} }
} }
// Wont do the claiming of objects, just lookup based on selectors // Wont do the claiming of objects, just lookup based on selectors
func getClusterPV(pvLister kyvernolister.ClusterPolicyViolationLister, policyName, rkind, rname string, log logr.Logger) (kyverno.ClusterPolicyViolation, error) { func getClusterPV(pvLister kyvernolister.ClusterPolicyViolationLister, policyName, rkind, rname string) (kyverno.ClusterPolicyViolation, error) {
var err error var err error
// Check Violation on resource // Check Violation on resource
pvs, err := pvLister.List(labels.Everything()) pvs, err := pvLister.List(labels.Everything())
if err != nil { if err != nil {
log.Error(err, "failed to list cluster policy violations") glog.V(2).Infof("unable to list policy violations : %v", err)
return kyverno.ClusterPolicyViolation{}, fmt.Errorf("failed to list cluster pv: %v", err) return kyverno.ClusterPolicyViolation{}, fmt.Errorf("failed to list cluster pv: %v", err)
} }
@ -83,10 +69,10 @@ func getClusterPV(pvLister kyvernolister.ClusterPolicyViolationLister, policyNam
return kyverno.ClusterPolicyViolation{}, nil return kyverno.ClusterPolicyViolation{}, nil
} }
func getNamespacedPV(nspvLister kyvernolister.PolicyViolationLister, policyName, rkind, rnamespace, rname string, log logr.Logger) (kyverno.PolicyViolation, error) { func getNamespacedPV(nspvLister kyvernolister.PolicyViolationLister, policyName, rkind, rnamespace, rname string) (kyverno.PolicyViolation, error) {
nspvs, err := nspvLister.PolicyViolations(rnamespace).List(labels.Everything()) nspvs, err := nspvLister.PolicyViolations(rnamespace).List(labels.Everything())
if err != nil { if err != nil {
log.Error(err, "failed to list namespaced policy violation") glog.V(2).Infof("failed to list namespaced pv: %v", err)
return kyverno.PolicyViolation{}, fmt.Errorf("failed to list namespaced pv: %v", err) return kyverno.PolicyViolation{}, fmt.Errorf("failed to list namespaced pv: %v", err)
} }

View file

@ -1,13 +1,15 @@
package policy package policy
import ( import (
"fmt"
"github.com/golang/glog"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1" kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
"k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/cache"
) )
func (pc *PolicyController) addClusterPolicyViolation(obj interface{}) { func (pc *PolicyController) addClusterPolicyViolation(obj interface{}) {
pv := obj.(*kyverno.ClusterPolicyViolation) pv := obj.(*kyverno.ClusterPolicyViolation)
logger := pc.log.WithValues("kind", pv.Kind, "namespace", pv.Namespace, "name", pv.Name)
if pv.DeletionTimestamp != nil { if pv.DeletionTimestamp != nil {
// On a restart of the controller manager, it's possible for an object to // On a restart of the controller manager, it's possible for an object to
@ -20,15 +22,15 @@ func (pc *PolicyController) addClusterPolicyViolation(obj interface{}) {
ps := pc.getPolicyForClusterPolicyViolation(pv) ps := pc.getPolicyForClusterPolicyViolation(pv)
if len(ps) == 0 { if len(ps) == 0 {
// there is no cluster policy for this violation, so we can delete this cluster policy violation // there is no cluster policy for this violation, so we can delete this cluster policy violation
logger.V(4).Info("Cluster Policy Violation does not belong to an active policy, will be cleanedup") glog.V(4).Infof("Cluster Policy Violation %s does not belong to an active policy, will be cleanedup", pv.Name)
if err := pc.pvControl.DeleteClusterPolicyViolation(pv.Name); err != nil { if err := pc.pvControl.DeleteClusterPolicyViolation(pv.Name); err != nil {
logger.Error(err, "failed to delete resource") glog.Errorf("Failed to deleted cluster policy violation %s: %v", pv.Name, err)
return return
} }
logger.V(4).Info("resource deleted") glog.V(4).Infof("Cluster Policy Violation %s deleted", pv.Name)
return return
} }
logger.V(4).Info("resource added") glog.V(4).Infof("Cluster Policy Violation %s added.", pv.Name)
for _, p := range ps { for _, p := range ps {
pc.enqueuePolicy(p) pc.enqueuePolicy(p)
} }
@ -42,20 +44,19 @@ func (pc *PolicyController) updateClusterPolicyViolation(old, cur interface{}) {
// Two different versions of the same replica set will always have different RVs. // Two different versions of the same replica set will always have different RVs.
return return
} }
logger := pc.log.WithValues("kind", curPV.Kind, "namespace", curPV.Namespace, "name", curPV.Name)
ps := pc.getPolicyForClusterPolicyViolation(curPV) ps := pc.getPolicyForClusterPolicyViolation(curPV)
if len(ps) == 0 { if len(ps) == 0 {
// there is no cluster policy for this violation, so we can delete this cluster policy violation // there is no cluster policy for this violation, so we can delete this cluster policy violation
logger.V(4).Info("Cluster Policy Violation does not belong to an active policy, will be cleanedup") glog.V(4).Infof("Cluster Policy Violation %s does not belong to an active policy, will be cleanedup", curPV.Name)
if err := pc.pvControl.DeleteClusterPolicyViolation(curPV.Name); err != nil { if err := pc.pvControl.DeleteClusterPolicyViolation(curPV.Name); err != nil {
logger.Error(err, "failed to delete resource") glog.Errorf("Failed to deleted cluster policy violation %s: %v", curPV.Name, err)
return return
} }
logger.V(4).Info("resource deleted") glog.V(4).Infof("PolicyViolation %s deleted", curPV.Name)
return return
} }
logger.V(4).Info("resource updated") glog.V(4).Infof("Cluster PolicyViolation %s updated", curPV.Name)
for _, p := range ps { for _, p := range ps {
pc.enqueuePolicy(p) pc.enqueuePolicy(p)
} }
@ -66,7 +67,6 @@ func (pc *PolicyController) updateClusterPolicyViolation(old, cur interface{}) {
// a DeletionFinalStateUnknown marker item. // a DeletionFinalStateUnknown marker item.
func (pc *PolicyController) deleteClusterPolicyViolation(obj interface{}) { func (pc *PolicyController) deleteClusterPolicyViolation(obj interface{}) {
logger := pc.log
pv, ok := obj.(*kyverno.ClusterPolicyViolation) pv, ok := obj.(*kyverno.ClusterPolicyViolation)
// When a delete is dropped, the relist will notice a PolicyViolation in the store not // When a delete is dropped, the relist will notice a PolicyViolation in the store not
// in the list, leading to the insertion of a tombstone object which contains // in the list, leading to the insertion of a tombstone object which contains
@ -75,35 +75,33 @@ func (pc *PolicyController) deleteClusterPolicyViolation(obj interface{}) {
if !ok { if !ok {
tombstone, ok := obj.(cache.DeletedFinalStateUnknown) tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
if !ok { if !ok {
logger.Info("Couldn't get object from tombstone", "obj", obj) glog.Info(fmt.Errorf("Couldn't get object from tombstone %#v", obj))
return return
} }
pv, ok = tombstone.Obj.(*kyverno.ClusterPolicyViolation) pv, ok = tombstone.Obj.(*kyverno.ClusterPolicyViolation)
if !ok { if !ok {
logger.Info("Couldn't get object from tombstone", "obj", obj) glog.Info(fmt.Errorf("Couldn't get object from tombstone %#v", obj))
return return
} }
} }
logger = logger.WithValues("kind", pv.Kind, "namespace", pv.Namespace, "name", pv.Name)
ps := pc.getPolicyForClusterPolicyViolation(pv) ps := pc.getPolicyForClusterPolicyViolation(pv)
if len(ps) == 0 { if len(ps) == 0 {
// there is no cluster policy for this violation, so we can delete this cluster policy violation // there is no cluster policy for this violation, so we can delete this cluster policy violation
logger.V(4).Info("Cluster Policy Violation does not belong to an active policy, will be cleanedup") glog.V(4).Infof("Cluster Policy Violation %s does not belong to an active policy, will be cleanedup", pv.Name)
if err := pc.pvControl.DeleteClusterPolicyViolation(pv.Name); err != nil { if err := pc.pvControl.DeleteClusterPolicyViolation(pv.Name); err != nil {
logger.Error(err, "failed to delete resource") glog.Errorf("Failed to deleted cluster policy violation %s: %v", pv.Name, err)
return return
} }
logger.V(4).Info("resource deleted") glog.V(4).Infof("Cluster Policy Violation %s deleted", pv.Name)
return return
} }
logger.V(4).Info("resource updated") glog.V(4).Infof("Cluster PolicyViolation %s updated", pv.Name)
for _, p := range ps { for _, p := range ps {
pc.enqueuePolicy(p) pc.enqueuePolicy(p)
} }
} }
func (pc *PolicyController) getPolicyForClusterPolicyViolation(pv *kyverno.ClusterPolicyViolation) []*kyverno.ClusterPolicy { func (pc *PolicyController) getPolicyForClusterPolicyViolation(pv *kyverno.ClusterPolicyViolation) []*kyverno.ClusterPolicy {
logger := pc.log.WithValues("kind", pv.Kind, "namespace", pv.Namespace, "name", pv.Name)
policies, err := pc.pLister.GetPolicyForPolicyViolation(pv) policies, err := pc.pLister.GetPolicyForPolicyViolation(pv)
if err != nil || len(policies) == 0 { if err != nil || len(policies) == 0 {
return nil return nil
@ -115,7 +113,8 @@ func (pc *PolicyController) getPolicyForClusterPolicyViolation(pv *kyverno.Clust
if len(policies) > 1 { if len(policies) > 1 {
// ControllerRef will ensure we don't do anything crazy, but more than one // ControllerRef will ensure we don't do anything crazy, but more than one
// item in this list nevertheless constitutes user error. // item in this list nevertheless constitutes user error.
logger.V(4).Info("user error! more than one policy is selecting policy violation", "labels", pv.Labels, "policy", policies[0].Name) glog.V(4).Infof("user error! more than one policy is selecting policy violation %s with labels: %#v, returning %s",
pv.Name, pv.Labels, policies[0].Name)
} }
return policies return policies
} }

View file

@ -3,10 +3,10 @@ package policy
import ( import (
"fmt" "fmt"
"github.com/golang/glog"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
"sigs.k8s.io/controller-runtime/pkg/log"
) )
func buildPolicyLabel(policyName string) (labels.Selector, error) { func buildPolicyLabel(policyName string) (labels.Selector, error) {
@ -27,7 +27,7 @@ func buildPolicyLabel(policyName string) (labels.Selector, error) {
func transformResource(resource unstructured.Unstructured) []byte { func transformResource(resource unstructured.Unstructured) []byte {
data, err := resource.MarshalJSON() data, err := resource.MarshalJSON()
if err != nil { if err != nil {
log.Log.Error(err, "failed to marshal resource") glog.Errorf("failed to marshall resource %v: %v", resource, err)
return nil return nil
} }
return data return data

View file

@ -1,85 +0,0 @@
package common
import (
"fmt"
"regexp"
"strconv"
"github.com/nirmata/kyverno/pkg/engine/anchor"
)
//ValidatePattern validates the pattern
func ValidatePattern(patternElement interface{}, path string, supportedAnchors []anchor.IsAnchor) (string, error) {
switch typedPatternElement := patternElement.(type) {
case map[string]interface{}:
return validateMap(typedPatternElement, path, supportedAnchors)
case []interface{}:
return validateArray(typedPatternElement, path, supportedAnchors)
case string, float64, int, int64, bool, nil:
//TODO? check operator
return "", nil
default:
return path, fmt.Errorf("Validation rule failed at '%s', pattern contains unknown type", path)
}
}
func validateMap(patternMap map[string]interface{}, path string, supportedAnchors []anchor.IsAnchor) (string, error) {
// check if anchors are defined
for key, value := range patternMap {
// if key is anchor
// check regex () -> this is anchor
// ()
// single char ()
re, err := regexp.Compile(`^.?\(.+\)$`)
if err != nil {
return path + "/" + key, fmt.Errorf("Unable to parse the field %s: %v", key, err)
}
matched := re.MatchString(key)
// check the type of anchor
if matched {
// some type of anchor
// check if valid anchor
if !checkAnchors(key, supportedAnchors) {
return path + "/" + key, fmt.Errorf("Unsupported anchor %s", key)
}
// addition check for existence anchor
// value must be of type list
if anchor.IsExistenceAnchor(key) {
typedValue, ok := value.([]interface{})
if !ok {
return path + "/" + key, fmt.Errorf("Existence anchor should have value of type list")
}
// validate there is only one entry in the list
if len(typedValue) == 0 || len(typedValue) > 1 {
return path + "/" + key, fmt.Errorf("Existence anchor: single value expected, multiple specified")
}
}
}
// lets validate the values now :)
if errPath, err := ValidatePattern(value, path+"/"+key, supportedAnchors); err != nil {
return errPath, err
}
}
return "", nil
}
func validateArray(patternArray []interface{}, path string, supportedAnchors []anchor.IsAnchor) (string, error) {
for i, patternElement := range patternArray {
currentPath := path + strconv.Itoa(i) + "/"
// lets validate the values now :)
if errPath, err := ValidatePattern(patternElement, currentPath, supportedAnchors); err != nil {
return errPath, err
}
}
return "", nil
}
func checkAnchors(key string, supportedAnchors []anchor.IsAnchor) bool {
for _, f := range supportedAnchors {
if f(key) {
return true
}
}
return false
}

View file

@ -1,9 +1,10 @@
package policy package policy
import ( import (
"fmt"
"time" "time"
"github.com/go-logr/logr" "github.com/golang/glog"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1" kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
kyvernoclient "github.com/nirmata/kyverno/pkg/client/clientset/versioned" kyvernoclient "github.com/nirmata/kyverno/pkg/client/clientset/versioned"
"github.com/nirmata/kyverno/pkg/client/clientset/versioned/scheme" "github.com/nirmata/kyverno/pkg/client/clientset/versioned/scheme"
@ -71,7 +72,6 @@ type PolicyController struct {
pvGenerator policyviolation.GeneratorInterface pvGenerator policyviolation.GeneratorInterface
// resourceWebhookWatcher queues the webhook creation request, creates the webhook // resourceWebhookWatcher queues the webhook creation request, creates the webhook
resourceWebhookWatcher *webhookconfig.ResourceWebhookRegister resourceWebhookWatcher *webhookconfig.ResourceWebhookRegister
log logr.Logger
} }
// NewPolicyController create a new PolicyController // NewPolicyController create a new PolicyController
@ -84,11 +84,10 @@ func NewPolicyController(kyvernoClient *kyvernoclient.Clientset,
eventGen event.Interface, eventGen event.Interface,
pvGenerator policyviolation.GeneratorInterface, pvGenerator policyviolation.GeneratorInterface,
pMetaStore policystore.UpdateInterface, pMetaStore policystore.UpdateInterface,
resourceWebhookWatcher *webhookconfig.ResourceWebhookRegister, resourceWebhookWatcher *webhookconfig.ResourceWebhookRegister) (*PolicyController, error) {
log logr.Logger) (*PolicyController, error) {
// Event broad caster // Event broad caster
eventBroadcaster := record.NewBroadcaster() eventBroadcaster := record.NewBroadcaster()
eventBroadcaster.StartLogging(log.Info) eventBroadcaster.StartLogging(glog.Infof)
eventInterface, err := client.GetEventsInterface() eventInterface, err := client.GetEventsInterface()
if err != nil { if err != nil {
return nil, err return nil, err
@ -105,7 +104,6 @@ func NewPolicyController(kyvernoClient *kyvernoclient.Clientset,
pMetaStore: pMetaStore, pMetaStore: pMetaStore,
pvGenerator: pvGenerator, pvGenerator: pvGenerator,
resourceWebhookWatcher: resourceWebhookWatcher, resourceWebhookWatcher: resourceWebhookWatcher,
log: log,
} }
pc.pvControl = RealPVControl{Client: kyvernoClient, Recorder: pc.eventRecorder} pc.pvControl = RealPVControl{Client: kyvernoClient, Recorder: pc.eventRecorder}
@ -147,7 +145,6 @@ func NewPolicyController(kyvernoClient *kyvernoclient.Clientset,
} }
func (pc *PolicyController) addPolicy(obj interface{}) { func (pc *PolicyController) addPolicy(obj interface{}) {
logger := pc.log
p := obj.(*kyverno.ClusterPolicy) p := obj.(*kyverno.ClusterPolicy)
// Only process policies that are enabled for "background" execution // Only process policies that are enabled for "background" execution
// policy.spec.background -> "True" // policy.spec.background -> "True"
@ -171,19 +168,19 @@ func (pc *PolicyController) addPolicy(obj interface{}) {
return return
} }
} }
logger.V(4).Info("adding policy", "name", p.Name)
glog.V(4).Infof("Adding Policy %s", p.Name)
pc.enqueuePolicy(p) pc.enqueuePolicy(p)
} }
func (pc *PolicyController) updatePolicy(old, cur interface{}) { func (pc *PolicyController) updatePolicy(old, cur interface{}) {
logger := pc.log
oldP := old.(*kyverno.ClusterPolicy) oldP := old.(*kyverno.ClusterPolicy)
curP := cur.(*kyverno.ClusterPolicy) curP := cur.(*kyverno.ClusterPolicy)
// TODO: optimize this : policy meta-store // TODO: optimize this : policy meta-store
// Update policy-> (remove,add) // Update policy-> (remove,add)
err := pc.pMetaStore.UnRegister(*oldP) err := pc.pMetaStore.UnRegister(*oldP)
if err != nil { if err != nil {
logger.Error(err, "failed to unregister policy", "name", oldP.Name) glog.Infof("Failed to unregister policy %s", oldP.Name)
} }
pc.pMetaStore.Register(*curP) pc.pMetaStore.Register(*curP)
@ -206,29 +203,28 @@ func (pc *PolicyController) updatePolicy(old, cur interface{}) {
return return
} }
} }
logger.V(4).Info("updating policy", "name", oldP.Name) glog.V(4).Infof("Updating Policy %s", oldP.Name)
pc.enqueuePolicy(curP) pc.enqueuePolicy(curP)
} }
func (pc *PolicyController) deletePolicy(obj interface{}) { func (pc *PolicyController) deletePolicy(obj interface{}) {
logger := pc.log
p, ok := obj.(*kyverno.ClusterPolicy) p, ok := obj.(*kyverno.ClusterPolicy)
if !ok { if !ok {
tombstone, ok := obj.(cache.DeletedFinalStateUnknown) tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
if !ok { if !ok {
logger.Info("couldnt get object from tomstone", "obj", obj) glog.Info(fmt.Errorf("Couldn't get object from tombstone %#v", obj))
return return
} }
p, ok = tombstone.Obj.(*kyverno.ClusterPolicy) p, ok = tombstone.Obj.(*kyverno.ClusterPolicy)
if !ok { if !ok {
logger.Info("tombstone container object that is not a policy", "obj", obj) glog.Info(fmt.Errorf("Tombstone contained object that is not a Policy %#v", obj))
return return
} }
} }
logger.V(4).Info("deleting policy", "name", p.Name) glog.V(4).Infof("Deleting Policy %s", p.Name)
// Unregister from policy meta-store // Unregister from policy meta-store
if err := pc.pMetaStore.UnRegister(*p); err != nil { if err := pc.pMetaStore.UnRegister(*p); err != nil {
logger.Error(err, "failed to unregister policy", "name", p.Name) glog.Infof("failed to unregister policy %s", p.Name)
} }
// we process policies that are not set of background processing as we need to perform policy violation // we process policies that are not set of background processing as we need to perform policy violation
// cleanup when a policy is deleted. // cleanup when a policy is deleted.
@ -236,10 +232,9 @@ func (pc *PolicyController) deletePolicy(obj interface{}) {
} }
func (pc *PolicyController) enqueue(policy *kyverno.ClusterPolicy) { func (pc *PolicyController) enqueue(policy *kyverno.ClusterPolicy) {
logger := pc.log
key, err := cache.MetaNamespaceKeyFunc(policy) key, err := cache.MetaNamespaceKeyFunc(policy)
if err != nil { if err != nil {
logger.Error(err, "failed to enqueu policy") glog.Error(err)
return return
} }
pc.queue.Add(key) pc.queue.Add(key)
@ -247,16 +242,15 @@ func (pc *PolicyController) enqueue(policy *kyverno.ClusterPolicy) {
// Run begins watching and syncing. // Run begins watching and syncing.
func (pc *PolicyController) Run(workers int, stopCh <-chan struct{}) { func (pc *PolicyController) Run(workers int, stopCh <-chan struct{}) {
logger := pc.log
defer utilruntime.HandleCrash() defer utilruntime.HandleCrash()
defer pc.queue.ShutDown() defer pc.queue.ShutDown()
logger.Info("starting") glog.Info("Starting policy controller")
defer logger.Info("shutting down") defer glog.Info("Shutting down policy controller")
if !cache.WaitForCacheSync(stopCh, pc.pListerSynced, pc.cpvListerSynced, pc.nspvListerSynced) { if !cache.WaitForCacheSync(stopCh, pc.pListerSynced, pc.cpvListerSynced, pc.nspvListerSynced) {
logger.Info("failed to sync informer cache") glog.Error("failed to sync informer cache")
return return
} }
@ -291,33 +285,31 @@ func (pc *PolicyController) processNextWorkItem() bool {
} }
func (pc *PolicyController) handleErr(err error, key interface{}) { func (pc *PolicyController) handleErr(err error, key interface{}) {
logger := pc.log
if err == nil { if err == nil {
pc.queue.Forget(key) pc.queue.Forget(key)
return return
} }
if pc.queue.NumRequeues(key) < maxRetries { if pc.queue.NumRequeues(key) < maxRetries {
logger.Error(err, "failed to sync policy", "key", key) glog.V(2).Infof("Error syncing Policy %v: %v", key, err)
pc.queue.AddRateLimited(key) pc.queue.AddRateLimited(key)
return return
} }
utilruntime.HandleError(err) utilruntime.HandleError(err)
logger.V(2).Info("dropping policy out of queue", "key", key) glog.V(2).Infof("Dropping policy %q out of the queue: %v", key, err)
pc.queue.Forget(key) pc.queue.Forget(key)
} }
func (pc *PolicyController) syncPolicy(key string) error { func (pc *PolicyController) syncPolicy(key string) error {
logger := pc.log
startTime := time.Now() startTime := time.Now()
logger.V(4).Info("started syncing policy", "key", key, "startTime", startTime) glog.V(4).Infof("Started syncing policy %q (%v)", key, startTime)
defer func() { defer func() {
logger.V(4).Info("finished syncing policy", "key", key, "processingTime", time.Since(startTime)) glog.V(4).Infof("Finished syncing policy %q (%v)", key, time.Since(startTime))
}() }()
policy, err := pc.pLister.Get(key) policy, err := pc.pLister.Get(key)
if errors.IsNotFound(err) { if errors.IsNotFound(err) {
logger.V(2).Info("policy deleted", "key", key) glog.V(2).Infof("Policy %v has been deleted", key)
// delete cluster policy violation // delete cluster policy violation
if err := pc.deleteClusterPolicyViolations(key); err != nil { if err := pc.deleteClusterPolicyViolations(key); err != nil {
return err return err
@ -330,7 +322,8 @@ func (pc *PolicyController) syncPolicy(key string) error {
// remove webhook configurations if there are no policies // remove webhook configurations if there are no policies
if err := pc.removeResourceWebhookConfiguration(); err != nil { if err := pc.removeResourceWebhookConfiguration(); err != nil {
// do not fail, if unable to delete resource webhook config // do not fail, if unable to delete resource webhook config
logger.Error(err, "failed to remove resource webhook configurations") glog.V(4).Infof("failed to remove resource webhook configuration: %v", err)
glog.Errorln(err)
} }
return nil return nil
} }

View file

@ -5,7 +5,7 @@ import (
"sync" "sync"
"time" "time"
"github.com/go-logr/logr" "github.com/golang/glog"
"github.com/minio/minio/pkg/wildcard" "github.com/minio/minio/pkg/wildcard"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1" kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
"github.com/nirmata/kyverno/pkg/config" "github.com/nirmata/kyverno/pkg/config"
@ -19,27 +19,27 @@ import (
) )
func (pc *PolicyController) processExistingResources(policy kyverno.ClusterPolicy) []response.EngineResponse { func (pc *PolicyController) processExistingResources(policy kyverno.ClusterPolicy) []response.EngineResponse {
logger := pc.log.WithValues("policy", policy.Name)
// Parse through all the resources // Parse through all the resources
// drops the cache after configured rebuild time // drops the cache after configured rebuild time
pc.rm.Drop() pc.rm.Drop()
var engineResponses []response.EngineResponse var engineResponses []response.EngineResponse
// get resource that are satisfy the resource description defined in the rules // get resource that are satisfy the resource description defined in the rules
resourceMap := listResources(pc.client, policy, pc.configHandler, logger) resourceMap := listResources(pc.client, policy, pc.configHandler)
for _, resource := range resourceMap { for _, resource := range resourceMap {
// pre-processing, check if the policy and resource version has been processed before // pre-processing, check if the policy and resource version has been processed before
if !pc.rm.ProcessResource(policy.Name, policy.ResourceVersion, resource.GetKind(), resource.GetNamespace(), resource.GetName(), resource.GetResourceVersion()) { if !pc.rm.ProcessResource(policy.Name, policy.ResourceVersion, resource.GetKind(), resource.GetNamespace(), resource.GetName(), resource.GetResourceVersion()) {
logger.V(4).Info("policy and resource already processed", "policyResourceVersion", policy.ResourceVersion, "resourceResourceVersion", resource.GetResourceVersion(), "kind", resource.GetKind(), "namespace", resource.GetNamespace(), "name", resource.GetName()) glog.V(4).Infof("policy %s with resource version %s already processed on resource %s/%s/%s with resource version %s", policy.Name, policy.ResourceVersion, resource.GetKind(), resource.GetNamespace(), resource.GetName(), resource.GetResourceVersion())
continue continue
} }
// skip reporting violation on pod which has annotation pod-policies.kyverno.io/autogen-applied // skip reporting violation on pod which has annotation pod-policies.kyverno.io/autogen-applied
if skipPodApplication(resource, logger) { if skipPodApplication(resource) {
continue continue
} }
// apply the policy on each // apply the policy on each
engineResponse := applyPolicy(policy, resource, logger) glog.V(4).Infof("apply policy %s with resource version %s on resource %s/%s/%s with resource version %s", policy.Name, policy.ResourceVersion, resource.GetKind(), resource.GetNamespace(), resource.GetName(), resource.GetResourceVersion())
engineResponse := applyPolicy(policy, resource)
// get engine response for mutation & validation independently // get engine response for mutation & validation independently
engineResponses = append(engineResponses, engineResponse...) engineResponses = append(engineResponses, engineResponse...)
// post-processing, register the resource as processed // post-processing, register the resource as processed
@ -48,26 +48,36 @@ func (pc *PolicyController) processExistingResources(policy kyverno.ClusterPolic
return engineResponses return engineResponses
} }
func listResources(client *client.Client, policy kyverno.ClusterPolicy, configHandler config.Interface, log logr.Logger) map[string]unstructured.Unstructured { func listResources(client *client.Client, policy kyverno.ClusterPolicy, configHandler config.Interface) map[string]unstructured.Unstructured {
// key uid // key uid
resourceMap := map[string]unstructured.Unstructured{} resourceMap := map[string]unstructured.Unstructured{}
for _, rule := range policy.Spec.Rules { for _, rule := range policy.Spec.Rules {
// resources that match // resources that match
for _, k := range rule.MatchResources.Kinds { for _, k := range rule.MatchResources.Kinds {
// if kindIsExcluded(k, rule.ExcludeResources.Kinds) {
// glog.V(4).Infof("processing policy %s rule %s: kind %s is exluded", policy.Name, rule.Name, k)
// continue
// }
var namespaces []string var namespaces []string
if k == "Namespace" {
// TODO
// this is handled by generator controller
glog.V(4).Infof("skipping processing policy %s rule %s for kind Namespace", policy.Name, rule.Name)
continue
}
if len(rule.MatchResources.Namespaces) > 0 { if len(rule.MatchResources.Namespaces) > 0 {
namespaces = append(namespaces, rule.MatchResources.Namespaces...) namespaces = append(namespaces, rule.MatchResources.Namespaces...)
log.V(4).Info("namespaces included", "namespaces", rule.MatchResources.Namespaces) glog.V(4).Infof("namespaces specified for inclusion: %v", rule.MatchResources.Namespaces)
} else { } else {
log.V(4).Info("processing all namespaces", "rule", rule.Name) glog.V(4).Infof("processing policy %s rule %s, namespace not defined, getting all namespaces ", policy.Name, rule.Name)
// get all namespaces // get all namespaces
namespaces = getAllNamespaces(client, log) namespaces = getAllNamespaces(client)
} }
// get resources in the namespaces // get resources in the namespaces
for _, ns := range namespaces { for _, ns := range namespaces {
rMap := getResourcesPerNamespace(k, client, ns, rule, configHandler, log) rMap := getResourcesPerNamespace(k, client, ns, rule, configHandler)
mergeresources(resourceMap, rMap) mergeresources(resourceMap, rMap)
} }
@ -76,16 +86,16 @@ func listResources(client *client.Client, policy kyverno.ClusterPolicy, configHa
return resourceMap return resourceMap
} }
func getResourcesPerNamespace(kind string, client *client.Client, namespace string, rule kyverno.Rule, configHandler config.Interface, log logr.Logger) map[string]unstructured.Unstructured { func getResourcesPerNamespace(kind string, client *client.Client, namespace string, rule kyverno.Rule, configHandler config.Interface) map[string]unstructured.Unstructured {
resourceMap := map[string]unstructured.Unstructured{} resourceMap := map[string]unstructured.Unstructured{}
// merge include and exclude label selector values // merge include and exclude label selector values
ls := rule.MatchResources.Selector ls := rule.MatchResources.Selector
// ls := mergeLabelSectors(rule.MatchResources.Selector, rule.ExcludeResources.Selector) // ls := mergeLabelSectors(rule.MatchResources.Selector, rule.ExcludeResources.Selector)
// list resources // list resources
log.V(4).Info("list resources to be processed") glog.V(4).Infof("get resources for kind %s, namespace %s, selector %v", kind, namespace, rule.MatchResources.Selector)
list, err := client.ListResource(kind, namespace, ls) list, err := client.ListResource(kind, namespace, ls)
if err != nil { if err != nil {
log.Error(err, "failed to list resources", "kind", kind) glog.Infof("unable to get resources: err %v", err)
return nil return nil
} }
// filter based on name // filter based on name
@ -93,6 +103,7 @@ func getResourcesPerNamespace(kind string, client *client.Client, namespace stri
// match name // match name
if rule.MatchResources.Name != "" { if rule.MatchResources.Name != "" {
if !wildcard.Match(rule.MatchResources.Name, r.GetName()) { if !wildcard.Match(rule.MatchResources.Name, r.GetName()) {
glog.V(4).Infof("skipping resource %s/%s due to include condition name=%s mistatch", r.GetNamespace(), r.GetName(), rule.MatchResources.Name)
continue continue
} }
} }
@ -107,11 +118,12 @@ func getResourcesPerNamespace(kind string, client *client.Client, namespace stri
// exclude the resources // exclude the resources
// skip resources to be filtered // skip resources to be filtered
excludeResources(resourceMap, rule.ExcludeResources.ResourceDescription, configHandler, log) excludeResources(resourceMap, rule.ExcludeResources.ResourceDescription, configHandler)
// glog.V(4).Infof("resource map: %v", resourceMap)
return resourceMap return resourceMap
} }
func excludeResources(included map[string]unstructured.Unstructured, exclude kyverno.ResourceDescription, configHandler config.Interface, log logr.Logger) { func excludeResources(included map[string]unstructured.Unstructured, exclude kyverno.ResourceDescription, configHandler config.Interface) {
if reflect.DeepEqual(exclude, (kyverno.ResourceDescription{})) { if reflect.DeepEqual(exclude, (kyverno.ResourceDescription{})) {
return return
} }
@ -142,7 +154,7 @@ func excludeResources(included map[string]unstructured.Unstructured, exclude kyv
selector, err := metav1.LabelSelectorAsSelector(exclude.Selector) selector, err := metav1.LabelSelectorAsSelector(exclude.Selector)
// if the label selector is incorrect, should be fail or // if the label selector is incorrect, should be fail or
if err != nil { if err != nil {
log.Error(err, "failed to build label selector") glog.Error(err)
return Skip return Skip
} }
if selector.Matches(labels.Set(labelsMap)) { if selector.Matches(labels.Set(labelsMap)) {
@ -193,6 +205,8 @@ func excludeResources(included map[string]unstructured.Unstructured, exclude kyv
} }
// exclude the filtered resources // exclude the filtered resources
if configHandler.ToFilter(resource.GetKind(), resource.GetNamespace(), resource.GetName()) { if configHandler.ToFilter(resource.GetKind(), resource.GetNamespace(), resource.GetName()) {
//TODO: improve the text
glog.V(4).Infof("excluding resource %s/%s/%s as its satisfies the filtered resources", resource.GetKind(), resource.GetNamespace(), resource.GetName())
delete(included, uid) delete(included, uid)
continue continue
} }
@ -230,13 +244,12 @@ func mergeresources(a, b map[string]unstructured.Unstructured) {
} }
} }
func getAllNamespaces(client *client.Client, log logr.Logger) []string { func getAllNamespaces(client *client.Client) []string {
var namespaces []string var namespaces []string
// get all namespaces // get all namespaces
nsList, err := client.ListResource("Namespace", "", nil) nsList, err := client.ListResource("Namespace", "", nil)
if err != nil { if err != nil {
log.Error(err, "failed to list namespaces") glog.Error(err)
return namespaces return namespaces
} }
for _, ns := range nsList.Items { for _, ns := range nsList.Items {
@ -278,11 +291,14 @@ type resourceManager interface {
//TODO: or drop based on the size //TODO: or drop based on the size
func (rm *ResourceManager) Drop() { func (rm *ResourceManager) Drop() {
timeSince := time.Since(rm.time) timeSince := time.Since(rm.time)
glog.V(4).Infof("time since last cache reset time %v is %v", rm.time, timeSince)
glog.V(4).Infof("cache rebuild time %v", time.Duration(rm.rebuildTime)*time.Second)
if timeSince > time.Duration(rm.rebuildTime)*time.Second { if timeSince > time.Duration(rm.rebuildTime)*time.Second {
rm.mux.Lock() rm.mux.Lock()
defer rm.mux.Unlock() defer rm.mux.Unlock()
rm.data = map[string]interface{}{} rm.data = map[string]interface{}{}
rm.time = time.Now() rm.time = time.Now()
glog.V(4).Infof("dropping cache at time %v", rm.time)
} }
} }
@ -311,14 +327,14 @@ func buildKey(policy, pv, kind, ns, name, rv string) string {
return policy + "/" + pv + "/" + kind + "/" + ns + "/" + name + "/" + rv return policy + "/" + pv + "/" + kind + "/" + ns + "/" + name + "/" + rv
} }
func skipPodApplication(resource unstructured.Unstructured, log logr.Logger) bool { func skipPodApplication(resource unstructured.Unstructured) bool {
if resource.GetKind() != "Pod" { if resource.GetKind() != "Pod" {
return false return false
} }
annotation := resource.GetAnnotations() annotation := resource.GetAnnotations()
if _, ok := annotation[engine.PodTemplateAnnotation]; ok { if _, ok := annotation[engine.PodTemplateAnnotation]; ok {
log.V(4).Info("Policies already processed on pod controllers, skip processing policy on Pod", "kind", resource.GetKind(), "namespace", resource.GetNamespace(), "name", resource.GetName()) glog.V(4).Infof("Policies already processed on pod controllers, skip processing policy on Pod/%s/%s", resource.GetNamespace(), resource.GetName())
return true return true
} }

View file

@ -1,74 +0,0 @@
package generate
import (
"github.com/go-logr/logr"
"github.com/nirmata/kyverno/pkg/auth"
dclient "github.com/nirmata/kyverno/pkg/dclient"
)
//Operations provides methods to performing operations on resource
type Operations interface {
// CanICreate returns 'true' if self can 'create' resource
CanICreate(kind, namespace string) (bool, error)
// CanIUpdate returns 'true' if self can 'update' resource
CanIUpdate(kind, namespace string) (bool, error)
// CanIDelete returns 'true' if self can 'delete' resource
CanIDelete(kind, namespace string) (bool, error)
// CanIGet returns 'true' if self can 'get' resource
CanIGet(kind, namespace string) (bool, error)
}
//Auth provides implementation to check if caller/self/kyverno has access to perofrm operations
type Auth struct {
client *dclient.Client
log logr.Logger
}
//NewAuth returns a new instance of Auth for operations
func NewAuth(client *dclient.Client, log logr.Logger) *Auth {
a := Auth{
client: client,
log: log,
}
return &a
}
// CanICreate returns 'true' if self can 'create' resource
func (a *Auth) CanICreate(kind, namespace string) (bool, error) {
canI := auth.NewCanI(a.client, kind, namespace, "create", a.log)
ok, err := canI.RunAccessCheck()
if err != nil {
return false, err
}
return ok, nil
}
// CanIUpdate returns 'true' if self can 'update' resource
func (a *Auth) CanIUpdate(kind, namespace string) (bool, error) {
canI := auth.NewCanI(a.client, kind, namespace, "update", a.log)
ok, err := canI.RunAccessCheck()
if err != nil {
return false, err
}
return ok, nil
}
// CanIDelete returns 'true' if self can 'delete' resource
func (a *Auth) CanIDelete(kind, namespace string) (bool, error) {
canI := auth.NewCanI(a.client, kind, namespace, "delete", a.log)
ok, err := canI.RunAccessCheck()
if err != nil {
return false, err
}
return ok, nil
}
// CanIGet returns 'true' if self can 'get' resource
func (a *Auth) CanIGet(kind, namespace string) (bool, error) {
canI := auth.NewCanI(a.client, kind, namespace, "get", a.log)
ok, err := canI.RunAccessCheck()
if err != nil {
return false, err
}
return ok, nil
}

View file

@ -1,21 +0,0 @@
package generate
import (
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
"github.com/nirmata/kyverno/pkg/policy/generate/fake"
)
//FakeGenerate provides implementation for generate rule processing
// with mocks/fakes for cluster interactions
type FakeGenerate struct {
Generate
}
//NewFakeGenerate returns a new instance of generatecheck that uses
// fake/mock implementation for operation access(always returns true)
func NewFakeGenerate(rule kyverno.Generation) *FakeGenerate {
g := FakeGenerate{}
g.rule = rule
g.authCheck = fake.NewFakeAuth()
return &g
}

View file

@ -1,31 +0,0 @@
package fake
//FakeAuth providers implementation for testing, retuning true for all operations
type FakeAuth struct {
}
//NewFakeAuth returns a new instance of Fake Auth that returns true for each operation
func NewFakeAuth() *FakeAuth {
a := FakeAuth{}
return &a
}
// CanICreate returns 'true'
func (a *FakeAuth) CanICreate(kind, namespace string) (bool, error) {
return true, nil
}
// CanIUpdate returns 'true'
func (a *FakeAuth) CanIUpdate(kind, namespace string) (bool, error) {
return true, nil
}
// CanIDelete returns 'true'
func (a *FakeAuth) CanIDelete(kind, namespace string) (bool, error) {
return true, nil
}
// CanIGet returns 'true'
func (a *FakeAuth) CanIGet(kind, namespace string) (bool, error) {
return true, nil
}

View file

@ -1,151 +0,0 @@
package generate
import (
"fmt"
"reflect"
"github.com/go-logr/logr"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
dclient "github.com/nirmata/kyverno/pkg/dclient"
"github.com/nirmata/kyverno/pkg/engine/anchor"
"github.com/nirmata/kyverno/pkg/engine/variables"
"github.com/nirmata/kyverno/pkg/policy/common"
)
// Generate provides implementation to validate 'generate' rule
type Generate struct {
// rule to hold 'generate' rule specifications
rule kyverno.Generation
// authCheck to check access for operations
authCheck Operations
//logger
log logr.Logger
}
//NewGenerateFactory returns a new instance of Generate validation checker
func NewGenerateFactory(client *dclient.Client, rule kyverno.Generation, log logr.Logger) *Generate {
g := Generate{
rule: rule,
authCheck: NewAuth(client, log),
log: log,
}
return &g
}
//Validate validates the 'generate' rule
func (g *Generate) Validate() (string, error) {
rule := g.rule
if rule.Data == nil && rule.Clone == (kyverno.CloneFrom{}) {
return "", fmt.Errorf("clone or data are required")
}
if rule.Data != nil && rule.Clone != (kyverno.CloneFrom{}) {
return "", fmt.Errorf("only one operation allowed per generate rule(data or clone)")
}
kind, name, namespace := rule.Kind, rule.Name, rule.Namespace
if name == "" {
return "name", fmt.Errorf("name cannot be empty")
}
if kind == "" {
return "kind", fmt.Errorf("kind cannot be empty")
}
// Can I generate resource
if !reflect.DeepEqual(rule.Clone, kyverno.CloneFrom{}) {
if path, err := g.validateClone(rule.Clone, kind); err != nil {
return fmt.Sprintf("clone.%s", path), err
}
}
if rule.Data != nil {
//TODO: is this required ?? as anchors can only be on pattern and not resource
// we can add this check by not sure if its needed here
if path, err := common.ValidatePattern(rule.Data, "/", []anchor.IsAnchor{}); err != nil {
return fmt.Sprintf("data.%s", path), fmt.Errorf("anchors not supported on generate resources: %v", err)
}
}
// Kyverno generate-controller create/update/deletes the resources specified in generate rule of policy
// kyverno uses SA 'kyverno-service-account' and has default ClusterRoles and ClusterRoleBindings
// instuctions to modify the RBAC for kyverno are mentioned at https://github.com/nirmata/kyverno/blob/master/documentation/installation.md
// - operations required: create/update/delete/get
// If kind and namespace contain variables, then we cannot resolve then so we skip the processing
if err := g.canIGenerate(kind, namespace); err != nil {
return "", err
}
return "", nil
}
func (g *Generate) validateClone(c kyverno.CloneFrom, kind string) (string, error) {
if c.Name == "" {
return "name", fmt.Errorf("name cannot be empty")
}
if c.Namespace == "" {
return "namespace", fmt.Errorf("namespace cannot be empty")
}
namespace := c.Namespace
// Skip if there is variable defined
if !variables.IsVariable(kind) && !variables.IsVariable(namespace) {
// GET
ok, err := g.authCheck.CanIGet(kind, namespace)
if err != nil {
return "", err
}
if !ok {
return "", fmt.Errorf("kyverno does not have permissions to 'get' resource %s/%s. Update permissions in ClusterRole 'kyverno:generatecontroller'", kind, namespace)
}
} else {
g.log.V(4).Info("name & namespace uses variables, so cannot be resolved. Skipping Auth Checks.")
}
return "", nil
}
//canIGenerate returns a error if kyverno cannot perform oprations
func (g *Generate) canIGenerate(kind, namespace string) error {
// Skip if there is variable defined
authCheck := g.authCheck
if !variables.IsVariable(kind) && !variables.IsVariable(namespace) {
// CREATE
ok, err := authCheck.CanICreate(kind, namespace)
if err != nil {
// machinery error
return err
}
if !ok {
return fmt.Errorf("kyverno does not have permissions to 'create' resource %s/%s. Update permissions in ClusterRole 'kyverno:generatecontroller'", kind, namespace)
}
// UPDATE
ok, err = authCheck.CanIUpdate(kind, namespace)
if err != nil {
// machinery error
return err
}
if !ok {
return fmt.Errorf("kyverno does not have permissions to 'update' resource %s/%s. Update permissions in ClusterRole 'kyverno:generatecontroller'", kind, namespace)
}
// GET
ok, err = authCheck.CanIGet(kind, namespace)
if err != nil {
// machinery error
return err
}
if !ok {
return fmt.Errorf("kyverno does not have permissions to 'get' resource %s/%s. Update permissions in ClusterRole 'kyverno:generatecontroller'", kind, namespace)
}
// DELETE
ok, err = authCheck.CanIDelete(kind, namespace)
if err != nil {
// machinery error
return err
}
if !ok {
return fmt.Errorf("kyverno does not have permissions to 'delete' resource %s/%s. Update permissions in ClusterRole 'kyverno:generatecontroller'", kind, namespace)
}
} else {
g.log.V(4).Info("name & namespace uses variables, so cannot be resolved. Skipping Auth Checks.")
}
return nil
}

View file

@ -1,89 +0,0 @@
package generate
import (
"encoding/json"
"testing"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
"gotest.tools/assert"
)
func Test_Validate_Generate(t *testing.T) {
rawGenerate := []byte(`
{
"kind": "NetworkPolicy",
"name": "defaultnetworkpolicy",
"data": {
"spec": {
"podSelector": {},
"policyTypes": [
"Ingress",
"Egress"
],
"ingress": [
{}
],
"egress": [
{}
]
}
}
}`)
var genRule kyverno.Generation
err := json.Unmarshal(rawGenerate, &genRule)
assert.NilError(t, err)
checker := NewFakeGenerate(genRule)
if _, err := checker.Validate(); err != nil {
assert.Assert(t, err != nil)
}
}
func Test_Validate_Generate_HasAnchors(t *testing.T) {
var err error
rawGenerate := []byte(`
{
"kind": "NetworkPolicy",
"name": "defaultnetworkpolicy",
"data": {
"spec": {
"(podSelector)": {},
"policyTypes": [
"Ingress",
"Egress"
],
"ingress": [
{}
],
"egress": [
{}
]
}
}
}`)
var genRule kyverno.Generation
err = json.Unmarshal(rawGenerate, &genRule)
assert.NilError(t, err)
checker := NewFakeGenerate(genRule)
if _, err := checker.Validate(); err != nil {
assert.Assert(t, err != nil)
}
rawGenerate = []byte(`
{
"kind": "ConfigMap",
"name": "copied-cm",
"clone": {
"^(namespace)": "default",
"name": "game"
}
}`)
err = json.Unmarshal(rawGenerate, &genRule)
assert.NilError(t, err)
checker = NewFakeGenerate(genRule)
if _, err := checker.Validate(); err != nil {
assert.Assert(t, err != nil)
}
}

View file

@ -1,63 +0,0 @@
package mutate
import (
"errors"
"fmt"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
"github.com/nirmata/kyverno/pkg/engine/anchor"
"github.com/nirmata/kyverno/pkg/policy/common"
)
// Mutate provides implementation to validate 'mutate' rule
type Mutate struct {
// rule to hold 'mutate' rule specifications
rule kyverno.Mutation
}
//NewMutateFactory returns a new instance of Mutate validation checker
func NewMutateFactory(rule kyverno.Mutation) *Mutate {
m := Mutate{
rule: rule,
}
return &m
}
//Validate validates the 'mutate' rule
func (m *Mutate) Validate() (string, error) {
rule := m.rule
// JSON Patches
if len(rule.Patches) != 0 {
for i, patch := range rule.Patches {
if err := validatePatch(patch); err != nil {
return fmt.Sprintf("patch[%d]", i), err
}
}
}
// Overlay
if rule.Overlay != nil {
path, err := common.ValidatePattern(rule.Overlay, "/", []anchor.IsAnchor{anchor.IsConditionAnchor, anchor.IsAddingAnchor})
if err != nil {
return path, err
}
}
return "", nil
}
// Validate if all mandatory PolicyPatch fields are set
func validatePatch(pp kyverno.Patch) error {
if pp.Path == "" {
return errors.New("JSONPatch field 'path' is mandatory")
}
if pp.Operation == "add" || pp.Operation == "replace" {
if pp.Value == nil {
return fmt.Errorf("JSONPatch field 'value' is mandatory for operation '%s'", pp.Operation)
}
return nil
} else if pp.Operation == "remove" {
return nil
}
return fmt.Errorf("Unsupported JSONPatch operation '%s'", pp.Operation)
}

View file

@ -1,151 +0,0 @@
package mutate
import (
"encoding/json"
"testing"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
"gotest.tools/assert"
)
func Test_Validate_Mutate_ConditionAnchor(t *testing.T) {
rawMutate := []byte(`
{
"overlay": {
"spec": {
"(serviceAccountName)": "*",
"automountServiceAccountToken": false
}
}
}`)
var mutate kyverno.Mutation
err := json.Unmarshal(rawMutate, &mutate)
assert.NilError(t, err)
checker := NewMutateFactory(mutate)
if _, err := checker.Validate(); err != nil {
assert.NilError(t, err)
}
}
func Test_Validate_Mutate_PlusAnchor(t *testing.T) {
rawMutate := []byte(`
{
"overlay": {
"spec": {
"+(serviceAccountName)": "*",
"automountServiceAccountToken": false
}
}
}`)
var mutate kyverno.Mutation
err := json.Unmarshal(rawMutate, &mutate)
assert.NilError(t, err)
checker := NewMutateFactory(mutate)
if _, err := checker.Validate(); err != nil {
assert.NilError(t, err)
}
}
func Test_Validate_Mutate_Mismatched(t *testing.T) {
rawMutate := []byte(`
{
"overlay": {
"spec": {
"^(serviceAccountName)": "*",
"automountServiceAccountToken": false
}
}
}`)
var mutateExistence kyverno.Mutation
err := json.Unmarshal(rawMutate, &mutateExistence)
assert.NilError(t, err)
checker := NewMutateFactory(mutateExistence)
if _, err := checker.Validate(); err != nil {
assert.Assert(t, err != nil)
}
var mutateEqual kyverno.Mutation
rawMutate = []byte(`
{
"overlay": {
"spec": {
"=(serviceAccountName)": "*",
"automountServiceAccountToken": false
}
}
}`)
err = json.Unmarshal(rawMutate, &mutateEqual)
assert.NilError(t, err)
checker = NewMutateFactory(mutateEqual)
if _, err := checker.Validate(); err != nil {
assert.Assert(t, err != nil)
}
var mutateNegation kyverno.Mutation
rawMutate = []byte(`
{
"overlay": {
"spec": {
"X(serviceAccountName)": "*",
"automountServiceAccountToken": false
}
}
}`)
err = json.Unmarshal(rawMutate, &mutateNegation)
assert.NilError(t, err)
checker = NewMutateFactory(mutateEqual)
if _, err := checker.Validate(); err != nil {
assert.Assert(t, err != nil)
}
}
func Test_Validate_Mutate_Unsupported(t *testing.T) {
var err error
var mutate kyverno.Mutation
// case 1
rawMutate := []byte(`
{
"overlay": {
"spec": {
"!(serviceAccountName)": "*",
"automountServiceAccountToken": false
}
}
}`)
err = json.Unmarshal(rawMutate, &mutate)
assert.NilError(t, err)
checker := NewMutateFactory(mutate)
if _, err := checker.Validate(); err != nil {
assert.Assert(t, err != nil)
}
// case 2
rawMutate = []byte(`
{
"overlay": {
"spec": {
"~(serviceAccountName)": "*",
"automountServiceAccountToken": false
}
}
}`)
err = json.Unmarshal(rawMutate, &mutate)
assert.NilError(t, err)
checker = NewMutateFactory(mutate)
if _, err := checker.Validate(); err != nil {
assert.Assert(t, err != nil)
}
}

View file

@ -1,13 +1,13 @@
package policy package policy
import ( import (
"github.com/golang/glog"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1" kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
cache "k8s.io/client-go/tools/cache" cache "k8s.io/client-go/tools/cache"
) )
func (pc *PolicyController) addNamespacedPolicyViolation(obj interface{}) { func (pc *PolicyController) addNamespacedPolicyViolation(obj interface{}) {
pv := obj.(*kyverno.PolicyViolation) pv := obj.(*kyverno.PolicyViolation)
logger := pc.log.WithValues("kind", pv.Kind, "namespace", pv.Namespace, "name", pv.Name)
if pv.DeletionTimestamp != nil { if pv.DeletionTimestamp != nil {
// On a restart of the controller manager, it's possible for an object to // On a restart of the controller manager, it's possible for an object to
@ -20,16 +20,15 @@ func (pc *PolicyController) addNamespacedPolicyViolation(obj interface{}) {
ps := pc.getPolicyForNamespacedPolicyViolation(pv) ps := pc.getPolicyForNamespacedPolicyViolation(pv)
if len(ps) == 0 { if len(ps) == 0 {
// there is no cluster policy for this violation, so we can delete this cluster policy violation // there is no cluster policy for this violation, so we can delete this cluster policy violation
logger.V(4).Info("namepaced policy violation does not belong to an active policy, will be cleanedup") glog.V(4).Infof("PolicyViolation %s does not belong to an active policy, will be cleanedup", pv.Name)
if err := pc.pvControl.DeleteNamespacedPolicyViolation(pv.Namespace, pv.Name); err != nil { if err := pc.pvControl.DeleteNamespacedPolicyViolation(pv.Namespace, pv.Name); err != nil {
logger.Error(err, "failed to delete resource") glog.Errorf("Failed to deleted policy violation %s: %v", pv.Name, err)
return return
} }
logger.V(4).Info("resource deleted") glog.V(4).Infof("PolicyViolation %s deleted", pv.Name)
return return
} }
glog.V(4).Infof("Orphan Policy Violation %s added.", pv.Name)
logger.V(4).Info("resource added")
for _, p := range ps { for _, p := range ps {
pc.enqueuePolicy(p) pc.enqueuePolicy(p)
} }
@ -43,20 +42,19 @@ func (pc *PolicyController) updateNamespacedPolicyViolation(old, cur interface{}
// Two different versions of the same replica set will always have different RVs. // Two different versions of the same replica set will always have different RVs.
return return
} }
logger := pc.log.WithValues("kind", curPV.Kind, "namespace", curPV.Namespace, "name", curPV.Name)
ps := pc.getPolicyForNamespacedPolicyViolation(curPV) ps := pc.getPolicyForNamespacedPolicyViolation(curPV)
if len(ps) == 0 { if len(ps) == 0 {
// there is no namespaced policy for this violation, so we can delete this cluster policy violation // there is no namespaced policy for this violation, so we can delete this cluster policy violation
logger.V(4).Info("nameapced policy violation does not belong to an active policy, will be cleanedup") glog.V(4).Infof("Namespaced Policy Violation %s does not belong to an active policy, will be cleanedup", curPV.Name)
if err := pc.pvControl.DeleteNamespacedPolicyViolation(curPV.Namespace, curPV.Name); err != nil { if err := pc.pvControl.DeleteNamespacedPolicyViolation(curPV.Namespace, curPV.Name); err != nil {
logger.Error(err, "failed to delete resource") glog.Errorf("Failed to deleted namespaced policy violation %s: %v", curPV.Name, err)
return return
} }
logger.V(4).Info("resource deleted") glog.V(4).Infof("Namespaced Policy Violation %s deleted", curPV.Name)
return return
} }
logger.V(4).Info("resource updated") glog.V(4).Infof("Namespaced Policy sViolation %s updated", curPV.Name)
for _, p := range ps { for _, p := range ps {
pc.enqueuePolicy(p) pc.enqueuePolicy(p)
} }
@ -64,7 +62,6 @@ func (pc *PolicyController) updateNamespacedPolicyViolation(old, cur interface{}
} }
func (pc *PolicyController) deleteNamespacedPolicyViolation(obj interface{}) { func (pc *PolicyController) deleteNamespacedPolicyViolation(obj interface{}) {
logger := pc.log
pv, ok := obj.(*kyverno.PolicyViolation) pv, ok := obj.(*kyverno.PolicyViolation)
// When a delete is dropped, the relist will notice a PolicyViolation in the store not // When a delete is dropped, the relist will notice a PolicyViolation in the store not
// in the list, leading to the insertion of a tombstone object which contains // in the list, leading to the insertion of a tombstone object which contains
@ -73,36 +70,34 @@ func (pc *PolicyController) deleteNamespacedPolicyViolation(obj interface{}) {
if !ok { if !ok {
tombstone, ok := obj.(cache.DeletedFinalStateUnknown) tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
if !ok { if !ok {
logger.Info("Couldn't get object from tombstone", "obj", obj) glog.Infof("Couldn't get object from tombstone %#v", obj)
return return
} }
pv, ok = tombstone.Obj.(*kyverno.PolicyViolation) pv, ok = tombstone.Obj.(*kyverno.PolicyViolation)
if !ok { if !ok {
logger.Info("Couldn't get object from tombstone", "obj", obj) glog.Infof("Couldn't get object from tombstone %#v", obj)
return return
} }
} }
logger = logger.WithValues("kind", pv.Kind, "namespace", pv.Namespace, "name", pv.Name)
ps := pc.getPolicyForNamespacedPolicyViolation(pv) ps := pc.getPolicyForNamespacedPolicyViolation(pv)
if len(ps) == 0 { if len(ps) == 0 {
// there is no cluster policy for this violation, so we can delete this cluster policy violation // there is no cluster policy for this violation, so we can delete this cluster policy violation
logger.V(4).Info("nameapced policy violation does not belong to an active policy, will be cleanedup") glog.V(4).Infof("Namespaced Policy Violation %s does not belong to an active policy, will be cleanedup", pv.Name)
if err := pc.pvControl.DeleteNamespacedPolicyViolation(pv.Namespace, pv.Name); err != nil { if err := pc.pvControl.DeleteNamespacedPolicyViolation(pv.Namespace, pv.Name); err != nil {
logger.Error(err, "failed to delete resource") glog.Errorf("Failed to deleted namespaced policy violation %s: %v", pv.Name, err)
return return
} }
logger.V(4).Info("resource deleted") glog.V(4).Infof("Namespaced Policy Violation %s deleted", pv.Name)
return return
} }
logger.V(4).Info("resource updated") glog.V(4).Infof("Namespaced PolicyViolation %s updated", pv.Name)
for _, p := range ps { for _, p := range ps {
pc.enqueuePolicy(p) pc.enqueuePolicy(p)
} }
} }
func (pc *PolicyController) getPolicyForNamespacedPolicyViolation(pv *kyverno.PolicyViolation) []*kyverno.ClusterPolicy { func (pc *PolicyController) getPolicyForNamespacedPolicyViolation(pv *kyverno.PolicyViolation) []*kyverno.ClusterPolicy {
logger := pc.log.WithValues("kind", pv.Kind, "namespace", pv.Namespace, "name", pv.Name)
policies, err := pc.pLister.GetPolicyForNamespacedPolicyViolation(pv) policies, err := pc.pLister.GetPolicyForNamespacedPolicyViolation(pv)
if err != nil || len(policies) == 0 { if err != nil || len(policies) == 0 {
return nil return nil
@ -114,7 +109,8 @@ func (pc *PolicyController) getPolicyForNamespacedPolicyViolation(pv *kyverno.Po
if len(policies) > 1 { if len(policies) > 1 {
// ControllerRef will ensure we don't do anything crazy, but more than one // ControllerRef will ensure we don't do anything crazy, but more than one
// item in this list nevertheless constitutes user error. // item in this list nevertheless constitutes user error.
logger.V(4).Info("user error! more than one policy is selecting policy violation", "labels", pv.Labels, "policy", policies[0].Name) glog.V(4).Infof("user error! more than one policy is selecting policy violation %s with labels: %#v, returning %s",
pv.Name, pv.Labels, policies[0].Name)
} }
return policies return policies
} }

View file

@ -3,7 +3,7 @@ package policy
import ( import (
"fmt" "fmt"
"github.com/go-logr/logr" "github.com/golang/glog"
"github.com/nirmata/kyverno/pkg/engine/response" "github.com/nirmata/kyverno/pkg/engine/response"
"github.com/nirmata/kyverno/pkg/event" "github.com/nirmata/kyverno/pkg/event"
"github.com/nirmata/kyverno/pkg/policyviolation" "github.com/nirmata/kyverno/pkg/policyviolation"
@ -13,12 +13,11 @@ import (
// - has violation -> report // - has violation -> report
// - no violation -> cleanup policy violations // - no violation -> cleanup policy violations
func (pc *PolicyController) cleanupAndReport(engineResponses []response.EngineResponse) { func (pc *PolicyController) cleanupAndReport(engineResponses []response.EngineResponse) {
logger := pc.log
// generate Events // generate Events
eventInfos := generateEvents(pc.log, engineResponses) eventInfos := generateEvents(engineResponses)
pc.eventGen.Add(eventInfos...) pc.eventGen.Add(eventInfos...)
// create policy violation // create policy violation
pvInfos := policyviolation.GeneratePVsFromEngineResponse(engineResponses, logger) pvInfos := policyviolation.GeneratePVsFromEngineResponse(engineResponses)
for i := range pvInfos { for i := range pvInfos {
pvInfos[i].FromSync = true pvInfos[i].FromSync = true
} }
@ -30,27 +29,39 @@ func (pc *PolicyController) cleanupAndReport(engineResponses []response.EngineRe
pc.cleanUp(engineResponses) pc.cleanUp(engineResponses)
} }
func generateEvents(log logr.Logger, ers []response.EngineResponse) []event.Info { func (pc *PolicyController) cleanUp(ers []response.EngineResponse) {
for _, er := range ers {
if !er.IsSuccesful() {
continue
}
if len(er.PolicyResponse.Rules) == 0 {
continue
}
// clean up after the policy has been corrected
pc.cleanUpPolicyViolation(er.PolicyResponse)
}
}
func generateEvents(ers []response.EngineResponse) []event.Info {
var eventInfos []event.Info var eventInfos []event.Info
for _, er := range ers { for _, er := range ers {
if er.IsSuccesful() { if er.IsSuccesful() {
continue continue
} }
eventInfos = append(eventInfos, generateEventsPerEr(log, er)...) eventInfos = append(eventInfos, generateEventsPerEr(er)...)
} }
return eventInfos return eventInfos
} }
func generateEventsPerEr(log logr.Logger, er response.EngineResponse) []event.Info { func generateEventsPerEr(er response.EngineResponse) []event.Info {
logger := log.WithValues("policy", er.PolicyResponse.Policy, "kind", er.PolicyResponse.Resource.Kind, "namespace", er.PolicyResponse.Resource.Namespace, "name", er.PolicyResponse.Resource.Name)
var eventInfos []event.Info var eventInfos []event.Info
logger.V(4).Info("reporting results for policy") glog.V(4).Infof("reporting results for policy '%s' application on resource '%s/%s/%s'", er.PolicyResponse.Policy, er.PolicyResponse.Resource.Kind, er.PolicyResponse.Resource.Namespace, er.PolicyResponse.Resource.Name)
for _, rule := range er.PolicyResponse.Rules { for _, rule := range er.PolicyResponse.Rules {
if rule.Success { if rule.Success {
continue continue
} }
// generate event on resource for each failed rule // generate event on resource for each failed rule
logger.V(4).Info("generating event on resource") glog.V(4).Infof("generation event on resource '%s/%s/%s' for policy '%s'", er.PolicyResponse.Resource.Kind, er.PolicyResponse.Resource.Namespace, er.PolicyResponse.Resource.Name, er.PolicyResponse.Policy)
e := event.Info{} e := event.Info{}
e.Kind = er.PolicyResponse.Resource.Kind e.Kind = er.PolicyResponse.Resource.Kind
e.Namespace = er.PolicyResponse.Resource.Namespace e.Namespace = er.PolicyResponse.Resource.Namespace
@ -65,7 +76,7 @@ func generateEventsPerEr(log logr.Logger, er response.EngineResponse) []event.In
} }
// generate a event on policy for all failed rules // generate a event on policy for all failed rules
logger.V(4).Info("generating event on policy") glog.V(4).Infof("generation event on policy '%s'", er.PolicyResponse.Policy)
e := event.Info{} e := event.Info{}
e.Kind = "ClusterPolicy" e.Kind = "ClusterPolicy"
e.Namespace = "" e.Namespace = ""

View file

@ -5,12 +5,16 @@ import (
"errors" "errors"
"fmt" "fmt"
"reflect" "reflect"
"regexp"
"strconv"
"strings" "strings"
"github.com/golang/glog"
"github.com/nirmata/kyverno/pkg/openapi" "github.com/nirmata/kyverno/pkg/openapi"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1" kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
dclient "github.com/nirmata/kyverno/pkg/dclient" "github.com/nirmata/kyverno/pkg/engine/anchor"
rbacv1 "k8s.io/api/rbac/v1" rbacv1 "k8s.io/api/rbac/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
) )
@ -18,10 +22,11 @@ import (
// Validate does some initial check to verify some conditions // Validate does some initial check to verify some conditions
// - One operation per rule // - One operation per rule
// - ResourceDescription mandatory checks // - ResourceDescription mandatory checks
func Validate(policyRaw []byte, client *dclient.Client, mock bool) error { func Validate(policyRaw []byte) error {
var p kyverno.ClusterPolicy var p kyverno.ClusterPolicy
err := json.Unmarshal(policyRaw, &p) err := json.Unmarshal(policyRaw, &p)
if err != nil { if err != nil {
glog.Errorf("Failed to unmarshal policy admission request, err %v\n", err)
return fmt.Errorf("failed to unmarshal policy admission request err %v", err) return fmt.Errorf("failed to unmarshal policy admission request err %v", err)
} }
@ -57,12 +62,24 @@ func Validate(policyRaw []byte, client *dclient.Client, mock bool) error {
// as there are more than 1 operation in rule, not need to evaluate it further // as there are more than 1 operation in rule, not need to evaluate it further
return fmt.Errorf("path: spec.rules[%d]: %v", i, err) return fmt.Errorf("path: spec.rules[%d]: %v", i, err)
} }
// validate rule actions // Operation Validation
// - Mutate // Mutation
// - Validate if rule.HasMutate() {
// - Generate if path, err := validateMutation(rule.Mutation); err != nil {
if err := validateActions(i, rule, client, mock); err != nil { return fmt.Errorf("path: spec.rules[%d].mutate.%s.: %v", i, path, err)
return err }
}
// Validation
if rule.HasValidate() {
if path, err := validateValidation(rule.Validation); err != nil {
return fmt.Errorf("path: spec.rules[%d].validate.%s.: %v", i, path, err)
}
}
// Generation
if rule.HasGenerate() {
if path, err := validateGeneration(rule.Generation); err != nil {
return fmt.Errorf("path: spec.rules[%d].generate.%s.: %v", i, path, err)
}
} }
// If a rules match block does not match any kind, // If a rules match block does not match any kind,
@ -261,3 +278,193 @@ func validateResourceDescription(rd kyverno.ResourceDescription) error {
} }
return nil return nil
} }
func validateMutation(m kyverno.Mutation) (string, error) {
// JSON Patches
if len(m.Patches) != 0 {
for i, patch := range m.Patches {
if err := validatePatch(patch); err != nil {
return fmt.Sprintf("patch[%d]", i), err
}
}
}
// Overlay
if m.Overlay != nil {
path, err := validatePattern(m.Overlay, "/", []anchor.IsAnchor{anchor.IsConditionAnchor, anchor.IsAddingAnchor})
if err != nil {
return path, err
}
}
return "", nil
}
// Validate if all mandatory PolicyPatch fields are set
func validatePatch(pp kyverno.Patch) error {
if pp.Path == "" {
return errors.New("JSONPatch field 'path' is mandatory")
}
if pp.Operation == "add" || pp.Operation == "replace" {
if pp.Value == nil {
return fmt.Errorf("JSONPatch field 'value' is mandatory for operation '%s'", pp.Operation)
}
return nil
} else if pp.Operation == "remove" {
return nil
}
return fmt.Errorf("Unsupported JSONPatch operation '%s'", pp.Operation)
}
func validateValidation(v kyverno.Validation) (string, error) {
if err := validateOverlayPattern(v); err != nil {
// no need to proceed ahead
return "", err
}
if v.Pattern != nil {
if path, err := validatePattern(v.Pattern, "/", []anchor.IsAnchor{anchor.IsConditionAnchor, anchor.IsExistenceAnchor, anchor.IsEqualityAnchor, anchor.IsNegationAnchor}); err != nil {
return fmt.Sprintf("pattern.%s", path), err
}
}
if len(v.AnyPattern) != 0 {
for i, pattern := range v.AnyPattern {
if path, err := validatePattern(pattern, "/", []anchor.IsAnchor{anchor.IsConditionAnchor, anchor.IsExistenceAnchor, anchor.IsEqualityAnchor, anchor.IsNegationAnchor}); err != nil {
return fmt.Sprintf("anyPattern[%d].%s", i, path), err
}
}
}
return "", nil
}
// validateOverlayPattern checks one of pattern/anyPattern must exist
func validateOverlayPattern(v kyverno.Validation) error {
if v.Pattern == nil && len(v.AnyPattern) == 0 {
return fmt.Errorf("a pattern or anyPattern must be specified")
}
if v.Pattern != nil && len(v.AnyPattern) != 0 {
return fmt.Errorf("only one operation allowed per validation rule(pattern or anyPattern)")
}
return nil
}
// Validate returns error if generator is configured incompletely
func validateGeneration(gen kyverno.Generation) (string, error) {
if gen.Data == nil && gen.Clone == (kyverno.CloneFrom{}) {
return "", fmt.Errorf("clone or data are required")
}
if gen.Data != nil && gen.Clone != (kyverno.CloneFrom{}) {
return "", fmt.Errorf("only one operation allowed per generate rule(data or clone)")
}
// check kind is non empty
// check name is non empty
if gen.Name == "" {
return "name", fmt.Errorf("name cannot be empty")
}
if gen.Kind == "" {
return "kind", fmt.Errorf("kind cannot be empty")
}
if !reflect.DeepEqual(gen.Clone, kyverno.CloneFrom{}) {
if path, err := validateClone(gen.Clone); err != nil {
return fmt.Sprintf("clone.%s", path), err
}
}
if gen.Data != nil {
//TODO: is this required ?? as anchors can only be on pattern and not resource
// we can add this check by not sure if its needed here
if path, err := validatePattern(gen.Data, "/", []anchor.IsAnchor{}); err != nil {
return fmt.Sprintf("data.%s", path), fmt.Errorf("anchors not supported on generate resources: %v", err)
}
}
return "", nil
}
func validateClone(c kyverno.CloneFrom) (string, error) {
if c.Name == "" {
return "name", fmt.Errorf("name cannot be empty")
}
if c.Namespace == "" {
return "namespace", fmt.Errorf("namespace cannot be empty")
}
return "", nil
}
func validatePattern(patternElement interface{}, path string, supportedAnchors []anchor.IsAnchor) (string, error) {
switch typedPatternElement := patternElement.(type) {
case map[string]interface{}:
return validateMap(typedPatternElement, path, supportedAnchors)
case []interface{}:
return validateArray(typedPatternElement, path, supportedAnchors)
case string, float64, int, int64, bool, nil:
//TODO? check operator
return "", nil
default:
return path, fmt.Errorf("Validation rule failed at '%s', pattern contains unknown type", path)
}
}
func validateMap(patternMap map[string]interface{}, path string, supportedAnchors []anchor.IsAnchor) (string, error) {
// check if anchors are defined
for key, value := range patternMap {
// if key is anchor
// check regex () -> this is anchor
// ()
// single char ()
re, err := regexp.Compile(`^.?\(.+\)$`)
if err != nil {
return path + "/" + key, fmt.Errorf("Unable to parse the field %s: %v", key, err)
}
matched := re.MatchString(key)
// check the type of anchor
if matched {
// some type of anchor
// check if valid anchor
if !checkAnchors(key, supportedAnchors) {
return path + "/" + key, fmt.Errorf("Unsupported anchor %s", key)
}
// addition check for existence anchor
// value must be of type list
if anchor.IsExistenceAnchor(key) {
typedValue, ok := value.([]interface{})
if !ok {
return path + "/" + key, fmt.Errorf("Existence anchor should have value of type list")
}
// validate there is only one entry in the list
if len(typedValue) == 0 || len(typedValue) > 1 {
return path + "/" + key, fmt.Errorf("Existence anchor: single value expected, multiple specified")
}
}
}
// lets validate the values now :)
if errPath, err := validatePattern(value, path+"/"+key, supportedAnchors); err != nil {
return errPath, err
}
}
return "", nil
}
func validateArray(patternArray []interface{}, path string, supportedAnchors []anchor.IsAnchor) (string, error) {
for i, patternElement := range patternArray {
currentPath := path + strconv.Itoa(i) + "/"
// lets validate the values now :)
if errPath, err := validatePattern(patternElement, currentPath, supportedAnchors); err != nil {
return errPath, err
}
}
return "", nil
}
func checkAnchors(key string, supportedAnchors []anchor.IsAnchor) bool {
for _, f := range supportedAnchors {
if f(key) {
return true
}
}
return false
}

View file

@ -1,61 +0,0 @@
package validate
import (
"fmt"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
"github.com/nirmata/kyverno/pkg/engine/anchor"
"github.com/nirmata/kyverno/pkg/policy/common"
)
// Validate provides implementation to validate 'validate' rule
type Validate struct {
// rule to hold 'validate' rule specifications
rule kyverno.Validation
}
//NewValidateFactory returns a new instance of Mutate validation checker
func NewValidateFactory(rule kyverno.Validation) *Validate {
m := Validate{
rule: rule,
}
return &m
}
//Validate validates the 'validate' rule
func (v *Validate) Validate() (string, error) {
rule := v.rule
if err := v.validateOverlayPattern(); err != nil {
// no need to proceed ahead
return "", err
}
if rule.Pattern != nil {
if path, err := common.ValidatePattern(rule.Pattern, "/", []anchor.IsAnchor{anchor.IsConditionAnchor, anchor.IsExistenceAnchor, anchor.IsEqualityAnchor, anchor.IsNegationAnchor}); err != nil {
return fmt.Sprintf("pattern.%s", path), err
}
}
if len(rule.AnyPattern) != 0 {
for i, pattern := range rule.AnyPattern {
if path, err := common.ValidatePattern(pattern, "/", []anchor.IsAnchor{anchor.IsConditionAnchor, anchor.IsExistenceAnchor, anchor.IsEqualityAnchor, anchor.IsNegationAnchor}); err != nil {
return fmt.Sprintf("anyPattern[%d].%s", i, path), err
}
}
}
return "", nil
}
// validateOverlayPattern checks one of pattern/anyPattern must exist
func (v *Validate) validateOverlayPattern() error {
rule := v.rule
if rule.Pattern == nil && len(rule.AnyPattern) == 0 {
return fmt.Errorf("a pattern or anyPattern must be specified")
}
if rule.Pattern != nil && len(rule.AnyPattern) != 0 {
return fmt.Errorf("only one operation allowed per validation rule(pattern or anyPattern)")
}
return nil
}

View file

@ -1,381 +0,0 @@
package validate
import (
"encoding/json"
"testing"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
"gotest.tools/assert"
)
func Test_Validate_OverlayPattern_Empty(t *testing.T) {
rawValidation := []byte(`
{}`)
var validation kyverno.Validation
err := json.Unmarshal(rawValidation, &validation)
assert.NilError(t, err)
checker := NewValidateFactory(validation)
if _, err := checker.Validate(); err != nil {
assert.Assert(t, err != nil)
}
}
func Test_Validate_OverlayPattern_Nil_PatternAnypattern(t *testing.T) {
rawValidation := []byte(`
{ "message": "Privileged mode is not allowed. Set allowPrivilegeEscalation and privileged to false"
}
`)
var validation kyverno.Validation
err := json.Unmarshal(rawValidation, &validation)
assert.NilError(t, err)
checker := NewValidateFactory(validation)
if _, err := checker.Validate(); err != nil {
assert.Assert(t, err != nil)
}
}
func Test_Validate_OverlayPattern_Exist_PatternAnypattern(t *testing.T) {
rawValidation := []byte(`
{
"message": "Privileged mode is not allowed. Set allowPrivilegeEscalation and privileged to false",
"anyPattern": [
{
"spec": {
"securityContext": {
"allowPrivilegeEscalation": false,
"privileged": false
}
}
}
],
"pattern": {
"spec": {
"containers": [
{
"name": "*",
"securityContext": {
"allowPrivilegeEscalation": false,
"privileged": false
}
}
]
}
}
}`)
var validation kyverno.Validation
err := json.Unmarshal(rawValidation, &validation)
assert.NilError(t, err)
checker := NewValidateFactory(validation)
if _, err := checker.Validate(); err != nil {
assert.Assert(t, err != nil)
}
}
func Test_Validate_OverlayPattern_Valid(t *testing.T) {
rawValidation := []byte(`
{
"message": "Privileged mode is not allowed. Set allowPrivilegeEscalation and privileged to false",
"anyPattern": [
{
"spec": {
"securityContext": {
"allowPrivilegeEscalation": false,
"privileged": false
}
}
},
{
"spec": {
"containers": [
{
"name": "*",
"securityContext": {
"allowPrivilegeEscalation": false,
"privileged": false
}
}
]
}
}
]
}
`)
var validation kyverno.Validation
err := json.Unmarshal(rawValidation, &validation)
assert.NilError(t, err)
checker := NewValidateFactory(validation)
if _, err := checker.Validate(); err != nil {
assert.NilError(t, err)
}
}
func Test_Validate_ExistingAnchor_AnchorOnMap(t *testing.T) {
rawValidation := []byte(`
{
"message": "validate container security contexts",
"anyPattern": [
{
"spec": {
"template": {
"spec": {
"containers": [
{
"^(securityContext)": {
"runAsNonRoot": true
}
}
]
}
}
}
}
]
}
`)
var validation kyverno.Validation
err := json.Unmarshal(rawValidation, &validation)
assert.NilError(t, err)
checker := NewValidateFactory(validation)
if _, err := checker.Validate(); err != nil {
assert.Assert(t, err != nil)
}
}
func Test_Validate_ExistingAnchor_AnchorOnString(t *testing.T) {
rawValidation := []byte(`{
"message": "validate container security contexts",
"pattern": {
"spec": {
"template": {
"spec": {
"containers": [
{
"securityContext": {
"allowPrivilegeEscalation": "^(false)"
}
}
]
}
}
}
}
}
`)
var validation kyverno.Validation
err := json.Unmarshal(rawValidation, &validation)
assert.NilError(t, err)
checker := NewValidateFactory(validation)
if _, err := checker.Validate(); err != nil {
assert.Assert(t, err != nil)
}
}
func Test_Validate_ExistingAnchor_Valid(t *testing.T) {
var err error
var validation kyverno.Validation
rawValidation := []byte(`
{
"message": "validate container security contexts",
"anyPattern": [
{
"spec": {
"template": {
"spec": {
"^(containers)": [
{
"securityContext": {
"runAsNonRoot": "true"
}
}
]
}
}
}
}
]
}`)
err = json.Unmarshal(rawValidation, &validation)
assert.NilError(t, err)
checker := NewValidateFactory(validation)
if _, err := checker.Validate(); err != nil {
assert.Assert(t, err != nil)
}
rawValidation = []byte(`
{
"message": "validate container security contexts",
"pattern": {
"spec": {
"template": {
"spec": {
"^(containers)": [
{
"securityContext": {
"allowPrivilegeEscalation": "false"
}
}
]
}
}
}
}
} `)
err = json.Unmarshal(rawValidation, &validation)
assert.NilError(t, err)
checker = NewValidateFactory(validation)
if _, err := checker.Validate(); err != nil {
assert.Assert(t, err != nil)
}
}
func Test_Validate_Validate_ValidAnchor(t *testing.T) {
var err error
var validate kyverno.Validation
var rawValidate []byte
// case 1
rawValidate = []byte(`
{
"message": "Root user is not allowed. Set runAsNonRoot to true.",
"anyPattern": [
{
"spec": {
"securityContext": {
"(runAsNonRoot)": true
}
}
},
{
"spec": {
"^(containers)": [
{
"name": "*",
"securityContext": {
"runAsNonRoot": true
}
}
]
}
}
]
}`)
err = json.Unmarshal(rawValidate, &validate)
assert.NilError(t, err)
checker := NewValidateFactory(validate)
if _, err := checker.Validate(); err != nil {
assert.NilError(t, err)
}
// case 2
validate = kyverno.Validation{}
rawValidate = []byte(`
{
"message": "Root user is not allowed. Set runAsNonRoot to true.",
"pattern": {
"spec": {
"=(securityContext)": {
"runAsNonRoot": "true"
}
}
}
}`)
err = json.Unmarshal(rawValidate, &validate)
assert.NilError(t, err)
checker = NewValidateFactory(validate)
if _, err := checker.Validate(); err != nil {
assert.NilError(t, err)
}
}
func Test_Validate_Validate_Mismatched(t *testing.T) {
rawValidate := []byte(`
{
"message": "Root user is not allowed. Set runAsNonRoot to true.",
"pattern": {
"spec": {
"containers": [
{
"name": "*",
"securityContext": {
"+(runAsNonRoot)": true
}
}
]
}
}
}`)
var validate kyverno.Validation
err := json.Unmarshal(rawValidate, &validate)
assert.NilError(t, err)
checker := NewValidateFactory(validate)
if _, err := checker.Validate(); err != nil {
assert.Assert(t, err != nil)
}
}
func Test_Validate_Validate_Unsupported(t *testing.T) {
var err error
var validate kyverno.Validation
// case 1
rawValidate := []byte(`
{
"message": "Root user is not allowed. Set runAsNonRoot to true.",
"pattern": {
"spec": {
"containers": [
{
"name": "*",
"securityContext": {
"!(runAsNonRoot)": true
}
}
]
}
}
}`)
err = json.Unmarshal(rawValidate, &validate)
assert.NilError(t, err)
checker := NewValidateFactory(validate)
if _, err := checker.Validate(); err != nil {
assert.Assert(t, err != nil)
}
// case 2
rawValidate = []byte(`
{
"message": "Root user is not allowed. Set runAsNonRoot to true.",
"pattern": {
"spec": {
"containers": [
{
"name": "*",
"securityContext": {
"~(runAsNonRoot)": true
}
}
]
}
}
}`)
err = json.Unmarshal(rawValidate, &validate)
assert.NilError(t, err)
checker = NewValidateFactory(validate)
if _, err := checker.Validate(); err != nil {
assert.Assert(t, err != nil)
}
}

View file

@ -287,6 +287,369 @@ func Test_Validate_ResourceDescription_InvalidSelector(t *testing.T) {
assert.Assert(t, err != nil) assert.Assert(t, err != nil)
} }
func Test_Validate_OverlayPattern_Empty(t *testing.T) {
rawValidation := []byte(`
{}`)
var validation kyverno.Validation
err := json.Unmarshal(rawValidation, &validation)
assert.NilError(t, err)
if _, err := validateValidation(validation); err != nil {
assert.Assert(t, err != nil)
}
}
func Test_Validate_OverlayPattern_Nil_PatternAnypattern(t *testing.T) {
rawValidation := []byte(`
{ "message": "Privileged mode is not allowed. Set allowPrivilegeEscalation and privileged to false"
}
`)
var validation kyverno.Validation
err := json.Unmarshal(rawValidation, &validation)
assert.NilError(t, err)
if _, err := validateValidation(validation); err != nil {
assert.Assert(t, err != nil)
}
}
func Test_Validate_OverlayPattern_Exist_PatternAnypattern(t *testing.T) {
rawValidation := []byte(`
{
"message": "Privileged mode is not allowed. Set allowPrivilegeEscalation and privileged to false",
"anyPattern": [
{
"spec": {
"securityContext": {
"allowPrivilegeEscalation": false,
"privileged": false
}
}
}
],
"pattern": {
"spec": {
"containers": [
{
"name": "*",
"securityContext": {
"allowPrivilegeEscalation": false,
"privileged": false
}
}
]
}
}
}`)
var validation kyverno.Validation
err := json.Unmarshal(rawValidation, &validation)
assert.NilError(t, err)
if _, err := validateValidation(validation); err != nil {
assert.Assert(t, err != nil)
}
}
func Test_Validate_OverlayPattern_Valid(t *testing.T) {
rawValidation := []byte(`
{
"message": "Privileged mode is not allowed. Set allowPrivilegeEscalation and privileged to false",
"anyPattern": [
{
"spec": {
"securityContext": {
"allowPrivilegeEscalation": false,
"privileged": false
}
}
},
{
"spec": {
"containers": [
{
"name": "*",
"securityContext": {
"allowPrivilegeEscalation": false,
"privileged": false
}
}
]
}
}
]
}
`)
var validation kyverno.Validation
err := json.Unmarshal(rawValidation, &validation)
assert.NilError(t, err)
if _, err := validateValidation(validation); err != nil {
assert.NilError(t, err)
}
}
func Test_Validate_ExistingAnchor_AnchorOnMap(t *testing.T) {
rawValidation := []byte(`
{
"message": "validate container security contexts",
"anyPattern": [
{
"spec": {
"template": {
"spec": {
"containers": [
{
"^(securityContext)": {
"runAsNonRoot": true
}
}
]
}
}
}
}
]
}
`)
var validation kyverno.Validation
err := json.Unmarshal(rawValidation, &validation)
assert.NilError(t, err)
if _, err := validateValidation(validation); err != nil {
assert.Assert(t, err != nil)
}
}
func Test_Validate_ExistingAnchor_AnchorOnString(t *testing.T) {
rawValidation := []byte(`{
"message": "validate container security contexts",
"pattern": {
"spec": {
"template": {
"spec": {
"containers": [
{
"securityContext": {
"allowPrivilegeEscalation": "^(false)"
}
}
]
}
}
}
}
}
`)
var validation kyverno.Validation
err := json.Unmarshal(rawValidation, &validation)
assert.NilError(t, err)
if _, err := validateValidation(validation); err != nil {
assert.Assert(t, err != nil)
}
}
func Test_Validate_ExistingAnchor_Valid(t *testing.T) {
var err error
var validation kyverno.Validation
rawValidation := []byte(`
{
"message": "validate container security contexts",
"anyPattern": [
{
"spec": {
"template": {
"spec": {
"^(containers)": [
{
"securityContext": {
"runAsNonRoot": "true"
}
}
]
}
}
}
}
]
}`)
err = json.Unmarshal(rawValidation, &validation)
assert.NilError(t, err)
if _, err := validateValidation(validation); err != nil {
assert.Assert(t, err != nil)
}
rawValidation = []byte(`
{
"message": "validate container security contexts",
"pattern": {
"spec": {
"template": {
"spec": {
"^(containers)": [
{
"securityContext": {
"allowPrivilegeEscalation": "false"
}
}
]
}
}
}
}
} `)
err = json.Unmarshal(rawValidation, &validation)
assert.NilError(t, err)
if _, err := validateValidation(validation); err != nil {
assert.Assert(t, err != nil)
}
}
func Test_Validate_Validate_ValidAnchor(t *testing.T) {
var err error
var validate kyverno.Validation
var rawValidate []byte
// case 1
rawValidate = []byte(`
{
"message": "Root user is not allowed. Set runAsNonRoot to true.",
"anyPattern": [
{
"spec": {
"securityContext": {
"(runAsNonRoot)": true
}
}
},
{
"spec": {
"^(containers)": [
{
"name": "*",
"securityContext": {
"runAsNonRoot": true
}
}
]
}
}
]
}`)
err = json.Unmarshal(rawValidate, &validate)
assert.NilError(t, err)
if _, err := validateValidation(validate); err != nil {
assert.NilError(t, err)
}
// case 2
validate = kyverno.Validation{}
rawValidate = []byte(`
{
"message": "Root user is not allowed. Set runAsNonRoot to true.",
"pattern": {
"spec": {
"=(securityContext)": {
"runAsNonRoot": "true"
}
}
}
}`)
err = json.Unmarshal(rawValidate, &validate)
assert.NilError(t, err)
if _, err := validateValidation(validate); err != nil {
assert.NilError(t, err)
}
}
func Test_Validate_Validate_Mismatched(t *testing.T) {
rawValidate := []byte(`
{
"message": "Root user is not allowed. Set runAsNonRoot to true.",
"pattern": {
"spec": {
"containers": [
{
"name": "*",
"securityContext": {
"+(runAsNonRoot)": true
}
}
]
}
}
}`)
var validate kyverno.Validation
err := json.Unmarshal(rawValidate, &validate)
assert.NilError(t, err)
if _, err := validateValidation(validate); err != nil {
assert.Assert(t, err != nil)
}
}
func Test_Validate_Validate_Unsupported(t *testing.T) {
var err error
var validate kyverno.Validation
// case 1
rawValidate := []byte(`
{
"message": "Root user is not allowed. Set runAsNonRoot to true.",
"pattern": {
"spec": {
"containers": [
{
"name": "*",
"securityContext": {
"!(runAsNonRoot)": true
}
}
]
}
}
}`)
err = json.Unmarshal(rawValidate, &validate)
assert.NilError(t, err)
if _, err := validateValidation(validate); err != nil {
assert.Assert(t, err != nil)
}
// case 2
rawValidate = []byte(`
{
"message": "Root user is not allowed. Set runAsNonRoot to true.",
"pattern": {
"spec": {
"containers": [
{
"name": "*",
"securityContext": {
"~(runAsNonRoot)": true
}
}
]
}
}
}`)
err = json.Unmarshal(rawValidate, &validate)
assert.NilError(t, err)
if _, err := validateValidation(validate); err != nil {
assert.Assert(t, err != nil)
}
}
func Test_Validate_Policy(t *testing.T) { func Test_Validate_Policy(t *testing.T) {
rawPolicy := []byte(` rawPolicy := []byte(`
{ {
@ -369,10 +732,225 @@ func Test_Validate_Policy(t *testing.T) {
} }
}`) }`)
err := Validate(rawPolicy, nil, true) err := Validate(rawPolicy)
assert.NilError(t, err) assert.NilError(t, err)
} }
func Test_Validate_Mutate_ConditionAnchor(t *testing.T) {
rawMutate := []byte(`
{
"overlay": {
"spec": {
"(serviceAccountName)": "*",
"automountServiceAccountToken": false
}
}
}`)
var mutate kyverno.Mutation
err := json.Unmarshal(rawMutate, &mutate)
assert.NilError(t, err)
if _, err := validateMutation(mutate); err != nil {
assert.NilError(t, err)
}
}
func Test_Validate_Mutate_PlusAnchor(t *testing.T) {
rawMutate := []byte(`
{
"overlay": {
"spec": {
"+(serviceAccountName)": "*",
"automountServiceAccountToken": false
}
}
}`)
var mutate kyverno.Mutation
err := json.Unmarshal(rawMutate, &mutate)
assert.NilError(t, err)
if _, err := validateMutation(mutate); err != nil {
assert.NilError(t, err)
}
}
func Test_Validate_Mutate_Mismatched(t *testing.T) {
rawMutate := []byte(`
{
"overlay": {
"spec": {
"^(serviceAccountName)": "*",
"automountServiceAccountToken": false
}
}
}`)
var mutateExistence kyverno.Mutation
err := json.Unmarshal(rawMutate, &mutateExistence)
assert.NilError(t, err)
if _, err := validateMutation(mutateExistence); err != nil {
assert.Assert(t, err != nil)
}
var mutateEqual kyverno.Mutation
rawMutate = []byte(`
{
"overlay": {
"spec": {
"=(serviceAccountName)": "*",
"automountServiceAccountToken": false
}
}
}`)
err = json.Unmarshal(rawMutate, &mutateEqual)
assert.NilError(t, err)
if _, err := validateMutation(mutateEqual); err != nil {
assert.Assert(t, err != nil)
}
var mutateNegation kyverno.Mutation
rawMutate = []byte(`
{
"overlay": {
"spec": {
"X(serviceAccountName)": "*",
"automountServiceAccountToken": false
}
}
}`)
err = json.Unmarshal(rawMutate, &mutateNegation)
assert.NilError(t, err)
if _, err := validateMutation(mutateEqual); err != nil {
assert.Assert(t, err != nil)
}
}
func Test_Validate_Mutate_Unsupported(t *testing.T) {
var err error
var mutate kyverno.Mutation
// case 1
rawMutate := []byte(`
{
"overlay": {
"spec": {
"!(serviceAccountName)": "*",
"automountServiceAccountToken": false
}
}
}`)
err = json.Unmarshal(rawMutate, &mutate)
assert.NilError(t, err)
if _, err := validateMutation(mutate); err != nil {
assert.Assert(t, err != nil)
}
// case 2
rawMutate = []byte(`
{
"overlay": {
"spec": {
"~(serviceAccountName)": "*",
"automountServiceAccountToken": false
}
}
}`)
err = json.Unmarshal(rawMutate, &mutate)
assert.NilError(t, err)
if _, err := validateMutation(mutate); err != nil {
assert.Assert(t, err != nil)
}
}
func Test_Validate_Generate(t *testing.T) {
rawGenerate := []byte(`
{
"kind": "NetworkPolicy",
"name": "defaultnetworkpolicy",
"data": {
"spec": {
"podSelector": {},
"policyTypes": [
"Ingress",
"Egress"
],
"ingress": [
{}
],
"egress": [
{}
]
}
}
}`)
var generate kyverno.Generation
err := json.Unmarshal(rawGenerate, &generate)
assert.NilError(t, err)
if _, err := validateGeneration(generate); err != nil {
assert.Assert(t, err != nil)
}
}
func Test_Validate_Generate_HasAnchors(t *testing.T) {
var err error
var generate kyverno.Generation
rawGenerate := []byte(`
{
"kind": "NetworkPolicy",
"name": "defaultnetworkpolicy",
"data": {
"spec": {
"(podSelector)": {},
"policyTypes": [
"Ingress",
"Egress"
],
"ingress": [
{}
],
"egress": [
{}
]
}
}
}`)
err = json.Unmarshal(rawGenerate, &generate)
assert.NilError(t, err)
if _, err := validateGeneration(generate); err != nil {
assert.Assert(t, err != nil)
}
rawGenerate = []byte(`
{
"kind": "ConfigMap",
"name": "copied-cm",
"clone": {
"^(namespace)": "default",
"name": "game"
}
}`)
errNew := json.Unmarshal(rawGenerate, &generate)
assert.NilError(t, errNew)
err = json.Unmarshal(rawGenerate, &generate)
assert.NilError(t, err)
if _, err := validateGeneration(generate); err != nil {
assert.Assert(t, err != nil)
}
}
func Test_Validate_ErrorFormat(t *testing.T) { func Test_Validate_ErrorFormat(t *testing.T) {
rawPolicy := []byte(` rawPolicy := []byte(`
{ {
@ -511,7 +1089,7 @@ func Test_Validate_ErrorFormat(t *testing.T) {
} }
`) `)
err := Validate(rawPolicy, nil, true) err := Validate(rawPolicy)
assert.Assert(t, err != nil) assert.Assert(t, err != nil)
} }

View file

@ -1,25 +1,25 @@
package policy package policy
import ( import (
"github.com/golang/glog"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
) )
func (pc *PolicyController) removeResourceWebhookConfiguration() error { func (pc *PolicyController) removeResourceWebhookConfiguration() error {
logger := pc.log
var err error var err error
// get all existing policies // get all existing policies
policies, err := pc.pLister.List(labels.NewSelector()) policies, err := pc.pLister.List(labels.NewSelector())
if err != nil { if err != nil {
logger.Error(err, "failed to list policies") glog.V(4).Infof("failed to list policies: %v", err)
return err return err
} }
if len(policies) == 0 { if len(policies) == 0 {
logger.V(4).Info("no policies loaded, removing resource webhook configuration if one exists") glog.V(4).Info("no policies loaded, removing resource webhook configuration if one exists")
return pc.resourceWebhookWatcher.RemoveResourceWebhookConfiguration() return pc.resourceWebhookWatcher.RemoveResourceWebhookConfiguration()
} }
logger.V(4).Info("no policies with mutating or validating webhook configurations, remove resource webhook configuration if one exists") glog.V(4).Info("no policies with mutating or validating webhook configurations, remove resource webhook configuration if one exists")
return pc.resourceWebhookWatcher.RemoveResourceWebhookConfiguration() return pc.resourceWebhookWatcher.RemoveResourceWebhookConfiguration()
} }

View file

@ -2,16 +2,16 @@ package policystatus
import ( import (
"encoding/json" "encoding/json"
"fmt"
"sync" "sync"
"time" "time"
"github.com/golang/glog"
"k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/util/wait"
"github.com/nirmata/kyverno/pkg/client/clientset/versioned" "github.com/nirmata/kyverno/pkg/client/clientset/versioned"
v1 "github.com/nirmata/kyverno/pkg/api/kyverno/v1" v1 "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
log "sigs.k8s.io/controller-runtime/pkg/log"
) )
// Policy status implementation works in the following way, // Policy status implementation works in the following way,
@ -111,7 +111,8 @@ func (s *Sync) updateStatusCache(stopCh <-chan struct{}) {
s.cache.keyToMutex.Get(statusUpdater.PolicyName()).Unlock() s.cache.keyToMutex.Get(statusUpdater.PolicyName()).Unlock()
oldStatus, _ := json.Marshal(status) oldStatus, _ := json.Marshal(status)
newStatus, _ := json.Marshal(updatedStatus) newStatus, _ := json.Marshal(updatedStatus)
log.Log.V(4).Info(fmt.Sprintf("\nupdated status of policy - %v\noldStatus:\n%v\nnewStatus:\n%v\n", statusUpdater.PolicyName(), string(oldStatus), string(newStatus)))
glog.V(4).Infof("\nupdated status of policy - %v\noldStatus:\n%v\nnewStatus:\n%v\n", statusUpdater.PolicyName(), string(oldStatus), string(newStatus))
case <-stopCh: case <-stopCh:
return return
} }
@ -139,7 +140,7 @@ func (s *Sync) updatePolicyStatus() {
s.cache.dataMu.Lock() s.cache.dataMu.Lock()
delete(s.cache.data, policyName) delete(s.cache.data, policyName)
s.cache.dataMu.Unlock() s.cache.dataMu.Unlock()
log.Log.Error(err, "failed to update policy status") glog.V(4).Info(err)
} }
} }
} }

View file

@ -3,11 +3,12 @@ package policystore
import ( import (
"sync" "sync"
"github.com/go-logr/logr" "k8s.io/apimachinery/pkg/labels"
"github.com/golang/glog"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1" kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
kyvernoinformer "github.com/nirmata/kyverno/pkg/client/informers/externalversions/kyverno/v1" kyvernoinformer "github.com/nirmata/kyverno/pkg/client/informers/externalversions/kyverno/v1"
kyvernolister "github.com/nirmata/kyverno/pkg/client/listers/kyverno/v1" kyvernolister "github.com/nirmata/kyverno/pkg/client/listers/kyverno/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/cache"
) )
@ -23,7 +24,6 @@ type PolicyStore struct {
pLister kyvernolister.ClusterPolicyLister pLister kyvernolister.ClusterPolicyLister
// returns true if the cluster policy store has been synced at least once // returns true if the cluster policy store has been synced at least once
pSynched cache.InformerSynced pSynched cache.InformerSynced
log logr.Logger
} }
//UpdateInterface provides api to update policies //UpdateInterface provides api to update policies
@ -40,29 +40,25 @@ type LookupInterface interface {
} }
// NewPolicyStore returns a new policy store // NewPolicyStore returns a new policy store
func NewPolicyStore(pInformer kyvernoinformer.ClusterPolicyInformer, func NewPolicyStore(pInformer kyvernoinformer.ClusterPolicyInformer) *PolicyStore {
log logr.Logger) *PolicyStore {
ps := PolicyStore{ ps := PolicyStore{
data: make(kindMap), data: make(kindMap),
pLister: pInformer.Lister(), pLister: pInformer.Lister(),
pSynched: pInformer.Informer().HasSynced, pSynched: pInformer.Informer().HasSynced,
log: log,
} }
return &ps return &ps
} }
//Run checks syncing //Run checks syncing
func (ps *PolicyStore) Run(stopCh <-chan struct{}) { func (ps *PolicyStore) Run(stopCh <-chan struct{}) {
logger := ps.log
if !cache.WaitForCacheSync(stopCh, ps.pSynched) { if !cache.WaitForCacheSync(stopCh, ps.pSynched) {
logger.Info("failed to sync informer cache") glog.Error("policy meta store: failed to sync informer cache")
} }
} }
//Register a new policy //Register a new policy
func (ps *PolicyStore) Register(policy kyverno.ClusterPolicy) { func (ps *PolicyStore) Register(policy kyverno.ClusterPolicy) {
logger := ps.log glog.V(4).Infof("adding resources %s", policy.Name)
logger.V(4).Info("adding policy", "name", policy.Name)
ps.mu.Lock() ps.mu.Lock()
defer ps.mu.Unlock() defer ps.mu.Unlock()
var pmap policyMap var pmap policyMap

View file

@ -3,23 +3,24 @@ package policyviolation
import ( import (
"fmt" "fmt"
"github.com/go-logr/logr" "github.com/golang/glog"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1" kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
"github.com/nirmata/kyverno/pkg/engine/response" "github.com/nirmata/kyverno/pkg/engine/response"
) )
//GeneratePVsFromEngineResponse generate Violations from engine responses //GeneratePVsFromEngineResponse generate Violations from engine responses
func GeneratePVsFromEngineResponse(ers []response.EngineResponse, log logr.Logger) (pvInfos []Info) { func GeneratePVsFromEngineResponse(ers []response.EngineResponse) (pvInfos []Info) {
for _, er := range ers { for _, er := range ers {
// ignore creation of PV for resources that are yet to be assigned a name // ignore creation of PV for resources that are yet to be assigned a name
if er.PolicyResponse.Resource.Name == "" { if er.PolicyResponse.Resource.Name == "" {
log.V(4).Info("resource does no have a name assigned yet, not creating a policy violation", "resource", er.PolicyResponse.Resource) glog.V(4).Infof("resource %v, has not been assigned a name, not creating a policy violation for it", er.PolicyResponse.Resource)
continue continue
} }
// skip when response succeed // skip when response succeed
if er.IsSuccesful() { if er.IsSuccesful() {
continue continue
} }
glog.V(4).Infof("Building policy violation for engine response %v", er)
// build policy violation info // build policy violation info
pvInfos = append(pvInfos, buildPVInfo(er)) pvInfos = append(pvInfos, buildPVInfo(er))
} }

View file

@ -5,7 +5,6 @@ import (
"github.com/nirmata/kyverno/pkg/engine/response" "github.com/nirmata/kyverno/pkg/engine/response"
"gotest.tools/assert" "gotest.tools/assert"
"sigs.k8s.io/controller-runtime/pkg/log"
) )
func Test_GeneratePVsFromEngineResponse_PathNotExist(t *testing.T) { func Test_GeneratePVsFromEngineResponse_PathNotExist(t *testing.T) {
@ -53,6 +52,6 @@ func Test_GeneratePVsFromEngineResponse_PathNotExist(t *testing.T) {
}, },
} }
pvInfos := GeneratePVsFromEngineResponse(ers, log.Log) pvInfos := GeneratePVsFromEngineResponse(ers)
assert.Assert(t, len(pvInfos) == 1) assert.Assert(t, len(pvInfos) == 1)
} }

View file

@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"reflect" "reflect"
"github.com/go-logr/logr" "github.com/golang/glog"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1" kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
kyvernov1 "github.com/nirmata/kyverno/pkg/client/clientset/versioned/typed/kyverno/v1" kyvernov1 "github.com/nirmata/kyverno/pkg/client/clientset/versioned/typed/kyverno/v1"
kyvernolister "github.com/nirmata/kyverno/pkg/client/listers/kyverno/v1" kyvernolister "github.com/nirmata/kyverno/pkg/client/listers/kyverno/v1"
@ -21,13 +21,11 @@ type clusterPV struct {
cpvLister kyvernolister.ClusterPolicyViolationLister cpvLister kyvernolister.ClusterPolicyViolationLister
// policy violation interface // policy violation interface
kyvernoInterface kyvernov1.KyvernoV1Interface kyvernoInterface kyvernov1.KyvernoV1Interface
// logger
log logr.Logger
// update policy stats with violationCount // update policy stats with violationCount
policyStatusListener policystatus.Listener policyStatusListener policystatus.Listener
} }
func newClusterPV(log logr.Logger, dclient *client.Client, func newClusterPV(dclient *client.Client,
cpvLister kyvernolister.ClusterPolicyViolationLister, cpvLister kyvernolister.ClusterPolicyViolationLister,
kyvernoInterface kyvernov1.KyvernoV1Interface, kyvernoInterface kyvernov1.KyvernoV1Interface,
policyStatus policystatus.Listener, policyStatus policystatus.Listener,
@ -36,7 +34,6 @@ func newClusterPV(log logr.Logger, dclient *client.Client,
dclient: dclient, dclient: dclient,
cpvLister: cpvLister, cpvLister: cpvLister,
kyvernoInterface: kyvernoInterface, kyvernoInterface: kyvernoInterface,
log: log,
policyStatusListener: policyStatus, policyStatusListener: policyStatus,
} }
return &cpv return &cpv
@ -59,7 +56,6 @@ func (cpv *clusterPV) create(pv kyverno.PolicyViolationTemplate) error {
} }
func (cpv *clusterPV) getExisting(newPv kyverno.ClusterPolicyViolation) (*kyverno.ClusterPolicyViolation, error) { func (cpv *clusterPV) getExisting(newPv kyverno.ClusterPolicyViolation) (*kyverno.ClusterPolicyViolation, error) {
logger := cpv.log.WithValues("namespace", newPv.Namespace, "name", newPv.Name)
var err error var err error
// use labels // use labels
policyLabelmap := map[string]string{"policy": newPv.Spec.Policy, "resource": newPv.Spec.ResourceSpec.ToKey()} policyLabelmap := map[string]string{"policy": newPv.Spec.Policy, "resource": newPv.Spec.ResourceSpec.ToKey()}
@ -70,7 +66,7 @@ func (cpv *clusterPV) getExisting(newPv kyverno.ClusterPolicyViolation) (*kyvern
pvs, err := cpv.cpvLister.List(ls) pvs, err := cpv.cpvLister.List(ls)
if err != nil { if err != nil {
logger.Error(err, "failed to list cluster policy violations") glog.Errorf("unable to list cluster policy violations : %v", err)
return nil, err return nil, err
} }
@ -87,8 +83,7 @@ func (cpv *clusterPV) getExisting(newPv kyverno.ClusterPolicyViolation) (*kyvern
func (cpv *clusterPV) createPV(newPv *kyverno.ClusterPolicyViolation) error { func (cpv *clusterPV) createPV(newPv *kyverno.ClusterPolicyViolation) error {
var err error var err error
logger := cpv.log.WithValues("policy", newPv.Spec.Policy, "kind", newPv.Spec.ResourceSpec.Kind, "namespace", newPv.Spec.ResourceSpec.Namespace, "name", newPv.Spec.ResourceSpec.Name) glog.V(4).Infof("creating new policy violation for policy %s & resource %s/%s", newPv.Spec.Policy, newPv.Spec.ResourceSpec.Kind, newPv.Spec.ResourceSpec.Name)
logger.V(4).Info("creating new policy violation")
obj, err := retryGetResource(cpv.dclient, newPv.Spec.ResourceSpec) obj, err := retryGetResource(cpv.dclient, newPv.Spec.ResourceSpec)
if err != nil { if err != nil {
return fmt.Errorf("failed to retry getting resource for policy violation %s/%s: %v", newPv.Name, newPv.Spec.Policy, err) return fmt.Errorf("failed to retry getting resource for policy violation %s/%s: %v", newPv.Name, newPv.Spec.Policy, err)
@ -100,7 +95,7 @@ func (cpv *clusterPV) createPV(newPv *kyverno.ClusterPolicyViolation) error {
// create resource // create resource
_, err = cpv.kyvernoInterface.ClusterPolicyViolations().Create(newPv) _, err = cpv.kyvernoInterface.ClusterPolicyViolations().Create(newPv)
if err != nil { if err != nil {
logger.Error(err, "failed to create cluster policy violation") glog.V(4).Infof("failed to create Cluster Policy Violation: %v", err)
return err return err
} }
@ -108,16 +103,15 @@ func (cpv *clusterPV) createPV(newPv *kyverno.ClusterPolicyViolation) error {
cpv.policyStatusListener.Send(violationCount{policyName: newPv.Spec.Policy, violatedRules: newPv.Spec.ViolatedRules}) cpv.policyStatusListener.Send(violationCount{policyName: newPv.Spec.Policy, violatedRules: newPv.Spec.ViolatedRules})
} }
logger.Info("cluster policy violation created") glog.Infof("policy violation created for resource %v", newPv.Spec.ResourceSpec)
return nil return nil
} }
func (cpv *clusterPV) updatePV(newPv, oldPv *kyverno.ClusterPolicyViolation) error { func (cpv *clusterPV) updatePV(newPv, oldPv *kyverno.ClusterPolicyViolation) error {
logger := cpv.log.WithValues("policy", newPv.Spec.Policy, "kind", newPv.Spec.ResourceSpec.Kind, "namespace", newPv.Spec.ResourceSpec.Namespace, "name", newPv.Spec.ResourceSpec.Name)
var err error var err error
// check if there is any update // check if there is any update
if reflect.DeepEqual(newPv.Spec, oldPv.Spec) { if reflect.DeepEqual(newPv.Spec, oldPv.Spec) {
logger.V(4).Info("policy violation spec did not change, not upadating the resource") glog.V(4).Infof("policy violation spec %v did not change so not updating it", newPv.Spec)
return nil return nil
} }
// set name // set name
@ -129,7 +123,7 @@ func (cpv *clusterPV) updatePV(newPv, oldPv *kyverno.ClusterPolicyViolation) err
if err != nil { if err != nil {
return fmt.Errorf("failed to update cluster policy violation: %v", err) return fmt.Errorf("failed to update cluster policy violation: %v", err)
} }
logger.Info("cluster policy violation created") glog.Infof("cluster policy violation updated for resource %v", newPv.Spec.ResourceSpec)
if newPv.Annotations["fromSync"] != "true" { if newPv.Annotations["fromSync"] != "true" {
cpv.policyStatusListener.Send(violationCount{policyName: newPv.Spec.Policy, violatedRules: newPv.Spec.ViolatedRules}) cpv.policyStatusListener.Send(violationCount{policyName: newPv.Spec.Policy, violatedRules: newPv.Spec.ViolatedRules})

View file

@ -5,13 +5,13 @@ import (
"time" "time"
backoff "github.com/cenkalti/backoff" backoff "github.com/cenkalti/backoff"
"github.com/golang/glog"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1" kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
v1 "github.com/nirmata/kyverno/pkg/api/kyverno/v1" v1 "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
client "github.com/nirmata/kyverno/pkg/dclient" client "github.com/nirmata/kyverno/pkg/dclient"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
unstructured "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" unstructured "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
"sigs.k8s.io/controller-runtime/pkg/log"
) )
func createOwnerReference(resource *unstructured.Unstructured) metav1.OwnerReference { func createOwnerReference(resource *unstructured.Unstructured) metav1.OwnerReference {
@ -34,7 +34,7 @@ func retryGetResource(client *client.Client, rspec kyverno.ResourceSpec) (*unstr
var err error var err error
getResource := func() error { getResource := func() error {
obj, err = client.GetResource(rspec.Kind, rspec.Namespace, rspec.Name) obj, err = client.GetResource(rspec.Kind, rspec.Namespace, rspec.Name)
log.Log.V(4).Info(fmt.Sprintf("retry %v getting %s/%s/%s", i, rspec.Kind, rspec.Namespace, rspec.Name)) glog.V(4).Infof("retry %v getting %s/%s/%s", i, rspec.Kind, rspec.Namespace, rspec.Name)
i++ i++
return err return err
} }

View file

@ -8,7 +8,7 @@ import (
"sync" "sync"
"time" "time"
"github.com/go-logr/logr" "github.com/golang/glog"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1" kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
kyvernoclient "github.com/nirmata/kyverno/pkg/client/clientset/versioned" kyvernoclient "github.com/nirmata/kyverno/pkg/client/clientset/versioned"
kyvernov1 "github.com/nirmata/kyverno/pkg/client/clientset/versioned/typed/kyverno/v1" kyvernov1 "github.com/nirmata/kyverno/pkg/client/clientset/versioned/typed/kyverno/v1"
@ -38,7 +38,6 @@ type Generator struct {
// returns true if the cluster policy store has been synced at least once // returns true if the cluster policy store has been synced at least once
pvSynced cache.InformerSynced pvSynced cache.InformerSynced
// returns true if the namespaced cluster policy store has been synced at at least once // returns true if the namespaced cluster policy store has been synced at at least once
log logr.Logger
nspvSynced cache.InformerSynced nspvSynced cache.InformerSynced
queue workqueue.RateLimitingInterface queue workqueue.RateLimitingInterface
dataStore *dataStore dataStore *dataStore
@ -108,8 +107,7 @@ func NewPVGenerator(client *kyvernoclient.Clientset,
dclient *dclient.Client, dclient *dclient.Client,
pvInformer kyvernoinformer.ClusterPolicyViolationInformer, pvInformer kyvernoinformer.ClusterPolicyViolationInformer,
nspvInformer kyvernoinformer.PolicyViolationInformer, nspvInformer kyvernoinformer.PolicyViolationInformer,
policyStatus policystatus.Listener, policyStatus policystatus.Listener) *Generator {
log logr.Logger) *Generator {
gen := Generator{ gen := Generator{
kyvernoInterface: client.KyvernoV1(), kyvernoInterface: client.KyvernoV1(),
dclient: dclient, dclient: dclient,
@ -119,7 +117,6 @@ func NewPVGenerator(client *kyvernoclient.Clientset,
nspvSynced: nspvInformer.Informer().HasSynced, nspvSynced: nspvInformer.Informer().HasSynced,
queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), workQueueName), queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), workQueueName),
dataStore: newDataStore(), dataStore: newDataStore(),
log: log,
policyStatusListener: policyStatus, policyStatusListener: policyStatus,
} }
return &gen return &gen
@ -138,18 +135,18 @@ func (gen *Generator) enqueue(info Info) {
func (gen *Generator) Add(infos ...Info) { func (gen *Generator) Add(infos ...Info) {
for _, info := range infos { for _, info := range infos {
gen.enqueue(info) gen.enqueue(info)
glog.V(3).Infof("Added policy violation: %s", info.toKey())
} }
} }
// Run starts the workers // Run starts the workers
func (gen *Generator) Run(workers int, stopCh <-chan struct{}) { func (gen *Generator) Run(workers int, stopCh <-chan struct{}) {
logger := gen.log
defer utilruntime.HandleCrash() defer utilruntime.HandleCrash()
logger.Info("start") glog.Info("Start policy violation generator")
defer logger.Info("shutting down") defer glog.Info("Shutting down policy violation generator")
if !cache.WaitForCacheSync(stopCh, gen.pvSynced, gen.nspvSynced) { if !cache.WaitForCacheSync(stopCh, gen.pvSynced, gen.nspvSynced) {
logger.Info("failed to sync informer cache") glog.Error("policy violation generator: failed to sync informer cache")
} }
for i := 0; i < workers; i++ { for i := 0; i < workers; i++ {
@ -164,7 +161,6 @@ func (gen *Generator) runWorker() {
} }
func (gen *Generator) handleErr(err error, key interface{}) { func (gen *Generator) handleErr(err error, key interface{}) {
logger := gen.log
if err == nil { if err == nil {
gen.queue.Forget(key) gen.queue.Forget(key)
return return
@ -172,22 +168,23 @@ func (gen *Generator) handleErr(err error, key interface{}) {
// retires requests if there is error // retires requests if there is error
if gen.queue.NumRequeues(key) < workQueueRetryLimit { if gen.queue.NumRequeues(key) < workQueueRetryLimit {
logger.Error(err, "failed to sync policy violation", "key", key) glog.V(4).Infof("Error syncing policy violation %v: %v", key, err)
// Re-enqueue the key rate limited. Based on the rate limiter on the // Re-enqueue the key rate limited. Based on the rate limiter on the
// queue and the re-enqueue history, the key will be processed later again. // queue and the re-enqueue history, the key will be processed later again.
gen.queue.AddRateLimited(key) gen.queue.AddRateLimited(key)
return return
} }
gen.queue.Forget(key) gen.queue.Forget(key)
glog.Error(err)
// remove from data store // remove from data store
if keyHash, ok := key.(string); ok { if keyHash, ok := key.(string); ok {
gen.dataStore.delete(keyHash) gen.dataStore.delete(keyHash)
} }
logger.Error(err, "dropping key out of the queue", "key", key)
glog.Warningf("Dropping the key out of the queue: %v", err)
} }
func (gen *Generator) processNextWorkitem() bool { func (gen *Generator) processNextWorkitem() bool {
logger := gen.log
obj, shutdown := gen.queue.Get() obj, shutdown := gen.queue.Get()
if shutdown { if shutdown {
return false return false
@ -199,7 +196,7 @@ func (gen *Generator) processNextWorkitem() bool {
var ok bool var ok bool
if keyHash, ok = obj.(string); !ok { if keyHash, ok = obj.(string); !ok {
gen.queue.Forget(obj) gen.queue.Forget(obj)
logger.Info("incorrect type; expecting type 'string'", "obj", obj) glog.Warningf("Expecting type string but got %v\n", obj)
return nil return nil
} }
// lookup data store // lookup data store
@ -207,7 +204,7 @@ func (gen *Generator) processNextWorkitem() bool {
if reflect.DeepEqual(info, Info{}) { if reflect.DeepEqual(info, Info{}) {
// empty key // empty key
gen.queue.Forget(obj) gen.queue.Forget(obj)
logger.Info("empty key") glog.Warningf("Got empty key %v\n", obj)
return nil return nil
} }
err := gen.syncHandler(info) err := gen.syncHandler(info)
@ -215,22 +212,22 @@ func (gen *Generator) processNextWorkitem() bool {
return nil return nil
}(obj) }(obj)
if err != nil { if err != nil {
logger.Error(err, "failed to process item") glog.Error(err)
return true return true
} }
return true return true
} }
func (gen *Generator) syncHandler(info Info) error { func (gen *Generator) syncHandler(info Info) error {
logger := gen.log glog.V(4).Infof("received info:%v", info)
var handler pvGenerator var handler pvGenerator
builder := newPvBuilder() builder := newPvBuilder()
if info.Resource.GetNamespace() == "" { if info.Resource.GetNamespace() == "" {
// cluster scope resource generate a clusterpolicy violation // cluster scope resource generate a clusterpolicy violation
handler = newClusterPV(gen.log.WithName("ClusterPV"), gen.dclient, gen.cpvLister, gen.kyvernoInterface, gen.policyStatusListener) handler = newClusterPV(gen.dclient, gen.cpvLister, gen.kyvernoInterface, gen.policyStatusListener)
} else { } else {
// namespaced resources generated a namespaced policy violation in the namespace of the resource // namespaced resources generated a namespaced policy violation in the namespace of the resource
handler = newNamespacedPV(gen.log.WithName("NamespacedPV"), gen.dclient, gen.nspvLister, gen.kyvernoInterface, gen.policyStatusListener) handler = newNamespacedPV(gen.dclient, gen.nspvLister, gen.kyvernoInterface, gen.policyStatusListener)
} }
failure := false failure := false
@ -243,12 +240,12 @@ func (gen *Generator) syncHandler(info Info) error {
} }
// Create Policy Violations // Create Policy Violations
logger.V(4).Info("creating policy violation", "key", info.toKey()) glog.V(3).Infof("Creating policy violation: %s", info.toKey())
if err := handler.create(pv); err != nil { if err := handler.create(pv); err != nil {
failure = true failure = true
logger.Error(err, "failed to create policy violation") glog.V(3).Infof("Failed to create policy violation: %v", err)
} else { } else {
logger.Info("created policy violation", "key", info.toKey()) glog.V(3).Infof("Policy violation created: %s", info.toKey())
} }
if failure { if failure {

View file

@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"reflect" "reflect"
"github.com/go-logr/logr" "github.com/golang/glog"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1" kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
kyvernov1 "github.com/nirmata/kyverno/pkg/client/clientset/versioned/typed/kyverno/v1" kyvernov1 "github.com/nirmata/kyverno/pkg/client/clientset/versioned/typed/kyverno/v1"
kyvernolister "github.com/nirmata/kyverno/pkg/client/listers/kyverno/v1" kyvernolister "github.com/nirmata/kyverno/pkg/client/listers/kyverno/v1"
@ -21,13 +21,11 @@ type namespacedPV struct {
nspvLister kyvernolister.PolicyViolationLister nspvLister kyvernolister.PolicyViolationLister
// policy violation interface // policy violation interface
kyvernoInterface kyvernov1.KyvernoV1Interface kyvernoInterface kyvernov1.KyvernoV1Interface
// logger
log logr.Logger
// update policy status with violationCount // update policy status with violationCount
policyStatusListener policystatus.Listener policyStatusListener policystatus.Listener
} }
func newNamespacedPV(log logr.Logger, dclient *client.Client, func newNamespacedPV(dclient *client.Client,
nspvLister kyvernolister.PolicyViolationLister, nspvLister kyvernolister.PolicyViolationLister,
kyvernoInterface kyvernov1.KyvernoV1Interface, kyvernoInterface kyvernov1.KyvernoV1Interface,
policyStatus policystatus.Listener, policyStatus policystatus.Listener,
@ -36,7 +34,6 @@ func newNamespacedPV(log logr.Logger, dclient *client.Client,
dclient: dclient, dclient: dclient,
nspvLister: nspvLister, nspvLister: nspvLister,
kyvernoInterface: kyvernoInterface, kyvernoInterface: kyvernoInterface,
log: log,
policyStatusListener: policyStatus, policyStatusListener: policyStatus,
} }
return &nspv return &nspv
@ -59,7 +56,6 @@ func (nspv *namespacedPV) create(pv kyverno.PolicyViolationTemplate) error {
} }
func (nspv *namespacedPV) getExisting(newPv kyverno.PolicyViolation) (*kyverno.PolicyViolation, error) { func (nspv *namespacedPV) getExisting(newPv kyverno.PolicyViolation) (*kyverno.PolicyViolation, error) {
logger := nspv.log.WithValues("namespace", newPv.Namespace, "name", newPv.Name)
var err error var err error
// use labels // use labels
policyLabelmap := map[string]string{"policy": newPv.Spec.Policy, "resource": newPv.Spec.ResourceSpec.ToKey()} policyLabelmap := map[string]string{"policy": newPv.Spec.Policy, "resource": newPv.Spec.ResourceSpec.ToKey()}
@ -69,7 +65,7 @@ func (nspv *namespacedPV) getExisting(newPv kyverno.PolicyViolation) (*kyverno.P
} }
pvs, err := nspv.nspvLister.PolicyViolations(newPv.GetNamespace()).List(ls) pvs, err := nspv.nspvLister.PolicyViolations(newPv.GetNamespace()).List(ls)
if err != nil { if err != nil {
logger.Error(err, "failed to list namespaced policy violations") glog.Errorf("unable to list namespaced policy violations : %v", err)
return nil, err return nil, err
} }
@ -86,8 +82,7 @@ func (nspv *namespacedPV) getExisting(newPv kyverno.PolicyViolation) (*kyverno.P
func (nspv *namespacedPV) createPV(newPv *kyverno.PolicyViolation) error { func (nspv *namespacedPV) createPV(newPv *kyverno.PolicyViolation) error {
var err error var err error
logger := nspv.log.WithValues("policy", newPv.Spec.Policy, "kind", newPv.Spec.ResourceSpec.Kind, "namespace", newPv.Spec.ResourceSpec.Namespace, "name", newPv.Spec.ResourceSpec.Name) glog.V(4).Infof("creating new policy violation for policy %s & resource %s/%s/%s", newPv.Spec.Policy, newPv.Spec.ResourceSpec.Kind, newPv.Spec.ResourceSpec.Namespace, newPv.Spec.ResourceSpec.Name)
logger.V(4).Info("creating new policy violation")
obj, err := retryGetResource(nspv.dclient, newPv.Spec.ResourceSpec) obj, err := retryGetResource(nspv.dclient, newPv.Spec.ResourceSpec)
if err != nil { if err != nil {
return fmt.Errorf("failed to retry getting resource for policy violation %s/%s: %v", newPv.Name, newPv.Spec.Policy, err) return fmt.Errorf("failed to retry getting resource for policy violation %s/%s: %v", newPv.Name, newPv.Spec.Policy, err)
@ -99,23 +94,22 @@ func (nspv *namespacedPV) createPV(newPv *kyverno.PolicyViolation) error {
// create resource // create resource
_, err = nspv.kyvernoInterface.PolicyViolations(newPv.GetNamespace()).Create(newPv) _, err = nspv.kyvernoInterface.PolicyViolations(newPv.GetNamespace()).Create(newPv)
if err != nil { if err != nil {
logger.Error(err, "failed to create namespaced policy violation") glog.V(4).Infof("failed to create Cluster Policy Violation: %v", err)
return err return err
} }
if newPv.Annotations["fromSync"] != "true" { if newPv.Annotations["fromSync"] != "true" {
nspv.policyStatusListener.Send(violationCount{policyName: newPv.Spec.Policy, violatedRules: newPv.Spec.ViolatedRules}) nspv.policyStatusListener.Send(violationCount{policyName: newPv.Spec.Policy, violatedRules: newPv.Spec.ViolatedRules})
} }
logger.Info("namespaced policy violation created") glog.Infof("policy violation created for resource %v", newPv.Spec.ResourceSpec)
return nil return nil
} }
func (nspv *namespacedPV) updatePV(newPv, oldPv *kyverno.PolicyViolation) error { func (nspv *namespacedPV) updatePV(newPv, oldPv *kyverno.PolicyViolation) error {
logger := nspv.log.WithValues("policy", newPv.Spec.Policy, "kind", newPv.Spec.ResourceSpec.Kind, "namespace", newPv.Spec.ResourceSpec.Namespace, "name", newPv.Spec.ResourceSpec.Name)
var err error var err error
// check if there is any update // check if there is any update
if reflect.DeepEqual(newPv.Spec, oldPv.Spec) { if reflect.DeepEqual(newPv.Spec, oldPv.Spec) {
logger.V(4).Info("policy violation spec did not change, not upadating the resource") glog.V(4).Infof("policy violation spec %v did not change so not updating it", newPv.Spec)
return nil return nil
} }
// set name // set name
@ -130,6 +124,6 @@ func (nspv *namespacedPV) updatePV(newPv, oldPv *kyverno.PolicyViolation) error
if newPv.Annotations["fromSync"] != "true" { if newPv.Annotations["fromSync"] != "true" {
nspv.policyStatusListener.Send(violationCount{policyName: newPv.Spec.Policy, violatedRules: newPv.Spec.ViolatedRules}) nspv.policyStatusListener.Send(violationCount{policyName: newPv.Spec.Policy, violatedRules: newPv.Spec.ViolatedRules})
} }
logger.Info("namespaced policy violation created") glog.Infof("namespaced policy violation updated for resource %v", newPv.Spec.ResourceSpec)
return nil return nil
} }

View file

@ -3,6 +3,7 @@ package testrunner
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"flag"
"io/ioutil" "io/ioutil"
"os" "os"
ospath "path" ospath "path"
@ -18,6 +19,7 @@ import (
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/kubernetes/scheme"
"github.com/golang/glog"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
apiyaml "k8s.io/apimachinery/pkg/util/yaml" apiyaml "k8s.io/apimachinery/pkg/util/yaml"
) )
@ -306,7 +308,7 @@ func loadPolicyResource(t *testing.T, file string) *unstructured.Unstructured {
func getClient(t *testing.T, files []string) *client.Client { func getClient(t *testing.T, files []string) *client.Client {
var objects []runtime.Object var objects []runtime.Object
if files != nil { if files != nil {
glog.V(4).Infof("loading resources: %v", files)
for _, file := range files { for _, file := range files {
objects = loadObjects(t, file) objects = loadObjects(t, file)
} }
@ -402,7 +404,7 @@ func loadPolicy(t *testing.T, path string) *kyverno.ClusterPolicy {
policy := kyverno.ClusterPolicy{} policy := kyverno.ClusterPolicy{}
pBytes, err := apiyaml.ToJSON(p) pBytes, err := apiyaml.ToJSON(p)
if err != nil { if err != nil {
t.Error(err) glog.Error(err)
continue continue
} }
@ -425,8 +427,7 @@ func loadPolicy(t *testing.T, path string) *kyverno.ClusterPolicy {
} }
func testScenario(t *testing.T, path string) { func testScenario(t *testing.T, path string) {
flag.Set("logtostderr", "true")
// flag.Set("logtostderr", "true")
// flag.Set("v", "8") // flag.Set("v", "8")
scenario, err := loadScenario(t, path) scenario, err := loadScenario(t, path)

View file

@ -4,8 +4,8 @@ import (
"io/ioutil" "io/ioutil"
"os" "os"
"github.com/golang/glog"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"sigs.k8s.io/controller-runtime/pkg/log"
) )
const ( const (
@ -42,7 +42,7 @@ func ConvertToUnstructured(data []byte) (*unstructured.Unstructured, error) {
resource := &unstructured.Unstructured{} resource := &unstructured.Unstructured{}
err := resource.UnmarshalJSON(data) err := resource.UnmarshalJSON(data)
if err != nil { if err != nil {
log.Log.Error(err, "failed to unmarshal resource") glog.V(4).Infof("failed to unmarshall resource: %v", err)
return nil, err return nil, err
} }
return resource, nil return resource, nil

Some files were not shown because too many files have changed in this diff Show more