...

Source file src/github.com/emissary-ingress/emissary/v3/pkg/kates/internal/borrowed_webhook.go

Documentation: github.com/emissary-ingress/emissary/v3/pkg/kates/internal

     1  // This file is a lightly modified subset of
     2  // sigs.k8s.io/controller-runtime/pkg/webhook/conversion/conversion.go.
     3  
     4  /*
     5  Copyright 2019 The Kubernetes Authors.
     6  
     7  Licensed under the Apache License, Version 2.0 (the "License");
     8  you may not use this file except in compliance with the License.
     9  You may obtain a copy of the License at
    10  
    11      http://www.apache.org/licenses/LICENSE-2.0
    12  
    13  Unless required by applicable law or agreed to in writing, software
    14  distributed under the License is distributed on an "AS IS" BASIS,
    15  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    16  See the License for the specific language governing permissions and
    17  limitations under the License.
    18  */
    19  
    20  package internal
    21  
    22  import (
    23  	"fmt"
    24  
    25  	"k8s.io/apimachinery/pkg/runtime"
    26  	"k8s.io/apimachinery/pkg/runtime/schema"
    27  	"sigs.k8s.io/controller-runtime/pkg/conversion"
    28  )
    29  
    30  type Webhook struct {
    31  	scheme *runtime.Scheme
    32  }
    33  
    34  // convertObject will convert given a src object to dst object.
    35  // Note(droot): couldn't find a way to reduce the cyclomatic complexity under 10
    36  // without compromising readability, so disabling gocyclo linter
    37  func (wh *Webhook) convertObject(src, dst runtime.Object) error {
    38  	srcGVK := src.GetObjectKind().GroupVersionKind()
    39  	dstGVK := dst.GetObjectKind().GroupVersionKind()
    40  
    41  	if srcGVK.GroupKind() != dstGVK.GroupKind() {
    42  		return fmt.Errorf("src %T and dst %T does not belong to same API Group", src, dst)
    43  	}
    44  
    45  	if srcGVK == dstGVK {
    46  		return fmt.Errorf("conversion is not allowed between same type %T", src)
    47  	}
    48  
    49  	srcIsHub, dstIsHub := isHub(src), isHub(dst)
    50  	srcIsConvertible, dstIsConvertible := isConvertible(src), isConvertible(dst)
    51  
    52  	switch {
    53  	case srcIsHub && dstIsConvertible:
    54  		return dst.(conversion.Convertible).ConvertFrom(src.(conversion.Hub))
    55  	case dstIsHub && srcIsConvertible:
    56  		return src.(conversion.Convertible).ConvertTo(dst.(conversion.Hub))
    57  	case srcIsConvertible && dstIsConvertible:
    58  		return wh.convertViaHub(src.(conversion.Convertible), dst.(conversion.Convertible))
    59  	default:
    60  		return fmt.Errorf("%T is not convertible to %T", src, dst)
    61  	}
    62  }
    63  
    64  func (wh *Webhook) convertViaHub(src, dst conversion.Convertible) error {
    65  	hub, err := wh.getHub(src)
    66  	if err != nil {
    67  		return err
    68  	}
    69  
    70  	if hub == nil {
    71  		return fmt.Errorf("%s does not have any Hub defined", src)
    72  	}
    73  
    74  	err = src.ConvertTo(hub)
    75  	if err != nil {
    76  		return fmt.Errorf("%T failed to convert to hub version %T : %w", src, hub, err)
    77  	}
    78  
    79  	err = dst.ConvertFrom(hub)
    80  	if err != nil {
    81  		return fmt.Errorf("%T failed to convert from hub version %T : %w", dst, hub, err)
    82  	}
    83  
    84  	return nil
    85  }
    86  
    87  // getHub returns an instance of the Hub for passed-in object's group/kind.
    88  func (wh *Webhook) getHub(obj runtime.Object) (conversion.Hub, error) {
    89  	gvks, err := objectGVKs(wh.scheme, obj)
    90  	if err != nil {
    91  		return nil, err
    92  	}
    93  	if len(gvks) == 0 {
    94  		return nil, fmt.Errorf("error retrieving gvks for object : %v", obj)
    95  	}
    96  
    97  	var hub conversion.Hub
    98  	var hubFoundAlready bool
    99  	for _, gvk := range gvks {
   100  		instance, err := wh.scheme.New(gvk)
   101  		if err != nil {
   102  			return nil, fmt.Errorf("failed to allocate an instance for gvk %v: %w", gvk, err)
   103  		}
   104  		if val, isHub := instance.(conversion.Hub); isHub {
   105  			if hubFoundAlready {
   106  				return nil, fmt.Errorf("multiple hub version defined for %T", obj)
   107  			}
   108  			hubFoundAlready = true
   109  			hub = val
   110  		}
   111  	}
   112  	return hub, nil
   113  }
   114  
   115  // objectGVKs returns all (Group,Version,Kind) for the Group/Kind of given object.
   116  func objectGVKs(scheme *runtime.Scheme, obj runtime.Object) ([]schema.GroupVersionKind, error) {
   117  	// NB: we should not use `obj.GetObjectKind().GroupVersionKind()` to get the
   118  	// GVK here, since it is parsed from apiVersion and kind fields and it may
   119  	// return empty GVK if obj is an uninitialized object.
   120  	objGVKs, _, err := scheme.ObjectKinds(obj)
   121  	if err != nil {
   122  		return nil, err
   123  	}
   124  	if len(objGVKs) != 1 {
   125  		return nil, fmt.Errorf("expect to get only one GVK for %v", obj)
   126  	}
   127  	objGVK := objGVKs[0]
   128  	knownTypes := scheme.AllKnownTypes()
   129  
   130  	var gvks []schema.GroupVersionKind
   131  	for gvk := range knownTypes {
   132  		if objGVK.GroupKind() == gvk.GroupKind() {
   133  			gvks = append(gvks, gvk)
   134  		}
   135  	}
   136  	return gvks, nil
   137  }
   138  
   139  // isHub determines if passed-in object is a Hub or not.
   140  func isHub(obj runtime.Object) bool {
   141  	_, yes := obj.(conversion.Hub)
   142  	return yes
   143  }
   144  
   145  // isConvertible determines if passed-in object is a convertible.
   146  func isConvertible(obj runtime.Object) bool {
   147  	_, yes := obj.(conversion.Convertible)
   148  	return yes
   149  }
   150  

View as plain text