Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade admissionreview to v1 #41

Merged
merged 1 commit into from
Apr 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
133 changes: 116 additions & 17 deletions pkg/apiserver/apiserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"strings"

admissionv1 "k8s.io/api/admission/v1"
admissionv1beta1 "k8s.io/api/admission/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
Expand Down Expand Up @@ -34,26 +35,51 @@ type ValidatingAdmissionHook interface {
// MutatingAdmissionHook as well, the two resources for validating and mutating admission must be different.
// Note: this is (usually) not the same as the payload resource!
ValidatingResource() (plural schema.GroupVersionResource, singular string)
}

type ValidatingAdmissionHookV1Beta1 interface {
ValidatingAdmissionHook

// Validate is called to decide whether to accept the admission request. The returned AdmissionResponse
// must not use the Patch field.
Validate(admissionSpec *admissionv1beta1.AdmissionRequest) *admissionv1beta1.AdmissionResponse
}

type ValidatingAdmissionHookV1 interface {
ValidatingAdmissionHook

// Validate is called to decide whether to accept the v1 admission request. The returned AdmissionResponse
// must not use the Patch field.
Validate(admissionSpec *admissionv1.AdmissionRequest) *admissionv1.AdmissionResponse
}

type MutatingAdmissionHook interface {
AdmissionHook

// MutatingResource is the resource to use for hosting your admission webhook. If the hook implements
// ValidatingAdmissionHook as well, the two resources for validating and mutating admission must be different.
// Note: this is (usually) not the same as the payload resource!
MutatingResource() (plural schema.GroupVersionResource, singular string)
}

type MutatingAdmissionHookV1Beta1 interface {
MutatingAdmissionHook

// Admit is called to decide whether to accept the admission request. The returned AdmissionResponse may
// use the Patch field to mutate the object from the passed AdmissionRequest.
Admit(admissionSpec *admissionv1beta1.AdmissionRequest) *admissionv1beta1.AdmissionResponse
}

type MutatingAdmissionHookV1 interface {
MutatingAdmissionHook

// Admit is called to decide whether to accept the v1 admission request. The returned AdmissionResponse may
// use the Patch field to mutate the object from the passed AdmissionRequest.
Admit(admissionSpec *admissionv1.AdmissionRequest) *admissionv1.AdmissionResponse
}

