Commit 49bee177 authored by Kubernetes Submit Queue's avatar Kubernetes Submit Queue Committed by GitHub

Merge pull request #49115 from CaoShuFeng/audit_beta

Automatic merge from submit-queue (batch tested with PRs 49115, 47480) Upgrade advanced audit to version v1beta1 This change does nothing but only upgrades advanced audit to version v1beta1. There will be following up changes which does real effect to advanced audit feature. After this change audit policy file should contain apiVersion and kind and has such format: ``` apiVersion: audit.k8s.io/v1alpha1 kind: Policy rules: - level: None ``` or use the v1beta1 policy: ``` apiVersion: audit.k8s.io/v1beta1 kind: Policy rules: - level: None ``` Updates #48561 **Release note**: ``` Upgrade advanced audit to version v1beta1. ```
parents 02ad4391 1dc251a1
...@@ -607,6 +607,7 @@ staging/src/k8s.io/apiserver/pkg/apis/apiserver ...@@ -607,6 +607,7 @@ staging/src/k8s.io/apiserver/pkg/apis/apiserver
staging/src/k8s.io/apiserver/pkg/apis/apiserver/v1alpha1 staging/src/k8s.io/apiserver/pkg/apis/apiserver/v1alpha1
staging/src/k8s.io/apiserver/pkg/apis/audit staging/src/k8s.io/apiserver/pkg/apis/audit
staging/src/k8s.io/apiserver/pkg/apis/audit/v1alpha1 staging/src/k8s.io/apiserver/pkg/apis/audit/v1alpha1
staging/src/k8s.io/apiserver/pkg/apis/audit/v1beta1
staging/src/k8s.io/apiserver/pkg/apis/audit/validation staging/src/k8s.io/apiserver/pkg/apis/audit/validation
staging/src/k8s.io/apiserver/pkg/apis/example staging/src/k8s.io/apiserver/pkg/apis/example
staging/src/k8s.io/apiserver/pkg/apis/example/v1 staging/src/k8s.io/apiserver/pkg/apis/example/v1
......
...@@ -51,6 +51,7 @@ openapi_library( ...@@ -51,6 +51,7 @@ openapi_library(
"k8s.io/apimachinery/pkg/util/intstr", "k8s.io/apimachinery/pkg/util/intstr",
"k8s.io/apimachinery/pkg/version", "k8s.io/apimachinery/pkg/version",
"k8s.io/apiserver/pkg/apis/audit/v1alpha1", "k8s.io/apiserver/pkg/apis/audit/v1alpha1",
"k8s.io/apiserver/pkg/apis/audit/v1beta1",
"k8s.io/apiserver/pkg/apis/example/v1", "k8s.io/apiserver/pkg/apis/example/v1",
"k8s.io/client-go/pkg/version", "k8s.io/client-go/pkg/version",
"k8s.io/kube-aggregator/pkg/apis/apiregistration/v1beta1", "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1beta1",
......
...@@ -34,8 +34,10 @@ filegroup( ...@@ -34,8 +34,10 @@ filegroup(
name = "all-srcs", name = "all-srcs",
srcs = [ srcs = [
":package-srcs", ":package-srcs",
"//staging/src/k8s.io/apiserver/pkg/apis/audit/fuzzer:all-srcs",
"//staging/src/k8s.io/apiserver/pkg/apis/audit/install:all-srcs", "//staging/src/k8s.io/apiserver/pkg/apis/audit/install:all-srcs",
"//staging/src/k8s.io/apiserver/pkg/apis/audit/v1alpha1:all-srcs", "//staging/src/k8s.io/apiserver/pkg/apis/audit/v1alpha1:all-srcs",
"//staging/src/k8s.io/apiserver/pkg/apis/audit/v1beta1:all-srcs",
"//staging/src/k8s.io/apiserver/pkg/apis/audit/validation:all-srcs", "//staging/src/k8s.io/apiserver/pkg/apis/audit/validation:all-srcs",
], ],
tags = ["automanaged"], tags = ["automanaged"],
......
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["fuzzer.go"],
visibility = ["//visibility:public"],
deps = [
"//vendor/github.com/google/gofuzz:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
"//vendor/k8s.io/apiserver/pkg/apis/audit:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package fuzzer
import (
fuzz "github.com/google/gofuzz"
"k8s.io/apimachinery/pkg/runtime"
runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/apiserver/pkg/apis/audit"
)
// Funcs returns the fuzzer functions for the audit api group.
func Funcs(codecs runtimeserializer.CodecFactory) []interface{} {
return []interface{}{
func(e *audit.Event, c fuzz.Continue) {
switch c.RandBool() {
case true:
e.RequestObject = nil
case false:
e.RequestObject = &runtime.Unknown{
TypeMeta: runtime.TypeMeta{APIVersion: "", Kind: ""},
Raw: []byte(`{"apiVersion":"","kind":"Pod","someKey":"someValue"}`),
ContentType: runtime.ContentTypeJSON,
}
}
switch c.RandBool() {
case true:
e.ResponseObject = nil
case false:
e.ResponseObject = &runtime.Unknown{
TypeMeta: runtime.TypeMeta{APIVersion: "", Kind: ""},
Raw: []byte(`{"apiVersion":"","kind":"Pod","someKey":"someValue"}`),
ContentType: runtime.ContentTypeJSON,
}
}
},
}
}
...@@ -3,6 +3,7 @@ package(default_visibility = ["//visibility:public"]) ...@@ -3,6 +3,7 @@ package(default_visibility = ["//visibility:public"])
load( load(
"@io_bazel_rules_go//go:def.bzl", "@io_bazel_rules_go//go:def.bzl",
"go_library", "go_library",
"go_test",
) )
go_library( go_library(
...@@ -15,6 +16,7 @@ go_library( ...@@ -15,6 +16,7 @@ go_library(
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//vendor/k8s.io/apiserver/pkg/apis/audit:go_default_library", "//vendor/k8s.io/apiserver/pkg/apis/audit:go_default_library",
"//vendor/k8s.io/apiserver/pkg/apis/audit/v1alpha1:go_default_library", "//vendor/k8s.io/apiserver/pkg/apis/audit/v1alpha1:go_default_library",
"//vendor/k8s.io/apiserver/pkg/apis/audit/v1beta1:go_default_library",
], ],
) )
...@@ -30,3 +32,13 @@ filegroup( ...@@ -30,3 +32,13 @@ filegroup(
srcs = [":package-srcs"], srcs = [":package-srcs"],
tags = ["automanaged"], tags = ["automanaged"],
) )
go_test(
name = "go_default_test",
srcs = ["roundtrip_test.go"],
library = ":go_default_library",
deps = [
"//vendor/k8s.io/apimachinery/pkg/api/testing/roundtrip:go_default_library",
"//vendor/k8s.io/apiserver/pkg/apis/audit/fuzzer:go_default_library",
],
)
...@@ -25,6 +25,7 @@ import ( ...@@ -25,6 +25,7 @@ import (
"k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apiserver/pkg/apis/audit" "k8s.io/apiserver/pkg/apis/audit"
"k8s.io/apiserver/pkg/apis/audit/v1alpha1" "k8s.io/apiserver/pkg/apis/audit/v1alpha1"
"k8s.io/apiserver/pkg/apis/audit/v1beta1"
) )
// Install registers the API group and adds types to a scheme // Install registers the API group and adds types to a scheme
...@@ -32,12 +33,13 @@ func Install(groupFactoryRegistry announced.APIGroupFactoryRegistry, registry *r ...@@ -32,12 +33,13 @@ func Install(groupFactoryRegistry announced.APIGroupFactoryRegistry, registry *r
if err := announced.NewGroupMetaFactory( if err := announced.NewGroupMetaFactory(
&announced.GroupMetaFactoryArgs{ &announced.GroupMetaFactoryArgs{
GroupName: audit.GroupName, GroupName: audit.GroupName,
VersionPreferenceOrder: []string{v1alpha1.SchemeGroupVersion.Version}, VersionPreferenceOrder: []string{v1beta1.SchemeGroupVersion.Version, v1alpha1.SchemeGroupVersion.Version},
// Any Kind that is not namespaced must be cluster scoped. // Any Kind that is not namespaced must be cluster scoped.
RootScopedKinds: sets.NewString("Event", "Policy"), RootScopedKinds: sets.NewString("Event", "Policy"),
AddInternalObjectsToScheme: audit.AddToScheme, AddInternalObjectsToScheme: audit.AddToScheme,
}, },
announced.VersionToSchemeFunc{ announced.VersionToSchemeFunc{
v1beta1.SchemeGroupVersion.Version: v1beta1.AddToScheme,
v1alpha1.SchemeGroupVersion.Version: v1alpha1.AddToScheme, v1alpha1.SchemeGroupVersion.Version: v1alpha1.AddToScheme,
}, },
).Announce(groupFactoryRegistry).RegisterAndEnable(registry, scheme); err != nil { ).Announce(groupFactoryRegistry).RegisterAndEnable(registry, scheme); err != nil {
......
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package install
import (
"testing"
"k8s.io/apimachinery/pkg/api/testing/roundtrip"
"k8s.io/apiserver/pkg/apis/audit/fuzzer"
)
func TestRoundTrip(t *testing.T) {
roundtrip.RoundTripTestForAPIGroup(t, Install, fuzzer.Funcs)
}
package(default_visibility = ["//visibility:public"])
licenses(["notice"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"doc.go",
"register.go",
"types.go",
"zz_generated.conversion.go",
"zz_generated.deepcopy.go",
"zz_generated.defaults.go",
],
tags = ["automanaged"],
deps = [
"//vendor/k8s.io/api/authentication/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/conversion:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
"//vendor/k8s.io/apiserver/pkg/apis/audit:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// +k8s:deepcopy-gen=package,register
// +k8s:conversion-gen=k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/apis/audit
// +k8s:openapi-gen=true
// +k8s:defaulter-gen=TypeMeta
// +groupName=audit.k8s.io
package v1beta1 // import "k8s.io/apiserver/pkg/apis/audit/v1beta1"
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1beta1
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
)
// GroupName is the group name use in this package
const GroupName = "audit.k8s.io"
// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1beta1"}
// Resource takes an unqualified resource and returns a Group qualified GroupResource
func Resource(resource string) schema.GroupResource {
return SchemeGroupVersion.WithResource(resource).GroupResource()
}
var (
SchemeBuilder runtime.SchemeBuilder
localSchemeBuilder = &SchemeBuilder
AddToScheme = localSchemeBuilder.AddToScheme
)
func init() {
// We only register manually written functions here. The registration of the
// generated functions takes place in the generated files. The separation
// makes the code compile even when the generated files are missing.
localSchemeBuilder.Register(addKnownTypes)
}
func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&Event{},
&EventList{},
&Policy{},
&PolicyList{},
)
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
return nil
}
// +build !ignore_autogenerated
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// This file was autogenerated by deepcopy-gen. Do not edit it manually!
package v1beta1
import (
v1 "k8s.io/api/authentication/v1"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
conversion "k8s.io/apimachinery/pkg/conversion"
runtime "k8s.io/apimachinery/pkg/runtime"
reflect "reflect"
)
func init() {
SchemeBuilder.Register(RegisterDeepCopies)
}
// RegisterDeepCopies adds deep-copy functions to the given scheme. Public
// to allow building arbitrary schemes.
//
// Deprecated: deepcopy registration will go away when static deepcopy is fully implemented.
func RegisterDeepCopies(scheme *runtime.Scheme) error {
return scheme.AddGeneratedDeepCopyFuncs(
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
in.(*Event).DeepCopyInto(out.(*Event))
return nil
}, InType: reflect.TypeOf(&Event{})},
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
in.(*EventList).DeepCopyInto(out.(*EventList))
return nil
}, InType: reflect.TypeOf(&EventList{})},
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
in.(*GroupResources).DeepCopyInto(out.(*GroupResources))
return nil
}, InType: reflect.TypeOf(&GroupResources{})},
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
in.(*ObjectReference).DeepCopyInto(out.(*ObjectReference))
return nil
}, InType: reflect.TypeOf(&ObjectReference{})},
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
in.(*Policy).DeepCopyInto(out.(*Policy))
return nil
}, InType: reflect.TypeOf(&Policy{})},
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
in.(*PolicyList).DeepCopyInto(out.(*PolicyList))
return nil
}, InType: reflect.TypeOf(&PolicyList{})},
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
in.(*PolicyRule).DeepCopyInto(out.(*PolicyRule))
return nil
}, InType: reflect.TypeOf(&PolicyRule{})},
)
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Event) DeepCopyInto(out *Event) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
in.Timestamp.DeepCopyInto(&out.Timestamp)
in.User.DeepCopyInto(&out.User)
if in.ImpersonatedUser != nil {
in, out := &in.ImpersonatedUser, &out.ImpersonatedUser
if *in == nil {
*out = nil
} else {
*out = new(v1.UserInfo)
(*in).DeepCopyInto(*out)
}
}
if in.SourceIPs != nil {
in, out := &in.SourceIPs, &out.SourceIPs
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.ObjectRef != nil {
in, out := &in.ObjectRef, &out.ObjectRef
if *in == nil {
*out = nil
} else {
*out = new(ObjectReference)
**out = **in
}
}
if in.ResponseStatus != nil {
in, out := &in.ResponseStatus, &out.ResponseStatus
if *in == nil {
*out = nil
} else {
*out = new(meta_v1.Status)
(*in).DeepCopyInto(*out)
}
}
if in.RequestObject != nil {
in, out := &in.RequestObject, &out.RequestObject
if *in == nil {
*out = nil
} else {
*out = new(runtime.Unknown)
(*in).DeepCopyInto(*out)
}
}
if in.ResponseObject != nil {
in, out := &in.ResponseObject, &out.ResponseObject
if *in == nil {
*out = nil
} else {
*out = new(runtime.Unknown)
(*in).DeepCopyInto(*out)
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Event.
func (in *Event) DeepCopy() *Event {
if in == nil {
return nil
}
out := new(Event)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *Event) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
} else {
return nil
}
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *EventList) DeepCopyInto(out *EventList) {
*out = *in
out.TypeMeta = in.TypeMeta
out.ListMeta = in.ListMeta
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]Event, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EventList.
func (in *EventList) DeepCopy() *EventList {
if in == nil {
return nil
}
out := new(EventList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *EventList) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
} else {
return nil
}
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *GroupResources) DeepCopyInto(out *GroupResources) {
*out = *in
if in.Resources != nil {
in, out := &in.Resources, &out.Resources
*out = make([]string, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GroupResources.
func (in *GroupResources) DeepCopy() *GroupResources {
if in == nil {
return nil
}
out := new(GroupResources)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ObjectReference) DeepCopyInto(out *ObjectReference) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ObjectReference.
func (in *ObjectReference) DeepCopy() *ObjectReference {
if in == nil {
return nil
}
out := new(ObjectReference)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Policy) DeepCopyInto(out *Policy) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
if in.Rules != nil {
in, out := &in.Rules, &out.Rules
*out = make([]PolicyRule, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Policy.
func (in *Policy) DeepCopy() *Policy {
if in == nil {
return nil
}
out := new(Policy)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *Policy) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
} else {
return nil
}
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *PolicyList) DeepCopyInto(out *PolicyList) {
*out = *in
out.TypeMeta = in.TypeMeta
out.ListMeta = in.ListMeta
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]Policy, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PolicyList.
func (in *PolicyList) DeepCopy() *PolicyList {
if in == nil {
return nil
}
out := new(PolicyList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *PolicyList) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
} else {
return nil
}
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *PolicyRule) DeepCopyInto(out *PolicyRule) {
*out = *in
if in.Users != nil {
in, out := &in.Users, &out.Users
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.UserGroups != nil {
in, out := &in.UserGroups, &out.UserGroups
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.Verbs != nil {
in, out := &in.Verbs, &out.Verbs
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.Resources != nil {
in, out := &in.Resources, &out.Resources
*out = make([]GroupResources, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.Namespaces != nil {
in, out := &in.Namespaces, &out.Namespaces
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.NonResourceURLs != nil {
in, out := &in.NonResourceURLs, &out.NonResourceURLs
*out = make([]string, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PolicyRule.
func (in *PolicyRule) DeepCopy() *PolicyRule {
if in == nil {
return nil
}
out := new(PolicyRule)
in.DeepCopyInto(out)
return out
}
// +build !ignore_autogenerated
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// This file was autogenerated by defaulter-gen. Do not edit it manually!
package v1beta1
import (
runtime "k8s.io/apimachinery/pkg/runtime"
)
// RegisterDefaults adds defaulters functions to the given scheme.
// Public to allow building arbitrary schemes.
// All generated defaulters are covering - they call all nested defaulters.
func RegisterDefaults(scheme *runtime.Scheme) error {
return nil
}
...@@ -30,6 +30,7 @@ go_library( ...@@ -30,6 +30,7 @@ go_library(
"//vendor/k8s.io/apimachinery/pkg/util/net:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/net:go_default_library",
"//vendor/k8s.io/apiserver/pkg/apis/audit:go_default_library", "//vendor/k8s.io/apiserver/pkg/apis/audit:go_default_library",
"//vendor/k8s.io/apiserver/pkg/apis/audit/v1alpha1:go_default_library", "//vendor/k8s.io/apiserver/pkg/apis/audit/v1alpha1:go_default_library",
"//vendor/k8s.io/apiserver/pkg/apis/audit/v1beta1:go_default_library",
"//vendor/k8s.io/apiserver/pkg/authorization/authorizer:go_default_library", "//vendor/k8s.io/apiserver/pkg/authorization/authorizer:go_default_library",
], ],
) )
......
...@@ -20,6 +20,7 @@ go_test( ...@@ -20,6 +20,7 @@ go_test(
"//vendor/k8s.io/apiserver/pkg/apis/audit:go_default_library", "//vendor/k8s.io/apiserver/pkg/apis/audit:go_default_library",
"//vendor/k8s.io/apiserver/pkg/authentication/user:go_default_library", "//vendor/k8s.io/apiserver/pkg/authentication/user:go_default_library",
"//vendor/k8s.io/apiserver/pkg/authorization/authorizer:go_default_library", "//vendor/k8s.io/apiserver/pkg/authorization/authorizer:go_default_library",
"//vendor/k8s.io/apiserver/plugin/pkg/audit/webhook:go_default_library",
], ],
) )
...@@ -34,6 +35,7 @@ go_library( ...@@ -34,6 +35,7 @@ go_library(
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apiserver/pkg/apis/audit:go_default_library", "//vendor/k8s.io/apiserver/pkg/apis/audit:go_default_library",
"//vendor/k8s.io/apiserver/pkg/apis/audit/v1alpha1:go_default_library", "//vendor/k8s.io/apiserver/pkg/apis/audit/v1alpha1:go_default_library",
"//vendor/k8s.io/apiserver/pkg/apis/audit/v1beta1:go_default_library",
"//vendor/k8s.io/apiserver/pkg/apis/audit/validation:go_default_library", "//vendor/k8s.io/apiserver/pkg/apis/audit/validation:go_default_library",
"//vendor/k8s.io/apiserver/pkg/audit:go_default_library", "//vendor/k8s.io/apiserver/pkg/audit:go_default_library",
"//vendor/k8s.io/apiserver/pkg/authorization/authorizer:go_default_library", "//vendor/k8s.io/apiserver/pkg/authorization/authorizer:go_default_library",
......
...@@ -23,6 +23,7 @@ import ( ...@@ -23,6 +23,7 @@ import (
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
auditinternal "k8s.io/apiserver/pkg/apis/audit" auditinternal "k8s.io/apiserver/pkg/apis/audit"
auditv1alpha1 "k8s.io/apiserver/pkg/apis/audit/v1alpha1" auditv1alpha1 "k8s.io/apiserver/pkg/apis/audit/v1alpha1"
auditv1beta1 "k8s.io/apiserver/pkg/apis/audit/v1beta1"
"k8s.io/apiserver/pkg/apis/audit/validation" "k8s.io/apiserver/pkg/apis/audit/validation"
"k8s.io/apiserver/pkg/audit" "k8s.io/apiserver/pkg/audit"
...@@ -38,16 +39,10 @@ func LoadPolicyFromFile(filePath string) (*auditinternal.Policy, error) { ...@@ -38,16 +39,10 @@ func LoadPolicyFromFile(filePath string) (*auditinternal.Policy, error) {
return nil, fmt.Errorf("failed to read file path %q: %+v", filePath, err) return nil, fmt.Errorf("failed to read file path %q: %+v", filePath, err)
} }
policyVersioned := &auditv1alpha1.Policy{}
decoder := audit.Codecs.UniversalDecoder(auditv1alpha1.SchemeGroupVersion)
if err := runtime.DecodeInto(decoder, policyDef, policyVersioned); err != nil {
return nil, fmt.Errorf("failed decoding file %q: %v", filePath, err)
}
policy := &auditinternal.Policy{} policy := &auditinternal.Policy{}
if err := audit.Scheme.Convert(policyVersioned, policy, nil); err != nil { decoder := audit.Codecs.UniversalDecoder(auditv1beta1.SchemeGroupVersion, auditv1alpha1.SchemeGroupVersion)
return nil, fmt.Errorf("failed converting policy: %v", err) if err := runtime.DecodeInto(decoder, policyDef, policy); err != nil {
return nil, fmt.Errorf("failed decoding file %q: %v", filePath, err)
} }
if err := validation.ValidatePolicy(policy); err != nil { if err := validation.ValidatePolicy(policy); err != nil {
......
...@@ -24,12 +24,36 @@ import ( ...@@ -24,12 +24,36 @@ import (
"k8s.io/apimachinery/pkg/util/diff" "k8s.io/apimachinery/pkg/util/diff"
"k8s.io/apiserver/pkg/apis/audit" "k8s.io/apiserver/pkg/apis/audit"
// import to call webhook's init() function to register audit.Policy to schema
_ "k8s.io/apiserver/plugin/pkg/audit/webhook"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
const policyDef = ` const policyDefV1alpha1 = `
apiVersion: audit.k8s.io/v1beta1
kind: Policy
rules:
- level: None
nonResourceURLs:
- /healthz*
- /version
- level: RequestResponse
users: ["tim"]
userGroups: ["testers", "developers"]
verbs: ["patch", "delete", "create"]
resources:
- group: ""
- group: "rbac.authorization.k8s.io"
resources: ["clusterroles", "clusterrolebindings"]
namespaces: ["default", "kube-system"]
- level: Metadata
`
const policyDefV1beta1 = `
apiVersion: audit.k8s.io/v1beta1
kind: Policy
rules: rules:
- level: None - level: None
nonResourceURLs: nonResourceURLs:
...@@ -66,13 +90,32 @@ var expectedPolicy = &audit.Policy{ ...@@ -66,13 +90,32 @@ var expectedPolicy = &audit.Policy{
}}, }},
} }
func TestParser(t *testing.T) { func TestParserV1alpha1(t *testing.T) {
// Create a policy file.
f, err := ioutil.TempFile("", "policy.yaml")
require.NoError(t, err)
defer os.Remove(f.Name())
_, err = f.WriteString(policyDefV1alpha1)
require.NoError(t, err)
require.NoError(t, f.Close())
policy, err := LoadPolicyFromFile(f.Name())
require.NoError(t, err)
assert.Len(t, policy.Rules, 3) // Sanity check.
if !reflect.DeepEqual(policy, expectedPolicy) {
t.Errorf("Unexpected policy! Diff:\n%s", diff.ObjectDiff(policy, expectedPolicy))
}
}
func TestParserV1beta1(t *testing.T) {
// Create a policy file. // Create a policy file.
f, err := ioutil.TempFile("", "policy.yaml") f, err := ioutil.TempFile("", "policy.yaml")
require.NoError(t, err) require.NoError(t, err)
defer os.Remove(f.Name()) defer os.Remove(f.Name())
_, err = f.WriteString(policyDef) _, err = f.WriteString(policyDefV1beta1)
require.NoError(t, err) require.NoError(t, err)
require.NoError(t, f.Close()) require.NoError(t, f.Close())
......
...@@ -23,6 +23,7 @@ import ( ...@@ -23,6 +23,7 @@ import (
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer" "k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/apiserver/pkg/apis/audit/v1alpha1" "k8s.io/apiserver/pkg/apis/audit/v1alpha1"
"k8s.io/apiserver/pkg/apis/audit/v1beta1"
) )
var Scheme = runtime.NewScheme() var Scheme = runtime.NewScheme()
...@@ -31,4 +32,5 @@ var Codecs = serializer.NewCodecFactory(Scheme) ...@@ -31,4 +32,5 @@ var Codecs = serializer.NewCodecFactory(Scheme)
func init() { func init() {
v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"}) v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"})
v1alpha1.AddToScheme(Scheme) v1alpha1.AddToScheme(Scheme)
v1beta1.AddToScheme(Scheme)
} }
...@@ -28,7 +28,7 @@ go_test( ...@@ -28,7 +28,7 @@ go_test(
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
"//vendor/k8s.io/apiserver/pkg/apis/audit:go_default_library", "//vendor/k8s.io/apiserver/pkg/apis/audit:go_default_library",
"//vendor/k8s.io/apiserver/pkg/apis/audit/v1alpha1:go_default_library", "//vendor/k8s.io/apiserver/pkg/apis/audit/v1beta1:go_default_library",
"//vendor/k8s.io/apiserver/pkg/audit:go_default_library", "//vendor/k8s.io/apiserver/pkg/audit:go_default_library",
"//vendor/k8s.io/apiserver/pkg/audit/policy:go_default_library", "//vendor/k8s.io/apiserver/pkg/audit/policy:go_default_library",
"//vendor/k8s.io/apiserver/pkg/authentication/authenticator:go_default_library", "//vendor/k8s.io/apiserver/pkg/authentication/authenticator:go_default_library",
......
...@@ -37,7 +37,7 @@ import ( ...@@ -37,7 +37,7 @@ import (
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/util/wait"
auditinternal "k8s.io/apiserver/pkg/apis/audit" auditinternal "k8s.io/apiserver/pkg/apis/audit"
auditv1alpha1 "k8s.io/apiserver/pkg/apis/audit/v1alpha1" auditv1beta1 "k8s.io/apiserver/pkg/apis/audit/v1beta1"
"k8s.io/apiserver/pkg/audit" "k8s.io/apiserver/pkg/audit"
"k8s.io/apiserver/pkg/audit/policy" "k8s.io/apiserver/pkg/audit/policy"
"k8s.io/apiserver/pkg/authentication/user" "k8s.io/apiserver/pkg/authentication/user"
...@@ -441,7 +441,7 @@ func TestAuditJson(t *testing.T) { ...@@ -441,7 +441,7 @@ func TestAuditJson(t *testing.T) {
verb string verb string
auditID string auditID string
handler func(http.ResponseWriter, *http.Request) handler func(http.ResponseWriter, *http.Request)
expected []auditv1alpha1.Event expected []auditv1beta1.Event
respHeader bool respHeader bool
}{ }{
// short running requests with read-only verb // short running requests with read-only verb
...@@ -451,7 +451,7 @@ func TestAuditJson(t *testing.T) { ...@@ -451,7 +451,7 @@ func TestAuditJson(t *testing.T) {
"GET", "GET",
"", "",
func(http.ResponseWriter, *http.Request) {}, func(http.ResponseWriter, *http.Request) {},
[]auditv1alpha1.Event{ []auditv1beta1.Event{
{ {
Stage: auditinternal.StageRequestReceived, Stage: auditinternal.StageRequestReceived,
Verb: "get", Verb: "get",
...@@ -474,7 +474,7 @@ func TestAuditJson(t *testing.T) { ...@@ -474,7 +474,7 @@ func TestAuditJson(t *testing.T) {
func(w http.ResponseWriter, req *http.Request) { func(w http.ResponseWriter, req *http.Request) {
w.Write([]byte("foo")) w.Write([]byte("foo"))
}, },
[]auditv1alpha1.Event{ []auditv1beta1.Event{
{ {
Stage: auditinternal.StageRequestReceived, Stage: auditinternal.StageRequestReceived,
Verb: "get", Verb: "get",
...@@ -497,7 +497,7 @@ func TestAuditJson(t *testing.T) { ...@@ -497,7 +497,7 @@ func TestAuditJson(t *testing.T) {
func(w http.ResponseWriter, req *http.Request) { func(w http.ResponseWriter, req *http.Request) {
panic("kaboom") panic("kaboom")
}, },
[]auditv1alpha1.Event{ []auditv1beta1.Event{
{ {
Stage: auditinternal.StageRequestReceived, Stage: auditinternal.StageRequestReceived,
Verb: "get", Verb: "get",
...@@ -519,7 +519,7 @@ func TestAuditJson(t *testing.T) { ...@@ -519,7 +519,7 @@ func TestAuditJson(t *testing.T) {
"PUT", "PUT",
"", "",
func(http.ResponseWriter, *http.Request) {}, func(http.ResponseWriter, *http.Request) {},
[]auditv1alpha1.Event{ []auditv1beta1.Event{
{ {
Stage: auditinternal.StageRequestReceived, Stage: auditinternal.StageRequestReceived,
Verb: "update", Verb: "update",
...@@ -543,7 +543,7 @@ func TestAuditJson(t *testing.T) { ...@@ -543,7 +543,7 @@ func TestAuditJson(t *testing.T) {
w.Write([]byte("foo")) w.Write([]byte("foo"))
time.Sleep(delay) time.Sleep(delay)
}, },
[]auditv1alpha1.Event{ []auditv1beta1.Event{
{ {
Stage: auditinternal.StageRequestReceived, Stage: auditinternal.StageRequestReceived,
Verb: "update", Verb: "update",
...@@ -567,7 +567,7 @@ func TestAuditJson(t *testing.T) { ...@@ -567,7 +567,7 @@ func TestAuditJson(t *testing.T) {
w.WriteHeader(403) w.WriteHeader(403)
w.Write([]byte("foo")) w.Write([]byte("foo"))
}, },
[]auditv1alpha1.Event{ []auditv1beta1.Event{
{ {
Stage: auditinternal.StageRequestReceived, Stage: auditinternal.StageRequestReceived,
Verb: "update", Verb: "update",
...@@ -590,7 +590,7 @@ func TestAuditJson(t *testing.T) { ...@@ -590,7 +590,7 @@ func TestAuditJson(t *testing.T) {
func(w http.ResponseWriter, req *http.Request) { func(w http.ResponseWriter, req *http.Request) {
panic("kaboom") panic("kaboom")
}, },
[]auditv1alpha1.Event{ []auditv1beta1.Event{
{ {
Stage: auditinternal.StageRequestReceived, Stage: auditinternal.StageRequestReceived,
Verb: "update", Verb: "update",
...@@ -614,7 +614,7 @@ func TestAuditJson(t *testing.T) { ...@@ -614,7 +614,7 @@ func TestAuditJson(t *testing.T) {
w.Write([]byte("foo")) w.Write([]byte("foo"))
panic("kaboom") panic("kaboom")
}, },
[]auditv1alpha1.Event{ []auditv1beta1.Event{
{ {
Stage: auditinternal.StageRequestReceived, Stage: auditinternal.StageRequestReceived,
Verb: "update", Verb: "update",
...@@ -636,7 +636,7 @@ func TestAuditJson(t *testing.T) { ...@@ -636,7 +636,7 @@ func TestAuditJson(t *testing.T) {
"GET", "GET",
"", "",
func(http.ResponseWriter, *http.Request) {}, func(http.ResponseWriter, *http.Request) {},
[]auditv1alpha1.Event{ []auditv1beta1.Event{
{ {
Stage: auditinternal.StageRequestReceived, Stage: auditinternal.StageRequestReceived,
Verb: "watch", Verb: "watch",
...@@ -665,7 +665,7 @@ func TestAuditJson(t *testing.T) { ...@@ -665,7 +665,7 @@ func TestAuditJson(t *testing.T) {
func(w http.ResponseWriter, req *http.Request) { func(w http.ResponseWriter, req *http.Request) {
w.Write([]byte("foo")) w.Write([]byte("foo"))
}, },
[]auditv1alpha1.Event{ []auditv1beta1.Event{
{ {
Stage: auditinternal.StageRequestReceived, Stage: auditinternal.StageRequestReceived,
Verb: "watch", Verb: "watch",
...@@ -694,7 +694,7 @@ func TestAuditJson(t *testing.T) { ...@@ -694,7 +694,7 @@ func TestAuditJson(t *testing.T) {
func(http.ResponseWriter, *http.Request) { func(http.ResponseWriter, *http.Request) {
time.Sleep(delay) time.Sleep(delay)
}, },
[]auditv1alpha1.Event{ []auditv1beta1.Event{
{ {
Stage: auditinternal.StageRequestReceived, Stage: auditinternal.StageRequestReceived,
Verb: "watch", Verb: "watch",
...@@ -724,7 +724,7 @@ func TestAuditJson(t *testing.T) { ...@@ -724,7 +724,7 @@ func TestAuditJson(t *testing.T) {
time.Sleep(delay) time.Sleep(delay)
w.WriteHeader(403) w.WriteHeader(403)
}, },
[]auditv1alpha1.Event{ []auditv1beta1.Event{
{ {
Stage: auditinternal.StageRequestReceived, Stage: auditinternal.StageRequestReceived,
Verb: "watch", Verb: "watch",
...@@ -753,7 +753,7 @@ func TestAuditJson(t *testing.T) { ...@@ -753,7 +753,7 @@ func TestAuditJson(t *testing.T) {
func(w http.ResponseWriter, req *http.Request) { func(w http.ResponseWriter, req *http.Request) {
w.Write([]byte("foo")) w.Write([]byte("foo"))
}, },
[]auditv1alpha1.Event{ []auditv1beta1.Event{
{ {
Stage: auditinternal.StageRequestReceived, Stage: auditinternal.StageRequestReceived,
Verb: "watch", Verb: "watch",
...@@ -783,7 +783,7 @@ func TestAuditJson(t *testing.T) { ...@@ -783,7 +783,7 @@ func TestAuditJson(t *testing.T) {
w.WriteHeader(403) w.WriteHeader(403)
w.Write([]byte("foo")) w.Write([]byte("foo"))
}, },
[]auditv1alpha1.Event{ []auditv1beta1.Event{
{ {
Stage: auditinternal.StageRequestReceived, Stage: auditinternal.StageRequestReceived,
Verb: "watch", Verb: "watch",
...@@ -812,7 +812,7 @@ func TestAuditJson(t *testing.T) { ...@@ -812,7 +812,7 @@ func TestAuditJson(t *testing.T) {
func(w http.ResponseWriter, req *http.Request) { func(w http.ResponseWriter, req *http.Request) {
panic("kaboom") panic("kaboom")
}, },
[]auditv1alpha1.Event{ []auditv1beta1.Event{
{ {
Stage: auditinternal.StageRequestReceived, Stage: auditinternal.StageRequestReceived,
Verb: "watch", Verb: "watch",
...@@ -836,7 +836,7 @@ func TestAuditJson(t *testing.T) { ...@@ -836,7 +836,7 @@ func TestAuditJson(t *testing.T) {
w.Write([]byte("foo")) w.Write([]byte("foo"))
panic("kaboom") panic("kaboom")
}, },
[]auditv1alpha1.Event{ []auditv1beta1.Event{
{ {
Stage: auditinternal.StageRequestReceived, Stage: auditinternal.StageRequestReceived,
Verb: "watch", Verb: "watch",
...@@ -892,8 +892,8 @@ func TestAuditJson(t *testing.T) { ...@@ -892,8 +892,8 @@ func TestAuditJson(t *testing.T) {
expectedID := types.UID("") expectedID := types.UID("")
for i, expect := range test.expected { for i, expect := range test.expected {
// decode events back to check json elements. // decode events back to check json elements.
event := &auditv1alpha1.Event{} event := &auditv1beta1.Event{}
decoder := audit.Codecs.UniversalDecoder(auditv1alpha1.SchemeGroupVersion) decoder := audit.Codecs.UniversalDecoder(auditv1beta1.SchemeGroupVersion)
if err := runtime.DecodeInto(decoder, []byte(line[i]), event); err != nil { if err := runtime.DecodeInto(decoder, []byte(line[i]), event); err != nil {
t.Errorf("failed decoding line %s: %v", line[i], err) t.Errorf("failed decoding line %s: %v", line[i], err)
continue continue
......
...@@ -51,6 +51,7 @@ go_library( ...@@ -51,6 +51,7 @@ go_library(
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//vendor/k8s.io/apiserver/pkg/admission:go_default_library", "//vendor/k8s.io/apiserver/pkg/admission:go_default_library",
"//vendor/k8s.io/apiserver/pkg/admission/initializer:go_default_library", "//vendor/k8s.io/apiserver/pkg/admission/initializer:go_default_library",
"//vendor/k8s.io/apiserver/pkg/apis/audit/v1alpha1:go_default_library",
"//vendor/k8s.io/apiserver/pkg/audit:go_default_library", "//vendor/k8s.io/apiserver/pkg/audit:go_default_library",
"//vendor/k8s.io/apiserver/pkg/audit/policy:go_default_library", "//vendor/k8s.io/apiserver/pkg/audit/policy:go_default_library",
"//vendor/k8s.io/apiserver/pkg/authentication/authenticatorfactory:go_default_library", "//vendor/k8s.io/apiserver/pkg/authentication/authenticatorfactory:go_default_library",
......
...@@ -25,6 +25,8 @@ import ( ...@@ -25,6 +25,8 @@ import (
"github.com/spf13/pflag" "github.com/spf13/pflag"
"gopkg.in/natefinch/lumberjack.v2" "gopkg.in/natefinch/lumberjack.v2"
"k8s.io/apimachinery/pkg/runtime/schema"
auditv1alpha1 "k8s.io/apiserver/pkg/apis/audit/v1alpha1"
"k8s.io/apiserver/pkg/audit" "k8s.io/apiserver/pkg/audit"
"k8s.io/apiserver/pkg/audit/policy" "k8s.io/apiserver/pkg/audit/policy"
"k8s.io/apiserver/pkg/features" "k8s.io/apiserver/pkg/features"
...@@ -237,7 +239,8 @@ func (o *AuditWebhookOptions) applyTo(c *server.Config) error { ...@@ -237,7 +239,8 @@ func (o *AuditWebhookOptions) applyTo(c *server.Config) error {
return nil return nil
} }
webhook, err := pluginwebhook.NewBackend(o.ConfigFile, o.Mode) // TODO: switch to beta
webhook, err := pluginwebhook.NewBackend(o.ConfigFile, o.Mode, []schema.GroupVersion{auditv1alpha1.SchemeGroupVersion})
if err != nil { if err != nil {
return fmt.Errorf("initializing audit webhook: %v", err) return fmt.Errorf("initializing audit webhook: %v", err)
} }
......
...@@ -11,7 +11,7 @@ go_library( ...@@ -11,7 +11,7 @@ go_library(
deps = [ deps = [
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apiserver/pkg/apis/audit:go_default_library", "//vendor/k8s.io/apiserver/pkg/apis/audit:go_default_library",
"//vendor/k8s.io/apiserver/pkg/apis/audit/v1alpha1:go_default_library", "//vendor/k8s.io/apiserver/pkg/apis/audit/v1beta1:go_default_library",
"//vendor/k8s.io/apiserver/pkg/audit:go_default_library", "//vendor/k8s.io/apiserver/pkg/audit:go_default_library",
], ],
) )
......
...@@ -23,7 +23,7 @@ import ( ...@@ -23,7 +23,7 @@ import (
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
auditinternal "k8s.io/apiserver/pkg/apis/audit" auditinternal "k8s.io/apiserver/pkg/apis/audit"
auditv1alpha1 "k8s.io/apiserver/pkg/apis/audit/v1alpha1" auditv1beta1 "k8s.io/apiserver/pkg/apis/audit/v1beta1"
"k8s.io/apiserver/pkg/audit" "k8s.io/apiserver/pkg/audit"
) )
...@@ -66,7 +66,8 @@ func (b *backend) logEvent(ev *auditinternal.Event) { ...@@ -66,7 +66,8 @@ func (b *backend) logEvent(ev *auditinternal.Event) {
case FormatLegacy: case FormatLegacy:
line = audit.EventString(ev) + "\n" line = audit.EventString(ev) + "\n"
case FormatJson: case FormatJson:
bs, err := runtime.Encode(audit.Codecs.LegacyCodec(auditv1alpha1.SchemeGroupVersion), ev) // TODO(audit): figure out a general way to let the client choose their preferred version
bs, err := runtime.Encode(audit.Codecs.LegacyCodec(auditv1beta1.SchemeGroupVersion), ev)
if err != nil { if err != nil {
audit.HandlePluginError("log", err, ev) audit.HandlePluginError("log", err, ev)
return return
......
...@@ -8,15 +8,20 @@ load( ...@@ -8,15 +8,20 @@ load(
go_test( go_test(
name = "go_default_test", name = "go_default_test",
srcs = ["webhook_test.go"], srcs = [
"webhook_test.go",
"webhook_v1alpha1_test.go",
],
library = ":go_default_library", library = ":go_default_library",
deps = [ deps = [
"//vendor/github.com/stretchr/testify/assert:go_default_library", "//vendor/github.com/stretchr/testify/assert:go_default_library",
"//vendor/github.com/stretchr/testify/require:go_default_library", "//vendor/github.com/stretchr/testify/require:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer/json:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime/serializer/json:go_default_library",
"//vendor/k8s.io/apiserver/pkg/apis/audit:go_default_library", "//vendor/k8s.io/apiserver/pkg/apis/audit:go_default_library",
"//vendor/k8s.io/apiserver/pkg/apis/audit/v1alpha1:go_default_library", "//vendor/k8s.io/apiserver/pkg/apis/audit/v1alpha1:go_default_library",
"//vendor/k8s.io/apiserver/pkg/apis/audit/v1beta1:go_default_library",
"//vendor/k8s.io/apiserver/pkg/audit:go_default_library", "//vendor/k8s.io/apiserver/pkg/audit:go_default_library",
"//vendor/k8s.io/client-go/tools/clientcmd/api/v1:go_default_library", "//vendor/k8s.io/client-go/tools/clientcmd/api/v1:go_default_library",
], ],
...@@ -35,6 +40,7 @@ go_library( ...@@ -35,6 +40,7 @@ go_library(
"//vendor/k8s.io/apiserver/pkg/apis/audit:go_default_library", "//vendor/k8s.io/apiserver/pkg/apis/audit:go_default_library",
"//vendor/k8s.io/apiserver/pkg/apis/audit/install:go_default_library", "//vendor/k8s.io/apiserver/pkg/apis/audit/install:go_default_library",
"//vendor/k8s.io/apiserver/pkg/apis/audit/v1alpha1:go_default_library", "//vendor/k8s.io/apiserver/pkg/apis/audit/v1alpha1:go_default_library",
"//vendor/k8s.io/apiserver/pkg/apis/audit/v1beta1:go_default_library",
"//vendor/k8s.io/apiserver/pkg/audit:go_default_library", "//vendor/k8s.io/apiserver/pkg/audit:go_default_library",
"//vendor/k8s.io/apiserver/pkg/util/webhook:go_default_library", "//vendor/k8s.io/apiserver/pkg/util/webhook:go_default_library",
], ],
......
...@@ -33,6 +33,7 @@ import ( ...@@ -33,6 +33,7 @@ import (
auditinternal "k8s.io/apiserver/pkg/apis/audit" auditinternal "k8s.io/apiserver/pkg/apis/audit"
"k8s.io/apiserver/pkg/apis/audit/install" "k8s.io/apiserver/pkg/apis/audit/install"
auditv1alpha1 "k8s.io/apiserver/pkg/apis/audit/v1alpha1" auditv1alpha1 "k8s.io/apiserver/pkg/apis/audit/v1alpha1"
auditv1beta1 "k8s.io/apiserver/pkg/apis/audit/v1beta1"
"k8s.io/apiserver/pkg/audit" "k8s.io/apiserver/pkg/audit"
"k8s.io/apiserver/pkg/util/webhook" "k8s.io/apiserver/pkg/util/webhook"
) )
...@@ -70,12 +71,12 @@ const pluginName = "webhook" ...@@ -70,12 +71,12 @@ const pluginName = "webhook"
// NewBackend returns an audit backend that sends events over HTTP to an external service. // NewBackend returns an audit backend that sends events over HTTP to an external service.
// The mode indicates the caching behavior of the webhook. Either blocking (ModeBlocking) // The mode indicates the caching behavior of the webhook. Either blocking (ModeBlocking)
// or buffered with batch POSTs (ModeBatch). // or buffered with batch POSTs (ModeBatch).
func NewBackend(kubeConfigFile string, mode string) (audit.Backend, error) { func NewBackend(kubeConfigFile string, mode string, groupVersions []schema.GroupVersion) (audit.Backend, error) {
switch mode { switch mode {
case ModeBatch: case ModeBatch:
return newBatchWebhook(kubeConfigFile) return newBatchWebhook(kubeConfigFile, groupVersions)
case ModeBlocking: case ModeBlocking:
return newBlockingWebhook(kubeConfigFile) return newBlockingWebhook(kubeConfigFile, groupVersions)
default: default:
return nil, fmt.Errorf("webhook mode %q is not in list of known modes (%s)", return nil, fmt.Errorf("webhook mode %q is not in list of known modes (%s)",
mode, strings.Join(AllowedModes, ",")) mode, strings.Join(AllowedModes, ","))
...@@ -87,24 +88,25 @@ var ( ...@@ -87,24 +88,25 @@ var (
// //
// Can we make these passable to NewGenericWebhook? // Can we make these passable to NewGenericWebhook?
groupFactoryRegistry = make(announced.APIGroupFactoryRegistry) groupFactoryRegistry = make(announced.APIGroupFactoryRegistry)
groupVersions = []schema.GroupVersion{auditv1alpha1.SchemeGroupVersion} // TODO(audit): figure out a general way to let the client choose their preferred version
registry = registered.NewOrDie("") registry = registered.NewOrDie("")
) )
func init() { func init() {
registry.RegisterVersions(groupVersions) allGVs := []schema.GroupVersion{auditv1alpha1.SchemeGroupVersion, auditv1beta1.SchemeGroupVersion}
if err := registry.EnableVersions(groupVersions...); err != nil { registry.RegisterVersions(allGVs)
panic(fmt.Sprintf("failed to enable version %v", groupVersions)) if err := registry.EnableVersions(allGVs...); err != nil {
panic(fmt.Sprintf("failed to enable version %v", allGVs))
} }
install.Install(groupFactoryRegistry, registry, audit.Scheme) install.Install(groupFactoryRegistry, registry, audit.Scheme)
} }
func loadWebhook(configFile string) (*webhook.GenericWebhook, error) { func loadWebhook(configFile string, groupVersions []schema.GroupVersion) (*webhook.GenericWebhook, error) {
return webhook.NewGenericWebhook(registry, audit.Codecs, configFile, groupVersions, 0) return webhook.NewGenericWebhook(registry, audit.Codecs, configFile, groupVersions, 0)
} }
func newBlockingWebhook(configFile string) (*blockingBackend, error) { func newBlockingWebhook(configFile string, groupVersions []schema.GroupVersion) (*blockingBackend, error) {
w, err := loadWebhook(configFile) w, err := loadWebhook(configFile, groupVersions)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -139,8 +141,8 @@ func (b *blockingBackend) processEvents(ev ...*auditinternal.Event) error { ...@@ -139,8 +141,8 @@ func (b *blockingBackend) processEvents(ev ...*auditinternal.Event) error {
return b.w.RestClient.Post().Body(&list).Do().Error() return b.w.RestClient.Post().Body(&list).Do().Error()
} }
func newBatchWebhook(configFile string) (*batchBackend, error) { func newBatchWebhook(configFile string, groupVersions []schema.GroupVersion) (*batchBackend, error) {
w, err := loadWebhook(configFile) w, err := loadWebhook(configFile, groupVersions)
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
...@@ -24,6 +24,7 @@ import ( ...@@ -24,6 +24,7 @@ import (
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"os" "os"
"reflect"
"sync" "sync"
"sync/atomic" "sync/atomic"
"testing" "testing"
...@@ -33,19 +34,22 @@ import ( ...@@ -33,19 +34,22 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer/json" "k8s.io/apimachinery/pkg/runtime/serializer/json"
auditinternal "k8s.io/apiserver/pkg/apis/audit" auditinternal "k8s.io/apiserver/pkg/apis/audit"
auditv1alpha1 "k8s.io/apiserver/pkg/apis/audit/v1alpha1" auditv1beta1 "k8s.io/apiserver/pkg/apis/audit/v1beta1"
"k8s.io/apiserver/pkg/audit" "k8s.io/apiserver/pkg/audit"
"k8s.io/client-go/tools/clientcmd/api/v1" "k8s.io/client-go/tools/clientcmd/api/v1"
) )
// newWebhookHandler returns a handler which recieves webhook events and decodes the // newWebhookHandler returns a handler which recieves webhook events and decodes the
// request body. The caller passes a callback which is called on each webhook POST. // request body. The caller passes a callback which is called on each webhook POST.
func newWebhookHandler(t *testing.T, cb func(events *auditv1alpha1.EventList)) http.Handler { // The object passed to cb is of the same type as list.
func newWebhookHandler(t *testing.T, list runtime.Object, cb func(events runtime.Object)) http.Handler {
s := json.NewSerializer(json.DefaultMetaFactory, audit.Scheme, audit.Scheme, false) s := json.NewSerializer(json.DefaultMetaFactory, audit.Scheme, audit.Scheme, false)
return &testWebhookHandler{ return &testWebhookHandler{
t: t, t: t,
list: list,
onEvents: cb, onEvents: cb,
serializer: s, serializer: s,
} }
...@@ -54,7 +58,8 @@ func newWebhookHandler(t *testing.T, cb func(events *auditv1alpha1.EventList)) h ...@@ -54,7 +58,8 @@ func newWebhookHandler(t *testing.T, cb func(events *auditv1alpha1.EventList)) h
type testWebhookHandler struct { type testWebhookHandler struct {
t *testing.T t *testing.T
onEvents func(events *auditv1alpha1.EventList) list runtime.Object
onEvents func(events runtime.Object)
serializer runtime.Serializer serializer runtime.Serializer
} }
...@@ -66,15 +71,14 @@ func (t *testWebhookHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { ...@@ -66,15 +71,14 @@ func (t *testWebhookHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return fmt.Errorf("read webhook request body: %v", err) return fmt.Errorf("read webhook request body: %v", err)
} }
obj, _, err := t.serializer.Decode(body, nil, &auditv1alpha1.EventList{}) obj, _, err := t.serializer.Decode(body, nil, t.list.DeepCopyObject())
if err != nil { if err != nil {
return fmt.Errorf("decode request body: %v", err) return fmt.Errorf("decode request body: %v", err)
} }
list, ok := obj.(*auditv1alpha1.EventList) if reflect.TypeOf(obj).Elem() != reflect.TypeOf(t.list).Elem() {
if !ok { return fmt.Errorf("expected %T, got %T", t.list, obj)
return fmt.Errorf("expected *v1alpha1.EventList got %T", obj)
} }
t.onEvents(list) t.onEvents(obj)
return nil return nil
}() }()
...@@ -87,15 +91,15 @@ func (t *testWebhookHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { ...@@ -87,15 +91,15 @@ func (t *testWebhookHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
} }
func newTestBlockingWebhook(t *testing.T, endpoint string) *blockingBackend { func newTestBlockingWebhook(t *testing.T, endpoint string, groupVersions []schema.GroupVersion) *blockingBackend {
return newWebhook(t, endpoint, ModeBlocking).(*blockingBackend) return newWebhook(t, endpoint, ModeBlocking, groupVersions).(*blockingBackend)
} }
func newTestBatchWebhook(t *testing.T, endpoint string) *batchBackend { func newTestBatchWebhook(t *testing.T, endpoint string, groupVersions []schema.GroupVersion) *batchBackend {
return newWebhook(t, endpoint, ModeBatch).(*batchBackend) return newWebhook(t, endpoint, ModeBatch, groupVersions).(*batchBackend)
} }
func newWebhook(t *testing.T, endpoint string, mode string) audit.Backend { func newWebhook(t *testing.T, endpoint string, mode string, groupVersions []schema.GroupVersion) audit.Backend {
config := v1.Config{ config := v1.Config{
Clusters: []v1.NamedCluster{ Clusters: []v1.NamedCluster{
{Cluster: v1.Cluster{Server: endpoint, InsecureSkipTLSVerify: true}}, {Cluster: v1.Cluster{Server: endpoint, InsecureSkipTLSVerify: true}},
...@@ -112,7 +116,7 @@ func newWebhook(t *testing.T, endpoint string, mode string) audit.Backend { ...@@ -112,7 +116,7 @@ func newWebhook(t *testing.T, endpoint string, mode string) audit.Backend {
// NOTE(ericchiang): Do we need to use a proper serializer? // NOTE(ericchiang): Do we need to use a proper serializer?
require.NoError(t, stdjson.NewEncoder(f).Encode(config), "writing kubeconfig") require.NoError(t, stdjson.NewEncoder(f).Encode(config), "writing kubeconfig")
backend, err := NewBackend(f.Name(), mode) backend, err := NewBackend(f.Name(), mode, groupVersions)
require.NoError(t, err, "initializing backend") require.NoError(t, err, "initializing backend")
return backend return backend
...@@ -122,12 +126,12 @@ func TestWebhook(t *testing.T) { ...@@ -122,12 +126,12 @@ func TestWebhook(t *testing.T) {
gotEvents := false gotEvents := false
defer func() { require.True(t, gotEvents, "no events received") }() defer func() { require.True(t, gotEvents, "no events received") }()
s := httptest.NewServer(newWebhookHandler(t, func(events *auditv1alpha1.EventList) { s := httptest.NewServer(newWebhookHandler(t, &auditv1beta1.EventList{}, func(events runtime.Object) {
gotEvents = true gotEvents = true
})) }))
defer s.Close() defer s.Close()
backend := newTestBlockingWebhook(t, s.URL) backend := newTestBlockingWebhook(t, s.URL, []schema.GroupVersion{auditv1beta1.SchemeGroupVersion})
// Ensure this doesn't return a serialization error. // Ensure this doesn't return a serialization error.
event := &auditinternal.Event{} event := &auditinternal.Event{}
...@@ -151,12 +155,12 @@ func TestBatchWebhookMaxEvents(t *testing.T) { ...@@ -151,12 +155,12 @@ func TestBatchWebhookMaxEvents(t *testing.T) {
} }
got := make(chan int, 2) got := make(chan int, 2)
s := httptest.NewServer(newWebhookHandler(t, func(events *auditv1alpha1.EventList) { s := httptest.NewServer(newWebhookHandler(t, &auditv1beta1.EventList{}, func(events runtime.Object) {
got <- len(events.Items) got <- len(events.(*auditv1beta1.EventList).Items)
})) }))
defer s.Close() defer s.Close()
backend := newTestBatchWebhook(t, s.URL) backend := newTestBatchWebhook(t, s.URL, []schema.GroupVersion{auditv1beta1.SchemeGroupVersion})
backend.ProcessEvents(events...) backend.ProcessEvents(events...)
...@@ -183,12 +187,12 @@ func TestBatchWebhookStopCh(t *testing.T) { ...@@ -183,12 +187,12 @@ func TestBatchWebhookStopCh(t *testing.T) {
expected := len(events) expected := len(events)
got := make(chan int, 2) got := make(chan int, 2)
s := httptest.NewServer(newWebhookHandler(t, func(events *auditv1alpha1.EventList) { s := httptest.NewServer(newWebhookHandler(t, &auditv1beta1.EventList{}, func(events runtime.Object) {
got <- len(events.Items) got <- len(events.(*auditv1beta1.EventList).Items)
})) }))
defer s.Close() defer s.Close()
backend := newTestBatchWebhook(t, s.URL) backend := newTestBatchWebhook(t, s.URL, []schema.GroupVersion{auditv1beta1.SchemeGroupVersion})
backend.ProcessEvents(events...) backend.ProcessEvents(events...)
stopCh := make(chan struct{}) stopCh := make(chan struct{})
...@@ -209,12 +213,12 @@ func TestBatchWebhookProcessEventsAfterStop(t *testing.T) { ...@@ -209,12 +213,12 @@ func TestBatchWebhookProcessEventsAfterStop(t *testing.T) {
} }
got := make(chan struct{}) got := make(chan struct{})
s := httptest.NewServer(newWebhookHandler(t, func(events *auditv1alpha1.EventList) { s := httptest.NewServer(newWebhookHandler(t, &auditv1beta1.EventList{}, func(events runtime.Object) {
close(got) close(got)
})) }))
defer s.Close() defer s.Close()
backend := newTestBatchWebhook(t, s.URL) backend := newTestBatchWebhook(t, s.URL, []schema.GroupVersion{auditv1beta1.SchemeGroupVersion})
stopCh := make(chan struct{}) stopCh := make(chan struct{})
backend.Run(stopCh) backend.Run(stopCh)
...@@ -233,13 +237,13 @@ func TestBatchWebhookShutdown(t *testing.T) { ...@@ -233,13 +237,13 @@ func TestBatchWebhookShutdown(t *testing.T) {
got := make(chan struct{}) got := make(chan struct{})
contReqCh := make(chan struct{}) contReqCh := make(chan struct{})
shutdownCh := make(chan struct{}) shutdownCh := make(chan struct{})
s := httptest.NewServer(newWebhookHandler(t, func(events *auditv1alpha1.EventList) { s := httptest.NewServer(newWebhookHandler(t, &auditv1beta1.EventList{}, func(events runtime.Object) {
close(got) close(got)
<-contReqCh <-contReqCh
})) }))
defer s.Close() defer s.Close()
backend := newTestBatchWebhook(t, s.URL) backend := newTestBatchWebhook(t, s.URL, []schema.GroupVersion{auditv1beta1.SchemeGroupVersion})
backend.ProcessEvents(events...) backend.ProcessEvents(events...)
go func() { go func() {
...@@ -278,12 +282,12 @@ func TestBatchWebhookEmptyBuffer(t *testing.T) { ...@@ -278,12 +282,12 @@ func TestBatchWebhookEmptyBuffer(t *testing.T) {
expected := len(events) expected := len(events)
got := make(chan int, 2) got := make(chan int, 2)
s := httptest.NewServer(newWebhookHandler(t, func(events *auditv1alpha1.EventList) { s := httptest.NewServer(newWebhookHandler(t, &auditv1beta1.EventList{}, func(events runtime.Object) {
got <- len(events.Items) got <- len(events.(*auditv1beta1.EventList).Items)
})) }))
defer s.Close() defer s.Close()
backend := newTestBatchWebhook(t, s.URL) backend := newTestBatchWebhook(t, s.URL, []schema.GroupVersion{auditv1beta1.SchemeGroupVersion})
stopCh := make(chan struct{}) stopCh := make(chan struct{})
timer := make(chan time.Time, 1) timer := make(chan time.Time, 1)
...@@ -311,12 +315,12 @@ func TestBatchBufferFull(t *testing.T) { ...@@ -311,12 +315,12 @@ func TestBatchBufferFull(t *testing.T) {
for i := range events { for i := range events {
events[i] = &auditinternal.Event{} events[i] = &auditinternal.Event{}
} }
s := httptest.NewServer(newWebhookHandler(t, func(events *auditv1alpha1.EventList) { s := httptest.NewServer(newWebhookHandler(t, &auditv1beta1.EventList{}, func(events runtime.Object) {
// Do nothing. // Do nothing.
})) }))
defer s.Close() defer s.Close()
backend := newTestBatchWebhook(t, s.URL) backend := newTestBatchWebhook(t, s.URL, []schema.GroupVersion{auditv1beta1.SchemeGroupVersion})
// Make sure this doesn't block. // Make sure this doesn't block.
backend.ProcessEvents(events...) backend.ProcessEvents(events...)
...@@ -344,7 +348,8 @@ func TestBatchRun(t *testing.T) { ...@@ -344,7 +348,8 @@ func TestBatchRun(t *testing.T) {
close(done) close(done)
}() }()
s := httptest.NewServer(newWebhookHandler(t, func(events *auditv1alpha1.EventList) { s := httptest.NewServer(newWebhookHandler(t, &auditv1beta1.EventList{}, func(obj runtime.Object) {
events := obj.(*auditv1beta1.EventList)
atomic.AddInt64(got, int64(len(events.Items))) atomic.AddInt64(got, int64(len(events.Items)))
wg.Add(-len(events.Items)) wg.Add(-len(events.Items))
})) }))
...@@ -353,7 +358,7 @@ func TestBatchRun(t *testing.T) { ...@@ -353,7 +358,7 @@ func TestBatchRun(t *testing.T) {
stopCh := make(chan struct{}) stopCh := make(chan struct{})
defer close(stopCh) defer close(stopCh)
backend := newTestBatchWebhook(t, s.URL) backend := newTestBatchWebhook(t, s.URL, []schema.GroupVersion{auditv1beta1.SchemeGroupVersion})
// Test the Run codepath. E.g. that the spawned goroutines behave correctly. // Test the Run codepath. E.g. that the spawned goroutines behave correctly.
backend.Run(stopCh) backend.Run(stopCh)
...@@ -377,8 +382,8 @@ func TestBatchConcurrentRequests(t *testing.T) { ...@@ -377,8 +382,8 @@ func TestBatchConcurrentRequests(t *testing.T) {
wg := new(sync.WaitGroup) wg := new(sync.WaitGroup)
wg.Add(len(events)) wg.Add(len(events))
s := httptest.NewServer(newWebhookHandler(t, func(events *auditv1alpha1.EventList) { s := httptest.NewServer(newWebhookHandler(t, &auditv1beta1.EventList{}, func(events runtime.Object) {
wg.Add(-len(events.Items)) wg.Add(-len(events.(*auditv1beta1.EventList).Items))
// Since the webhook makes concurrent requests, blocking on the webhook response // Since the webhook makes concurrent requests, blocking on the webhook response
// shouldn't block the webhook from sending more events. // shouldn't block the webhook from sending more events.
...@@ -391,7 +396,7 @@ func TestBatchConcurrentRequests(t *testing.T) { ...@@ -391,7 +396,7 @@ func TestBatchConcurrentRequests(t *testing.T) {
stopCh := make(chan struct{}) stopCh := make(chan struct{})
defer close(stopCh) defer close(stopCh)
backend := newTestBatchWebhook(t, s.URL) backend := newTestBatchWebhook(t, s.URL, []schema.GroupVersion{auditv1beta1.SchemeGroupVersion})
backend.Run(stopCh) backend.Run(stopCh)
backend.ProcessEvents(events...) backend.ProcessEvents(events...)
......
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package webhook
import (
"net/http/httptest"
"sync"
"sync/atomic"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
auditinternal "k8s.io/apiserver/pkg/apis/audit"
auditv1alpha1 "k8s.io/apiserver/pkg/apis/audit/v1alpha1"
)
func TestBatchWebhookMaxEventsV1Alpha1(t *testing.T) {
nRest := 10
events := make([]*auditinternal.Event, defaultBatchMaxSize+nRest) // greater than max size.
for i := range events {
events[i] = &auditinternal.Event{}
}
got := make(chan int, 2)
s := httptest.NewServer(newWebhookHandler(t, &auditv1alpha1.EventList{}, func(events runtime.Object) {
got <- len(events.(*auditv1alpha1.EventList).Items)
}))
defer s.Close()
backend := newTestBatchWebhook(t, s.URL, []schema.GroupVersion{auditv1alpha1.SchemeGroupVersion})
backend.ProcessEvents(events...)
stopCh := make(chan struct{})
timer := make(chan time.Time, 1)
backend.sendBatchEvents(backend.collectEvents(stopCh, timer))
require.Equal(t, defaultBatchMaxSize, <-got, "did not get batch max size")
go func() {
waitForEmptyBuffer(backend) // wait for the buffer to empty
timer <- time.Now() // Trigger the wait timeout
}()
backend.sendBatchEvents(backend.collectEvents(stopCh, timer))
require.Equal(t, nRest, <-got, "failed to get the rest of the events")
}
func TestBatchWebhookStopChV1Alpha1(t *testing.T) {
events := make([]*auditinternal.Event, 1) // less than max size.
for i := range events {
events[i] = &auditinternal.Event{}
}
expected := len(events)
got := make(chan int, 2)
s := httptest.NewServer(newWebhookHandler(t, &auditv1alpha1.EventList{}, func(events runtime.Object) {
got <- len(events.(*auditv1alpha1.EventList).Items)
}))
defer s.Close()
backend := newTestBatchWebhook(t, s.URL, []schema.GroupVersion{auditv1alpha1.SchemeGroupVersion})
backend.ProcessEvents(events...)
stopCh := make(chan struct{})
timer := make(chan time.Time)
go func() {
waitForEmptyBuffer(backend)
close(stopCh) // stop channel has stopped
}()
backend.sendBatchEvents(backend.collectEvents(stopCh, timer))
require.Equal(t, expected, <-got, "get queued events after timer expires")
}
func TestBatchWebhookProcessEventsAfterStopV1Alpha1(t *testing.T) {
events := make([]*auditinternal.Event, 1) // less than max size.
for i := range events {
events[i] = &auditinternal.Event{}
}
got := make(chan struct{})
s := httptest.NewServer(newWebhookHandler(t, &auditv1alpha1.EventList{}, func(events runtime.Object) {
close(got)
}))
defer s.Close()
backend := newTestBatchWebhook(t, s.URL, []schema.GroupVersion{auditv1alpha1.SchemeGroupVersion})
stopCh := make(chan struct{})
backend.Run(stopCh)
close(stopCh)
<-backend.shutdownCh
backend.ProcessEvents(events...)
assert.Equal(t, 0, len(backend.buffer), "processed events after the backed has been stopped")
}
func TestBatchWebhookShutdownV1Alpha1(t *testing.T) {
events := make([]*auditinternal.Event, 1)
for i := range events {
events[i] = &auditinternal.Event{}
}
got := make(chan struct{})
contReqCh := make(chan struct{})
shutdownCh := make(chan struct{})
s := httptest.NewServer(newWebhookHandler(t, &auditv1alpha1.EventList{}, func(events runtime.Object) {
close(got)
<-contReqCh
}))
defer s.Close()
backend := newTestBatchWebhook(t, s.URL, []schema.GroupVersion{auditv1alpha1.SchemeGroupVersion})
backend.ProcessEvents(events...)
go func() {
// Assume stopCh was closed.
close(backend.buffer)
backend.sendBatchEvents(backend.collectLastEvents())
}()
<-got
go func() {
close(backend.shutdownCh)
backend.Shutdown()
close(shutdownCh)
}()
// Wait for some time in case there's a bug that allows for the Shutdown
// method to exit before all requests has been completed.
time.Sleep(1 * time.Second)
select {
case <-shutdownCh:
t.Fatal("Backend shut down before all requests finished")
default:
// Continue.
}
close(contReqCh)
<-shutdownCh
}
func TestBatchWebhookEmptyBufferV1Alpha1(t *testing.T) {
events := make([]*auditinternal.Event, 1) // less than max size.
for i := range events {
events[i] = &auditinternal.Event{}
}
expected := len(events)
got := make(chan int, 2)
s := httptest.NewServer(newWebhookHandler(t, &auditv1alpha1.EventList{}, func(events runtime.Object) {
got <- len(events.(*auditv1alpha1.EventList).Items)
}))
defer s.Close()
backend := newTestBatchWebhook(t, s.URL, []schema.GroupVersion{auditv1alpha1.SchemeGroupVersion})
stopCh := make(chan struct{})
timer := make(chan time.Time, 1)
timer <- time.Now() // Timer is done.
// Buffer is empty, no events have been queued. This should exit but send no events.
backend.sendBatchEvents(backend.collectEvents(stopCh, timer))
// Send additional events after the sendBatchEvents has been called.
backend.ProcessEvents(events...)
go func() {
waitForEmptyBuffer(backend)
timer <- time.Now()
}()
backend.sendBatchEvents(backend.collectEvents(stopCh, timer))
// Make sure we didn't get a POST with zero events.
require.Equal(t, expected, <-got, "expected one event")
}
func TestBatchBufferFullV1Alpha1(t *testing.T) {
events := make([]*auditinternal.Event, defaultBatchBufferSize+1) // More than buffered size
for i := range events {
events[i] = &auditinternal.Event{}
}
s := httptest.NewServer(newWebhookHandler(t, &auditv1alpha1.EventList{}, func(events runtime.Object) {
// Do nothing.
}))
defer s.Close()
backend := newTestBatchWebhook(t, s.URL, []schema.GroupVersion{auditv1alpha1.SchemeGroupVersion})
// Make sure this doesn't block.
backend.ProcessEvents(events...)
}
func TestBatchRunV1Alpha1(t *testing.T) {
// Divisable by max batch size so we don't have to wait for a minute for
// the test to finish.
events := make([]*auditinternal.Event, defaultBatchMaxSize*3)
for i := range events {
events[i] = &auditinternal.Event{}
}
got := new(int64)
want := len(events)
wg := new(sync.WaitGroup)
wg.Add(want)
done := make(chan struct{})
go func() {
wg.Wait()
// When the expected number of events have been received, close the channel.
close(done)
}()
s := httptest.NewServer(newWebhookHandler(t, &auditv1alpha1.EventList{}, func(obj runtime.Object) {
events := obj.(*auditv1alpha1.EventList)
atomic.AddInt64(got, int64(len(events.Items)))
wg.Add(-len(events.Items))
}))
defer s.Close()
stopCh := make(chan struct{})
defer close(stopCh)
backend := newTestBatchWebhook(t, s.URL, []schema.GroupVersion{auditv1alpha1.SchemeGroupVersion})
// Test the Run codepath. E.g. that the spawned goroutines behave correctly.
backend.Run(stopCh)
backend.ProcessEvents(events...)
select {
case <-done:
// Received all the events.
case <-time.After(2 * time.Minute):
t.Errorf("expected %d events got %d", want, atomic.LoadInt64(got))
}
}
func TestBatchConcurrentRequestsV1Alpha1(t *testing.T) {
events := make([]*auditinternal.Event, defaultBatchBufferSize) // Don't drop events
for i := range events {
events[i] = &auditinternal.Event{}
}
wg := new(sync.WaitGroup)
wg.Add(len(events))
s := httptest.NewServer(newWebhookHandler(t, &auditv1alpha1.EventList{}, func(events runtime.Object) {
wg.Add(-len(events.(*auditv1alpha1.EventList).Items))
// Since the webhook makes concurrent requests, blocking on the webhook response
// shouldn't block the webhook from sending more events.
//
// Wait for all responses to be received before sending the response.
wg.Wait()
}))
defer s.Close()
stopCh := make(chan struct{})
defer close(stopCh)
backend := newTestBatchWebhook(t, s.URL, []schema.GroupVersion{auditv1alpha1.SchemeGroupVersion})
backend.Run(stopCh)
backend.ProcessEvents(events...)
// Wait for the webhook to receive all events.
wg.Wait()
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment