Skip to content

Commit

Permalink
Return different admission responses internally based on the type of …
Browse files Browse the repository at this point in the history
…errors that methods return. This is so we can differentiate between a bad request, when a resource is not found and when there has been simply an internal server error (#215)
  • Loading branch information
Kyle Hodgetts authored Feb 3, 2022
1 parent ae0069f commit 1377d6a
Showing 1 changed file with 48 additions and 33 deletions.
81 changes: 48 additions & 33 deletions api/v1alpha1/envoyfleet_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"net/http"

v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
logf "sigs.k8s.io/controller-runtime/pkg/log"
Expand Down Expand Up @@ -75,38 +76,37 @@ func (e *EnvoyFleetValidator) Handle(ctx context.Context, req admission.Request)
if err != nil {
return admission.Errored(http.StatusBadRequest, err)
}
if err := e.validate(ctx, envoyFleetObj); err != nil {
return admission.Errored(http.StatusInternalServerError, err)
}

return admission.Allowed("")
return e.validate(ctx, envoyFleetObj)
}

func (e *EnvoyFleetValidator) validate(ctx context.Context, envoyFleet *EnvoyFleet) error {
func (e *EnvoyFleetValidator) validate(ctx context.Context, envoyFleet *EnvoyFleet) admission.Response {

if err := e.validateNameWithinSizeBound(envoyFleet.Name); err != nil {
return err
if resp := e.validateNameWithinSizeBound(envoyFleet.Name); !resp.Allowed {
return resp
}

if err := e.validateNoOverlappingSANSInTLS(ctx, envoyFleet.Spec.TLS.TlsSecrets); err != nil {
return err
if resp := e.validateNoOverlappingSANSInTLS(ctx, envoyFleet.Spec.TLS.TlsSecrets); !resp.Allowed {
return resp
}

return nil
return admission.Allowed("")
}

func (e *EnvoyFleetValidator) validateNameWithinSizeBound(name string) error {
func (e *EnvoyFleetValidator) validateNameWithinSizeBound(name string) admission.Response {
if kubernetesMaxNameLength := 64; len(EnvoyResourceNamePrefix+name) > kubernetesMaxNameLength {
return fmt.Errorf(
err := fmt.Errorf(
"resulting name of envoy resources (%s) is larger than the kubernetes max allowed name of %d",
name,
kubernetesMaxNameLength,
)
return admission.Errored(http.StatusBadRequest, err)
}
return nil

return admission.Allowed("")
}

func (e *EnvoyFleetValidator) validateNoOverlappingSANSInTLS(ctx context.Context, secrets []TLSSecrets) error {
func (e *EnvoyFleetValidator) validateNoOverlappingSANSInTLS(ctx context.Context, secrets []TLSSecrets) admission.Response {
getSecret := func(tlsSecret TLSSecrets) (*v1.Secret, error) {
var secret v1.Secret
if err := e.Client.Get(
Expand All @@ -117,12 +117,7 @@ func (e *EnvoyFleetValidator) validateNoOverlappingSANSInTLS(ctx context.Context
},
&secret,
); err != nil {
return nil, fmt.Errorf(
"unable to query secret %s in namespace %s: %w",
tlsSecret.SecretRef,
tlsSecret.Namespace,
err,
)
return nil, err
}

return &secret, nil
Expand Down Expand Up @@ -153,30 +148,50 @@ func (e *EnvoyFleetValidator) validateNoOverlappingSANSInTLS(ctx context.Context
envoyfleetlog.Info("processing secret", "secret", tlsSecret.SecretRef, "namespace", tlsSecret.Namespace)
secret, err := getSecret(tlsSecret)
if err != nil {
return err
wrappedErr := fmt.Errorf(
"unable to query secret %s in namespace %s: %w",
tlsSecret.SecretRef,
tlsSecret.Namespace,
err,
)

var statusCode int32 = http.StatusInternalServerError
if errors.IsNotFound(err) {
statusCode = http.StatusNotFound
} else if errors.IsBadRequest(err) {
statusCode = http.StatusBadRequest
}

return admission.Errored(statusCode, wrappedErr)
}

crt, ok := secret.Data["tls.crt"]
if !ok {
return fmt.Errorf("tls.crt field not found in secret %s in namespace %s", secret.Name, secret.Namespace)
return admission.Errored(
http.StatusBadRequest,
fmt.Errorf("tls.crt field not found in secret %s in namespace %s", secret.Name, secret.Namespace),
)
}

dnsNames, err := getDNSNamesFromCert(crt)
if err != nil {
return err
return admission.Errored(http.StatusBadRequest, err)
}

for _, dnsName := range dnsNames {
if associatedSecret, ok := sanSet[dnsName]; ok {
return fmt.Errorf(
"conflicting SAN %s found in secret %s in namespace %s. "+
"%s already associated with secret %s in %s",
dnsName,
secret.Name,
secret.Namespace,
dnsName,
associatedSecret.Name,
associatedSecret.Namespace,
return admission.Errored(
http.StatusBadRequest,
fmt.Errorf(
"conflicting SAN %s found in secret %s in namespace %s. "+
"%s already associated with secret %s in %s",
dnsName,
secret.Name,
secret.Namespace,
dnsName,
associatedSecret.Name,
associatedSecret.Namespace,
),
)
}

Expand All @@ -185,5 +200,5 @@ func (e *EnvoyFleetValidator) validateNoOverlappingSANSInTLS(ctx context.Context

}

return nil
return admission.Allowed("")
}

0 comments on commit 1377d6a

Please sign in to comment.