func init() {
admissionv1.AddToScheme(Scheme)
admissionv1beta1.AddToScheme(Scheme)

// we need to add the options to empty v1
Expand All @@ -74,6 +100,7 @@ func init() {
type Config struct {
GenericConfig *genericapiserver.RecommendedConfig
ExtraConfig ExtraConfig
RestConfig *restclient.Config
}

type ExtraConfig struct {
Expand All @@ -88,6 +115,7 @@ type AdmissionServer struct {
type completedConfig struct {
GenericConfig genericapiserver.CompletedConfig
ExtraConfig *ExtraConfig
RestConfig *restclient.Config
}

type CompletedConfig struct {
Expand All @@ -100,6 +128,7 @@ func (c *Config) Complete() CompletedConfig {
completedCfg := completedConfig{
c.GenericConfig.Complete(),
&c.ExtraConfig,
c.RestConfig,
}

completedCfg.GenericConfig.Version = &version.Info{
Expand All @@ -121,9 +150,12 @@ func (c completedConfig) New() (*AdmissionServer, error) {
GenericAPIServer: genericServer,
}

inClusterConfig, err := restclient.InClusterConfig()
if err != nil {
return nil, err
restConfig := c.RestConfig
if restConfig == nil {
restConfig, err = restclient.InClusterConfig()
if err != nil {
return nil, err
}
}

for _, versionMap := range admissionHooksByGroupThenVersion(c.ExtraConfig.AdmissionHooks...) {
Expand All @@ -147,7 +179,10 @@ func (c completedConfig) New() (*AdmissionServer, error) {
// just overwrite the groupversion with a random one. We don't really care or know.
apiGroupInfo.PrioritizedVersions = appendUniqueGroupVersion(apiGroupInfo.PrioritizedVersions, admissionVersion)

admissionReview := admissionreview.NewREST(admissionHook.Admission)
admissionReview := getAdmissionRest(admissionHook)
if admissionReview == nil {
continue
}
v1alpha1storage, ok := apiGroupInfo.VersionedResourcesStorageMap[admissionVersion.Version]
if !ok {
v1alpha1storage = map[string]rest.Storage{}
Expand All @@ -170,7 +205,7 @@ func (c completedConfig) New() (*AdmissionServer, error) {
}
s.GenericAPIServer.AddPostStartHookOrDie(postStartName,
func(context genericapiserver.PostStartHookContext) error {
return admissionHook.Initialize(inClusterConfig, context.StopCh)
return admissionHook.Initialize(restConfig, context.StopCh)
},
)
}
Expand Down Expand Up @@ -213,55 +248,119 @@ func admissionHooksByGroupThenVersion(admissionHooks ...AdmissionHook) map[strin
ret := map[string]map[string][]admissionHookWrapper{}

for i := range admissionHooks {
if mutatingHook, ok := admissionHooks[i].(MutatingAdmissionHook); ok {
if mutatingHook, ok := admissionHooks[i].(MutatingAdmissionHookV1Beta1); ok {
gvr, _ := mutatingHook.MutatingResource()
group, ok := ret[gvr.Group]
if !ok {
group = map[string][]admissionHookWrapper{}
ret[gvr.Group] = group
}
group[gvr.Version] = append(group[gvr.Version], mutatingAdmissionHookWrapper{mutatingHook})
group[gvr.Version] = append(group[gvr.Version], mutatingAdmissionHookV1Beta1Wrapper{hook: mutatingHook})
}
if validatingHook, ok := admissionHooks[i].(ValidatingAdmissionHook); ok {
if validatingHook, ok := admissionHooks[i].(ValidatingAdmissionHookV1Beta1); ok {
gvr, _ := validatingHook.ValidatingResource()
group, ok := ret[gvr.Group]
if !ok {
group = map[string][]admissionHookWrapper{}
ret[gvr.Group] = group
}
group[gvr.Version] = append(group[gvr.Version], validatingAdmissionHookWrapper{validatingHook})
group[gvr.Version] = append(group[gvr.Version], validatingAdmissionHookV1Beta1Wrapper{hook: validatingHook})
}
if mutatingHook, ok := admissionHooks[i].(MutatingAdmissionHookV1); ok {
gvr, _ := mutatingHook.MutatingResource()
group, ok := ret[gvr.Group]
if !ok {
group = map[string][]admissionHookWrapper{}
ret[gvr.Group] = group
}
group[gvr.Version] = append(group[gvr.Version], mutatingAdmissionHookV1Wrapper{hook: mutatingHook})
}
if validatingHook, ok := admissionHooks[i].(ValidatingAdmissionHookV1); ok {
gvr, _ := validatingHook.ValidatingResource()
group, ok := ret[gvr.Group]
if !ok {
group = map[string][]admissionHookWrapper{}
ret[gvr.Group] = group
}
group[gvr.Version] = append(group[gvr.Version], validatingAdmissionHookV1Wrapper{hook: validatingHook})
}
}

return ret
}

func getAdmissionRest(wrapper admissionHookWrapper) rest.Storage {
switch t := wrapper.(type) {
case admissionHookWrapperV1Alpha1:
return admissionreview.NewREST(t.Admission)
case admissionHookWrapperV1:
return admissionreview.NewV1REST(t.Admission)
}

return nil
}

// admissionHookWrapper wraps either a validating or mutating admission hooks, calling the respective resource and admission method.
type admissionHookWrapper interface {
Resource() (plural schema.GroupVersionResource, singular string)
}

type admissionHookWrapperV1Alpha1 interface {
admissionHookWrapper
Admission(admissionSpec *admissionv1beta1.AdmissionRequest) *admissionv1beta1.AdmissionResponse
}

type mutatingAdmissionHookWrapper struct {
hook MutatingAdmissionHook
type admissionHookWrapperV1 interface {
admissionHookWrapper
Admission(admissionSpec *admissionv1.AdmissionRequest) *admissionv1.AdmissionResponse
}

// v1beta1 wrappers
type mutatingAdmissionHookV1Beta1Wrapper struct {
hook MutatingAdmissionHookV1Beta1
}

func (h mutatingAdmissionHookV1Beta1Wrapper) Resource() (plural schema.GroupVersionResource, singular string) {
return h.hook.MutatingResource()
}

func (h mutatingAdmissionHookV1Beta1Wrapper) Admission(admissionSpec *admissionv1beta1.AdmissionRequest) *admissionv1beta1.AdmissionResponse {
return h.hook.Admit(admissionSpec)
}

type validatingAdmissionHookV1Beta1Wrapper struct {
hook ValidatingAdmissionHookV1Beta1
}

func (h validatingAdmissionHookV1Beta1Wrapper) Resource() (plural schema.GroupVersionResource, singular string) {
return h.hook.ValidatingResource()
}

func (h validatingAdmissionHookV1Beta1Wrapper) Admission(admissionSpec *admissionv1beta1.AdmissionRequest) *admissionv1beta1.AdmissionResponse {
return h.hook.Validate(admissionSpec)
}

// v1 wrappers
type mutatingAdmissionHookV1Wrapper struct {
hook MutatingAdmissionHookV1
}

func (h mutatingAdmissionHookWrapper) Resource() (plural schema.GroupVersionResource, singular string) {
func (h mutatingAdmissionHookV1Wrapper) Resource() (plural schema.GroupVersionResource, singular string) {
return h.hook.MutatingResource()
}

func (h mutatingAdmissionHookWrapper) Admission(admissionSpec *admissionv1beta1.AdmissionRequest) *admissionv1beta1.AdmissionResponse {
func (h mutatingAdmissionHookV1Wrapper) Admission(admissionSpec *admissionv1.AdmissionRequest) *admissionv1.AdmissionResponse {
return h.hook.Admit(admissionSpec)
}

type validatingAdmissionHookWrapper struct {
hook ValidatingAdmissionHook
type validatingAdmissionHookV1Wrapper struct {
hook ValidatingAdmissionHookV1
}

func (h validatingAdmissionHookWrapper) Resource() (plural schema.GroupVersionResource, singular string) {
func (h validatingAdmissionHookV1Wrapper) Resource() (plural schema.GroupVersionResource, singular string) {
return h.hook.ValidatingResource()
}

func (h validatingAdmissionHookWrapper) Admission(admissionSpec *admissionv1beta1.AdmissionRequest) *admissionv1beta1.AdmissionResponse {
func (h validatingAdmissionHookV1Wrapper) Admission(admissionSpec *admissionv1.AdmissionRequest) *admissionv1.AdmissionResponse {
return h.hook.Validate(admissionSpec)
}
Loading