slok/kubewebhook

Asserting inferred type?

arkadijs opened this issue · 3 comments

I'm getting a weird results in a mutating webhook writtten to process both v1 and v1beta Ingress.
Full code https://github.com/agilestacks/tls-host-controller/blob/master/cmd/tls-host-controller/main.go

import (
	netv1 "k8s.io/api/networking/v1"
	netv1beta1 "k8s.io/api/networking/v1beta1"
)

mt := mutating.MutatorFunc(func(_ context.Context, _ *kwhmodel.AdmissionReview, obj metav1.Object) (*mutating.MutatorResult, error) {
	ingressv1, v1 := obj.(*netv1.Ingress)
	ingressv1beta1, v1beta1 := obj.(*netv1beta1.Ingress)
	if !v1 && !v1beta1 {
		logger.Warningf("v1: %+v", ingressv1)
		logger.Warningf("v1beta1: %+v", ingressv1beta1)
		logger.Warningf("unsupported object kind %s: %+v", reflect.TypeOf(obj), obj)
		return &mutating.MutatorResult{}, nil
	}

If mutating.WebhookConfig{Obj: &netv1beta1.Ingress{}} is set, then it works. If not, then the output is rather cryptic:

v1: nil
v1beta1: nil
unsupported object kind *v1beta1.Ingress: &Ingress{ObjectMeta:{prometheus-operator-grafana  monitoring  8fbdff6f-a83c-44e5-bb15-ed7f999571ba 19038466 3 2021-02-10 15:54:25 +0000 UTC <nil> <nil> map[app.kubernetes.io/instance:prometheus-operator app.kubernetes.io/managed-by:Helm app.kubernetes.io/name:grafana app.kubernetes.io/version:7.4.5 helm.sh/chart:grafana-6.6.3] map[kubernetes.io/ingress.class:nginx kubernetes.io/tls-acme:true meta.helm.sh/release-name:prometheus-operator meta.helm.sh/release-namespace:monitoring] [] []  []},Spec:IngressSpec{Backend:nil,TLS:[]IngressTLS{IngressTLS <cut>

Any suggestions?

slok commented

Hi @arkadijs!

Could be possible that the v1beta1 that you are receiving is a k8s.io/api/extensions/v1beta1 Ingress?

I guess that when you set the specific object (no inference) on the webhook, it doesn't fail because Kubernetes under the hood is doing its best on the object you passed, however, you are marshalling an object type into a different one, so some fields may be empty.

Check this out as an example:

https://github.com/slok/k8s-webhook-example/blob/ca70c6b387e5268e185d80cfe74823b372eea213/internal/validation/ingress/singlehost.go#L24-L33

Thank you, that was the case. Adding extensions/v1beta1 solved the issue.

Yet, mutating and returning a v1 object is somehow converts it into extensions/v1beta1:

object kind *v1.Ingress: &Ingress{<cut>}
returning *v1.Ingress: &Ingress{<cut>}
Webhook mutating review finished with: '[{\"op\":\"add\",\"path\":\"/metadata/annotations/kubernetes.io~1tls-acme\",\"value\":\"true\"},{\"op\":\"add\",\"path\":\"/spec/tls\",\"value\":[{\"hosts\":[\"<cut>>\"],\"secretName\":\"auto-prometheus-operator-grafana2-tls\"}]}]' JSON Patch" dry-run=false kind=networking.k8s.io/v1/Ingress name=prometheus-operator-grafana2 ns=monitoring op=create path=/mutate request-id=7e958ebe-a9c1-4b33-b4f7-f0d67859da51 webhhok-type=mutating webhook-id=tls-host-controller webhook-kind=mutating wh-version=v1
Admission review request handled" dry-run=false duration=4.183391ms kind=networking.k8s.io/v1/Ingress name=prometheus-operator-grafana2 ns=monitoring op=create path=/mutate request-id=7e958ebe-a9c1-4b33-b4f7-f0d67859da51 svc=http.Handler webhook-id=tls-host-controller webhook-kind=mutating wh-version=v1

Now reading the object with kubectl v1.20.5:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"networking.k8s.io/v1","kind":"Ingress"
<cut>
  name: prometheus-operator-grafana2
<cut>
spec:
  ingressClassName: nginx
<cut>

The server is EKS at v1.19.6.
Registration https://github.com/agilestacks/tls-host-controller/blob/master/deploy/create_cm_issuer_and_cert.sh#L58

Looks like v1.19 issue not related to mutation admission controller: networking.k8s.io/v1 objects are served back as extensions/v1beta1.