1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2024-12-15 17:51:20 +00:00

Merge pull request #147 from nirmata/78_refactor

Go Report formatting and support
This commit is contained in:
shuting 2019-06-05 18:33:51 -07:00 committed by GitHub
commit 01d6af03bb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 92 additions and 65 deletions

View file

@ -14,6 +14,9 @@ install: true
script:
- make build
after_script:
- curl -d "repo=https://github.com/nirmata/kyverno" https://goreportcard.com/checks
after_success:
- docker login -u $DOCKER_USER -p $DOCKER_PASSWORD
- make docker-publish

View file

@ -1,6 +1,6 @@
# Kyverno - Kubernetes Native Policy Management
[![Build Status](https://travis-ci.org/nirmata/kyverno.svg?branch=master)](https://travis-ci.org/nirmata/kyverno)
[![Build Status](https://travis-ci.org/nirmata/kyverno.svg?branch=master)](https://travis-ci.org/nirmata/kyverno) [![Go Report Card](https://goreportcard.com/badge/github.com/nirmata/kyverno)](https://goreportcard.com/report/github.com/nirmata/kyverno)
![logo](documentation/images/Kyverno_Horizontal.png)

View file

@ -28,7 +28,7 @@ func createClientConfig(kubeconfig string) (*rest.Config, error) {
// Loads or creates PEM private key and TLS certificate for webhook server.
// Created pair is stored in cluster's secret.
// Returns struct with key/certificate pair.
func initTlsPemPair(configuration *rest.Config, client *client.Client) (*tls.TlsPemPair, error) {
func initTLSPemPair(configuration *rest.Config, client *client.Client) (*tls.TlsPemPair, error) {
certProps, err := client.GetTLSCertProps(configuration)
if err != nil {
return nil, err

View file

@ -45,7 +45,7 @@ func main() {
violationBuilder,
eventController)
tlsPair, err := initTlsPemPair(clientConfig, client)
tlsPair, err := initTLSPemPair(clientConfig, client)
if err != nil {
glog.Fatalf("Failed to initialize TLS key/certificate pair: %v\n", err)
}

View file

@ -85,7 +85,7 @@ type Violation struct {
Resource string `json:"resource,omitempty"`
Rule string `json:"rule,omitempty"`
Reason string `json:"reason,omitempty"`
Message string `json:"message,omitempty`
Message string `json:"message,omitempty"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

View file

@ -102,6 +102,7 @@ func (pc *PolicyController) Run(stopCh <-chan struct{}) error {
return nil
}
//Stop to perform actions when controller is stopped
func (pc *PolicyController) Stop() {
glog.Info("shutting down policy controller workers")
}
@ -144,7 +145,7 @@ func (pc *PolicyController) handleErr(err error, key interface{}) {
}
pc.queue.Forget(key)
utilruntime.HandleError(err)
glog.Warning("Dropping the key %q out of the queue: %v", key, err)
glog.Warningf("Dropping the key %q out of the queue: %v", key, err)
}
func (pc *PolicyController) syncHandler(obj interface{}) error {

View file

@ -16,7 +16,7 @@ import (
"k8s.io/client-go/rest"
)
// Issues TLS certificate for webhook server using given PEM private key
//GenerateTlsPemPair Issues TLS certificate for webhook server using given PEM private key
// Returns signed and approved TLS certificate in PEM format
func (c *Client) GenerateTlsPemPair(props tls.TlsCertificateProps) (*tls.TlsPemPair, error) {
privateKey, err := tls.TlsGeneratePrivateKey()
@ -26,17 +26,17 @@ func (c *Client) GenerateTlsPemPair(props tls.TlsCertificateProps) (*tls.TlsPemP
certRequest, err := tls.TlsCertificateGenerateRequest(privateKey, props)
if err != nil {
return nil, errors.New(fmt.Sprintf("Unable to create certificate request: %v", err))
return nil, fmt.Errorf("Unable to create certificate request: %v", err)
}
certRequest, err = c.submitAndApproveCertificateRequest(certRequest)
if err != nil {
return nil, errors.New(fmt.Sprintf("Unable to submit and approve certificate request: %v", err))
return nil, fmt.Errorf("Unable to submit and approve certificate request: %v", err)
}
tlsCert, err := c.fetchCertificateFromRequest(certRequest, 10)
if err != nil {
return nil, errors.New(fmt.Sprintf("Failed to configure a certificate for the Kyverno controller. A CA certificate is required to allow the Kubernetes API Server to communicate with Kyverno. You can either provide a certificate or configure your cluster to allow certificate signing. Please refer to https://github.com/nirmata/kyverno/installation.md.: %v", err))
return nil, fmt.Errorf("Failed to configure a certificate for the Kyverno controller. A CA certificate is required to allow the Kubernetes API Server to communicate with Kyverno. You can either provide a certificate or configure your cluster to allow certificate signing. Please refer to https://github.com/nirmata/kyverno/installation.md.: %v", err)
}
return &tls.TlsPemPair{
@ -53,14 +53,14 @@ func (c *Client) submitAndApproveCertificateRequest(req *certificates.Certificat
}
csrList, err := c.ListResource(CSRs, "")
if err != nil {
return nil, errors.New(fmt.Sprintf("Unable to list existing certificate requests: %v", err))
return nil, fmt.Errorf("Unable to list existing certificate requests: %v", err)
}
for _, csr := range csrList.Items {
if csr.GetName() == req.ObjectMeta.Name {
err := c.DeleteResouce(CSRs, "", csr.GetName())
if err != nil {
return nil, errors.New(fmt.Sprintf("Unable to delete existing certificate request: %v", err))
return nil, fmt.Errorf("Unable to delete existing certificate request: %v", err)
}
glog.Info("Old certificate request is deleted")
break
@ -84,7 +84,7 @@ func (c *Client) submitAndApproveCertificateRequest(req *certificates.Certificat
})
res, err = certClient.UpdateApproval(res)
if err != nil {
return nil, errors.New(fmt.Sprintf("Unable to approve certificate request: %v", err))
return nil, fmt.Errorf("Unable to approve certificate request: %v", err)
}
glog.Infof("Certificate request %s is approved", res.ObjectMeta.Name)
@ -115,9 +115,10 @@ func (c *Client) fetchCertificateFromRequest(req *certificates.CertificateSignin
}
}
}
return nil, errors.New(fmt.Sprintf("Cerificate fetch timeout is reached: %d seconds", maxWaitSeconds))
return nil, fmt.Errorf("Cerificate fetch timeout is reached: %d seconds", maxWaitSeconds)
}
//ReadRootCASecret returns the RootCA from the pre-defined secret
func (c *Client) ReadRootCASecret() (result []byte) {
certProps, err := c.GetTLSCertProps(c.clientConfig)
if err != nil {
@ -147,7 +148,7 @@ func (c *Client) ReadRootCASecret() (result []byte) {
const selfSignedAnnotation string = "self-signed-cert"
const rootCAKey string = "rootCA.crt"
// 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 {
sname := generateTLSPairSecretName(props)
unstrSecret, err := c.GetResource(Secrets, props.Namespace, sname)
@ -186,7 +187,7 @@ func (c *Client) ReadTlsPair(props tls.TlsCertificateProps) *tls.TlsPemPair {
return &pemPair
}
// 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.
func (c *Client) WriteTlsPair(props tls.TlsCertificateProps, pemPair *tls.TlsPemPair) error {
name := generateTLSPairSecretName(props)

View file

@ -25,6 +25,7 @@ import (
"k8s.io/client-go/rest"
)
//Client enables interaction with k8 resource
type Client struct {
client dynamic.Interface
cachedClient discovery.CachedDiscoveryInterface
@ -32,6 +33,7 @@ type Client struct {
kclient *kubernetes.Clientset
}
//NewClient creates new instance of client
func NewClient(config *rest.Config) (*Client, error) {
client, err := dynamic.NewForConfig(config)
if err != nil {
@ -51,6 +53,7 @@ func NewClient(config *rest.Config) (*Client, error) {
}, nil
}
//GetKubePolicyDeployment returns kube policy depoyment value
func (c *Client) GetKubePolicyDeployment() (*apps.Deployment, error) {
kubePolicyDeployment, err := c.GetResource("deployments", config.KubePolicyNamespace, config.KubePolicyDeploymentName)
if err != nil {
@ -63,13 +66,14 @@ func (c *Client) GetKubePolicyDeployment() (*apps.Deployment, error) {
return &deploy, nil
}
//GetEventsInterface provides typed interface for events
//TODO: can we use dynamic client to fetch the typed interface
// or generate a kube client value to access the interface
//GetEventsInterface provides typed interface for events
func (c *Client) GetEventsInterface() (event.EventInterface, error) {
return c.kclient.CoreV1().Events(""), nil
}
//GetCSRInterface provides type interface for CSR
func (c *Client) GetCSRInterface() (csrtype.CertificateSigningRequestInterface, error) {
return c.kclient.CertificatesV1beta1().CertificateSigningRequests(), nil
}
@ -110,6 +114,7 @@ func (c *Client) ListResource(resource string, namespace string) (*unstructured.
return c.getResourceInterface(resource, namespace).List(meta.ListOptions{})
}
// DeleteResouce deletes the specified resource
func (c *Client) DeleteResouce(resource string, namespace string, name string) error {
return c.getResourceInterface(resource, namespace).Delete(name, &meta.DeleteOptions{})
@ -228,7 +233,7 @@ func convertToCSR(obj *unstructured.Unstructured) (*certificates.CertificateSign
func (c *Client) waitUntilNamespaceIsCreated(name string) error {
timeStart := time.Now()
var lastError error = nil
var lastError error
for time.Now().Sub(timeStart) < namespaceCreationMaxWaitTime {
_, lastError = c.GetResource(Namespaces, "", name)
if lastError == nil {
@ -253,7 +258,7 @@ func (c *Client) getGVR(resource string) schema.GroupVersionResource {
}
//TODO using cached client to support cache validation and invalidation
// iterate over the key to compare the resource
for gvr, _ := range resources {
for gvr := range resources {
if gvr.Resource == resource {
return gvr
}

View file

@ -5,9 +5,13 @@ import (
)
const (
//CSRs certificatesigningrequests
CSRs string = "certificatesigningrequests"
// Secrets secrets
Secrets string = "secrets"
// ConfigMaps configmaps
ConfigMaps string = "configmaps"
// Namespaces namespaces
Namespaces string = "namespaces"
)
const namespaceCreationMaxWaitTime time.Duration = 30 * time.Second

View file

@ -13,7 +13,7 @@ import (
)
// ProcessOverlay handles validating admission request
// Checks the target resourse for rules defined in the policy
// Checks the target resources for rules defined in the policy
func ProcessOverlay(rule kubepolicy.Rule, rawResource []byte, gvk metav1.GroupVersionKind) ([]PatchBytes, result.RuleApplicationResult) {
overlayApplicationResult := result.NewRuleApplicationResult(rule.Name)
if rule.Mutation == nil || rule.Mutation.Overlay == nil {
@ -112,7 +112,7 @@ func applyOverlayToArray(resource, overlay []interface{}, path string, res *resu
case map[string]interface{}:
for _, overlayElement := range overlay {
typedOverlay := overlayElement.(map[string]interface{})
anchors := GetAnchorsFromMap(typedOverlay)
anchors := getAnchorsFromMap(typedOverlay)
if len(anchors) > 0 {
for i, resourceElement := range resource {
typedResource := resourceElement.(map[string]interface{})
@ -170,7 +170,7 @@ func fillEmptyArray(overlay []interface{}, path string, res *result.RuleApplicat
case map[string]interface{}:
for _, overlayElement := range overlay {
typedOverlay := overlayElement.(map[string]interface{})
anchors := GetAnchorsFromMap(typedOverlay)
anchors := getAnchorsFromMap(typedOverlay)
if len(anchors) == 0 {
patch := insertSubtree(overlayElement, path, res)
@ -287,7 +287,7 @@ func prepareJSONValue(overlay interface{}) string {
func hasOnlyAnchors(overlay interface{}) bool {
switch typed := overlay.(type) {
case map[string]interface{}:
if anchors := GetAnchorsFromMap(typed); len(anchors) == len(typed) {
if anchors := getAnchorsFromMap(typed); len(anchors) == len(typed) {
return true
}
@ -306,7 +306,7 @@ func hasOnlyAnchors(overlay interface{}) bool {
func hasNestedAnchors(overlay interface{}) bool {
switch typed := overlay.(type) {
case map[string]interface{}:
if anchors := GetAnchorsFromMap(typed); len(anchors) > 0 {
if anchors := getAnchorsFromMap(typed); len(anchors) > 0 {
return true
}

View file

@ -18,7 +18,7 @@ func ResourceMeetsDescription(resourceRaw []byte, description kubepolicy.Resourc
}
if resourceRaw != nil {
meta := ParseMetadataFromObject(resourceRaw)
meta := parseMetadataFromObject(resourceRaw)
name := ParseNameFromObject(resourceRaw)
if description.Name != nil {
@ -35,7 +35,7 @@ func ResourceMeetsDescription(resourceRaw []byte, description kubepolicy.Resourc
return false
}
labelMap := ParseLabelsFromMetadata(meta)
labelMap := parseLabelsFromMetadata(meta)
if !selector.Matches(labelMap) {
return false
@ -46,21 +46,21 @@ func ResourceMeetsDescription(resourceRaw []byte, description kubepolicy.Resourc
return true
}
func ParseMetadataFromObject(bytes []byte) map[string]interface{} {
func parseMetadataFromObject(bytes []byte) map[string]interface{} {
var objectJSON map[string]interface{}
json.Unmarshal(bytes, &objectJSON)
return objectJSON["metadata"].(map[string]interface{})
}
func ParseKindFromObject(bytes []byte) string {
func parseKindFromObject(bytes []byte) string {
var objectJSON map[string]interface{}
json.Unmarshal(bytes, &objectJSON)
return objectJSON["kind"].(string)
}
func ParseLabelsFromMetadata(meta map[string]interface{}) labels.Set {
func parseLabelsFromMetadata(meta map[string]interface{}) labels.Set {
if interfaceMap, ok := meta["labels"].(map[string]interface{}); ok {
labelMap := make(labels.Set, len(interfaceMap))
@ -72,6 +72,7 @@ func ParseLabelsFromMetadata(meta map[string]interface{}) labels.Set {
return nil
}
//ParseNameFromObject extracts resource name from JSON obj
func ParseNameFromObject(bytes []byte) string {
var objectJSON map[string]interface{}
json.Unmarshal(bytes, &objectJSON)
@ -84,6 +85,7 @@ func ParseNameFromObject(bytes []byte) string {
return ""
}
// ParseNamespaceFromObject extracts the namespace from the JSON obj
func ParseNamespaceFromObject(bytes []byte) string {
var objectJSON map[string]interface{}
json.Unmarshal(bytes, &objectJSON)
@ -105,7 +107,7 @@ func ParseRegexPolicyResourceName(policyResourceName string) (string, bool) {
return strings.Trim(regex[1], " "), true
}
func GetAnchorsFromMap(anchorsMap map[string]interface{}) map[string]interface{} {
func getAnchorsFromMap(anchorsMap map[string]interface{}) map[string]interface{} {
result := make(map[string]interface{})
for key, value := range anchorsMap {

View file

@ -10,7 +10,7 @@ import (
)
// Validate handles validating admission request
// Checks the target resourse for rules defined in the policy
// Checks the target resources for rules defined in the policy
func Validate(policy kubepolicy.Policy, rawResource []byte, gvk metav1.GroupVersionKind) result.Result {
var resource interface{}
json.Unmarshal(rawResource, &resource)
@ -116,7 +116,7 @@ func validateArray(resourceArray, patternArray []interface{}, path string) resul
switch pattern := patternArray[0].(type) {
case map[string]interface{}:
anchors := GetAnchorsFromMap(pattern)
anchors := getAnchorsFromMap(pattern)
for i, value := range resourceArray {
currentPath := path + strconv.Itoa(i) + "/"
resource, ok := value.(map[string]interface{})

View file

@ -206,7 +206,7 @@ func TestGetAnchorsFromMap_ThereAreAnchors(t *testing.T) {
var unmarshalled map[string]interface{}
json.Unmarshal(rawMap, &unmarshalled)
actualMap := GetAnchorsFromMap(unmarshalled)
actualMap := getAnchorsFromMap(unmarshalled)
assert.Equal(t, len(actualMap), 2)
assert.Equal(t, actualMap["(name)"].(string), "nirmata-*")
assert.Equal(t, actualMap["(namespace)"].(string), "kube-?olicy")
@ -227,7 +227,7 @@ func TestGetAnchorsFromMap_ThereAreNoAnchors(t *testing.T) {
var unmarshalled map[string]interface{}
json.Unmarshal(rawMap, &unmarshalled)
actualMap := GetAnchorsFromMap(unmarshalled)
actualMap := getAnchorsFromMap(unmarshalled)
assert.Assert(t, len(actualMap) == 0)
}

View file

@ -17,6 +17,7 @@ type Info struct {
//MsgKey is an identified to determine the preset message formats
type MsgKey int
//Message id for pre-defined messages
const (
FResourcePolcy MsgKey = iota
FProcessRule

View file

@ -4,9 +4,9 @@ package result
type Reason int
const (
//PolicyViolation there is a violation of policy
Success Reason = iota
//Success policy applied
Success Reason = iota
//Violation there is a violation of policy
Violation
//Failed the request to create/update the resource was blocked(generated from admission-controller)
Failed

View file

@ -37,6 +37,7 @@ type RuleApplicationResult struct {
Messages []string
}
//NewRuleApplicationResult creates a new rule application result
func NewRuleApplicationResult(ruleName string) RuleApplicationResult {
return RuleApplicationResult{
PolicyRule: ruleName,
@ -67,6 +68,7 @@ func (e *RuleApplicationResult) String() string {
return e.StringWithIndent("")
}
// ToError returns the error if reason is not success
func (e *RuleApplicationResult) ToError() error {
if e.Reason != Success {
return fmt.Errorf(e.String())
@ -74,22 +76,23 @@ func (e *RuleApplicationResult) ToError() error {
return nil
}
//GetReason returns reason
func (e *RuleApplicationResult) GetReason() Reason {
return e.Reason
}
// Adds formatted message to this result
func (rar *RuleApplicationResult) AddMessagef(message string, a ...interface{}) {
rar.Messages = append(rar.Messages, fmt.Sprintf(message, a...))
//AddMessagef Adds formatted message to this result
func (e *RuleApplicationResult) AddMessagef(message string, a ...interface{}) {
e.Messages = append(e.Messages, fmt.Sprintf(message, a...))
}
// Sets the Reason Failed and adds formatted message to this result
func (rar *RuleApplicationResult) FailWithMessagef(message string, a ...interface{}) {
rar.Reason = Failed
rar.AddMessagef(message, a...)
//FailWithMessagef Sets the Reason Failed and adds formatted message to this result
func (e *RuleApplicationResult) FailWithMessagef(message string, a ...interface{}) {
e.Reason = Failed
e.AddMessagef(message, a...)
}
// Takes messages and higher reason from another RuleApplicationResult
//MergeWith Takes messages and higher reason from another RuleApplicationResult
func (e *RuleApplicationResult) MergeWith(other *RuleApplicationResult) {
if other != nil {
e.Messages = append(e.Messages, other.Messages...)
@ -122,6 +125,7 @@ func (e *CompositeResult) String() string {
return e.StringWithIndent("")
}
//ToError returns error if reason is not success
func (e *CompositeResult) ToError() error {
if e.Reason != Success {
return fmt.Errorf(e.String())
@ -129,10 +133,12 @@ func (e *CompositeResult) ToError() error {
return nil
}
//GetReason returns reason
func (e *CompositeResult) GetReason() Reason {
return e.Reason
}
//NewPolicyApplicationResult creates a new policy application result
func NewPolicyApplicationResult(policyName string) Result {
return &CompositeResult{
Message: fmt.Sprintf("policy - %s:", policyName),
@ -140,6 +146,7 @@ func NewPolicyApplicationResult(policyName string) Result {
}
}
//NewAdmissionResult creates a new admission result
func NewAdmissionResult(requestUID string) Result {
return &CompositeResult{
Message: fmt.Sprintf("For resource with UID - %s:", requestUID),

View file

@ -11,11 +11,13 @@ import (
"k8s.io/client-go/tools/cache"
)
//PolicyInformer access policy informers
type PolicyInformer interface {
GetLister() v1alpha1.PolicyLister
GetInfomer() cache.SharedIndexInformer
}
// SharedInfomer access shared informers
type SharedInfomer interface {
PolicyInformer
Run(stopCh <-chan struct{})
@ -25,7 +27,7 @@ type sharedInfomer struct {
policyInformerFactory informers.SharedInformerFactory
}
//NewSharedInformer returns shared informer
//NewSharedInformerFactory returns shared informer
func NewSharedInformerFactory(clientConfig *rest.Config) (SharedInfomer, error) {
// create policy client
policyClientset, err := policyclientset.NewForConfig(clientConfig)

View file

@ -14,25 +14,25 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// Properties of TLS certificate which should be issued for webhook server
//TlsCertificateProps Properties of TLS certificate which should be issued for webhook server
type TlsCertificateProps struct {
Service string
Namespace string
ApiServerHost string
}
// The pair of TLS certificate corresponding private key, both in PEM format
//TlsPemPair The pair of TLS certificate corresponding private key, both in PEM format
type TlsPemPair struct {
Certificate []byte
PrivateKey []byte
}
// Generates RSA private key
//TlsGeneratePrivateKey Generates RSA private key
func TlsGeneratePrivateKey() (*rsa.PrivateKey, error) {
return rsa.GenerateKey(rand.Reader, 2048)
}
// Creates PEM block from private key object
//TlsPrivateKeyToPem Creates PEM block from private key object
func TlsPrivateKeyToPem(rsaKey *rsa.PrivateKey) []byte {
privateKey := &pem.Block{
Type: "PRIVATE KEY",
@ -42,7 +42,7 @@ func TlsPrivateKeyToPem(rsaKey *rsa.PrivateKey) []byte {
return pem.EncodeToMemory(privateKey)
}
// Creates PEM block from raw certificate request
//TlsCertificateRequestToPem Creates PEM block from raw certificate request
func TlsCertificateRequestToPem(csrRaw []byte) []byte {
csrBlock := &pem.Block{
Type: "CERTIFICATE REQUEST",
@ -52,7 +52,7 @@ func TlsCertificateRequestToPem(csrRaw []byte) []byte {
return pem.EncodeToMemory(csrBlock)
}
// Generates raw certificate signing request
//TlsCertificateGenerateRequest Generates raw certificate signing request
func TlsCertificateGenerateRequest(privateKey *rsa.PrivateKey, props TlsCertificateProps) (*certificates.CertificateSigningRequest, error) {
dnsNames := make([]string, 3)
dnsNames[0] = props.Service
@ -104,12 +104,12 @@ func TlsCertificateGenerateRequest(privateKey *rsa.PrivateKey, props TlsCertific
}, nil
}
// The generated service name should be the common name for TLS certificate
//GenerateInClusterServiceName The generated service name should be the common name for TLS certificate
func GenerateInClusterServiceName(props TlsCertificateProps) string {
return props.Service + "." + props.Namespace + ".svc"
}
//Gets NotAfter property from raw certificate
//TlsCertificateGetExpirationDate Gets NotAfter property from raw certificate
func TlsCertificateGetExpirationDate(certData []byte) (*time.Time, error) {
block, _ := pem.Decode(certData)
if block == nil {
@ -127,6 +127,7 @@ func TlsCertificateGetExpirationDate(certData []byte) (*time.Time, error) {
// an expired certificate in a controller that has been running for a long time
const timeReserveBeforeCertificateExpiration time.Duration = time.Hour * 24 * 30 * 6 // About half a year
//IsTlsPairShouldBeUpdated checks if TLS pair has expited and needs to be updated
func IsTlsPairShouldBeUpdated(tlsPair *TlsPemPair) bool {
if tlsPair == nil {
return true

View file

@ -163,14 +163,14 @@ func (ws *WebhookServer) HandleMutation(request *v1beta1.AdmissionRequest) *v1be
Patch: engine.JoinPatches(allPatches),
PatchType: &patchType,
}
} else {
}
return &v1beta1.AdmissionResponse{
Allowed: false,
Result: &metav1.Status{
Message: message,
},
}
}
}
// HandleValidation handles validating webhook admission request
@ -249,7 +249,7 @@ func (ws *WebhookServer) bodyToAdmissionReview(request *http.Request, writer htt
glog.Errorf("Error: Can't decode body as AdmissionReview: %v", err)
http.Error(writer, "Can't decode body as AdmissionReview", http.StatusExpectationFailed)
return nil
} else {
return admissionReview
}
return admissionReview
}