Merge pull request #69941 from miguelbernadi/fix-golint-issues-68026

Fix golint issues in plugin/pkg/admission
k3s-v1.15.3
Kubernetes Prow Robot 2019-05-30 08:38:26 -07:00 committed by GitHub
commit b8eecd671d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 297 additions and 226 deletions

View File

@ -320,20 +320,10 @@ pkg/volume/testing
pkg/volume/util/fs
pkg/volume/util/volumepathhandler
pkg/volume/vsphere_volume
plugin/pkg/admission/antiaffinity
plugin/pkg/admission/eventratelimit/apis/eventratelimit/v1alpha1
plugin/pkg/admission/limitranger
plugin/pkg/admission/noderestriction
plugin/pkg/admission/podnodeselector
plugin/pkg/admission/podpreset
plugin/pkg/admission/podtolerationrestriction
plugin/pkg/admission/podtolerationrestriction/apis/podtolerationrestriction/v1alpha1
plugin/pkg/admission/resourcequota
plugin/pkg/admission/resourcequota/apis/resourcequota
plugin/pkg/admission/resourcequota/apis/resourcequota/v1alpha1
plugin/pkg/admission/resourcequota/apis/resourcequota/v1beta1
plugin/pkg/admission/security/podsecuritypolicy
plugin/pkg/admission/serviceaccount
plugin/pkg/auth/authorizer/node
plugin/pkg/auth/authorizer/rbac
plugin/pkg/auth/authorizer/rbac/bootstrappolicy

View File

@ -26,6 +26,7 @@ import (
api "k8s.io/kubernetes/pkg/apis/core"
)
// PluginName is a string with the name of the plugin
const PluginName = "LimitPodHardAntiAffinityTopology"
// Register registers a plugin

View File

@ -14,15 +14,16 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
// LimitPodHardAntiAffinityTopology admission controller rejects any pod
// that specifies "hard" (RequiredDuringScheduling) anti-affinity
// with a TopologyKey other than v1.LabelHostname.
// Because anti-affinity is symmetric, without this admission controller,
// a user could maliciously or accidentally specify that their pod (once it has scheduled)
// should block other pods from scheduling into the same zone or some other large topology,
// essentially DoSing the cluster.
// In the future we will address this problem more fully by using quota and priority,
// but for now this admission controller provides a simple protection,
// on the assumption that the only legitimate use of hard pod anti-affinity
// is to exclude other pods from the same node.
// Package antiaffinity provides the LimitPodHardAntiAffinityTopology
// admission controller. It rejects any pod that specifies "hard"
// (RequiredDuringScheduling) anti-affinity with a TopologyKey other
// than v1.LabelHostname. Because anti-affinity is symmetric, without
// this admission controller, a user could maliciously or accidentally
// specify that their pod (once it has scheduled) should block other
// pods from scheduling into the same zone or some other large
// topology, essentially DoSing the cluster. In the future we will
// address this problem more fully by using quota and priority, but
// for now this admission controller provides a simple protection, on
// the assumption that the only legitimate use of hard pod
// anti-affinity is to exclude other pods from the same node.
package antiaffinity // import "k8s.io/kubernetes/plugin/pkg/admission/antiaffinity"

View File

@ -24,7 +24,7 @@ import (
var (
// SchemeBuilder is the scheme builder with scheme init functions to run for this API package
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
// AddToScheme is a global function that registers this API group & version to a scheme
// AddToScheme is used to register the types to API encoding/decoding machinery
AddToScheme = SchemeBuilder.AddToScheme
)

View File

@ -30,9 +30,12 @@ var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha
var (
// TODO: move SchemeBuilder with zz_generated.deepcopy.go to k8s.io/api.
// localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes.
// SchemeBuilder is a pointer used to call AddToScheme
SchemeBuilder runtime.SchemeBuilder
localSchemeBuilder = &SchemeBuilder
AddToScheme = localSchemeBuilder.AddToScheme
// AddToScheme is used to register the types to API encoding/decoding machinery
AddToScheme = localSchemeBuilder.AddToScheme
)
func init() {

View File

@ -78,16 +78,19 @@ type liveLookupEntry struct {
items []*corev1.LimitRange
}
// SetExternalKubeInformerFactory registers an informer factory into the LimitRanger
func (l *LimitRanger) SetExternalKubeInformerFactory(f informers.SharedInformerFactory) {
limitRangeInformer := f.Core().V1().LimitRanges()
l.SetReadyFunc(limitRangeInformer.Informer().HasSynced)
l.lister = limitRangeInformer.Lister()
}
func (a *LimitRanger) SetExternalKubeClientSet(client kubernetes.Interface) {
a.client = client
// SetExternalKubeClientSet registers the client into LimitRanger
func (l *LimitRanger) SetExternalKubeClientSet(client kubernetes.Interface) {
l.client = client
}
// ValidateInitialization verifies the LimitRanger object has been properly initialized
func (l *LimitRanger) ValidateInitialization() error {
if l.lister == nil {
return fmt.Errorf("missing limitRange lister")
@ -146,6 +149,8 @@ func (l *LimitRanger) runLimitFunc(a admission.Attributes, limitFn func(limitRan
return nil
}
// GetLimitRanges returns a LimitRange object with the items held in
// the indexer if available, or do alive lookup of the value.
func (l *LimitRanger) GetLimitRanges(a admission.Attributes) ([]*corev1.LimitRange, error) {
items, err := l.lister.LimitRanges(a.GetNamespace()).List(labels.Everything())
if err != nil {
@ -306,13 +311,13 @@ func minConstraint(limitType string, resourceName string, enforced resource.Quan
observedReqValue, observedLimValue, enforcedValue := requestLimitEnforcedValues(req, lim, enforced)
if !reqExists {
return fmt.Errorf("minimum %s usage per %s is %s. No request is specified.", resourceName, limitType, enforced.String())
return fmt.Errorf("minimum %s usage per %s is %s. No request is specified", resourceName, limitType, enforced.String())
}
if observedReqValue < enforcedValue {
return fmt.Errorf("minimum %s usage per %s is %s, but request is %s.", resourceName, limitType, enforced.String(), req.String())
return fmt.Errorf("minimum %s usage per %s is %s, but request is %s", resourceName, limitType, enforced.String(), req.String())
}
if limExists && (observedLimValue < enforcedValue) {
return fmt.Errorf("minimum %s usage per %s is %s, but limit is %s.", resourceName, limitType, enforced.String(), lim.String())
return fmt.Errorf("minimum %s usage per %s is %s, but limit is %s", resourceName, limitType, enforced.String(), lim.String())
}
return nil
}
@ -324,10 +329,10 @@ func maxRequestConstraint(limitType string, resourceName string, enforced resour
observedReqValue, _, enforcedValue := requestLimitEnforcedValues(req, resource.Quantity{}, enforced)
if !reqExists {
return fmt.Errorf("maximum %s usage per %s is %s. No request is specified.", resourceName, limitType, enforced.String())
return fmt.Errorf("maximum %s usage per %s is %s. No request is specified", resourceName, limitType, enforced.String())
}
if observedReqValue > enforcedValue {
return fmt.Errorf("maximum %s usage per %s is %s, but request is %s.", resourceName, limitType, enforced.String(), req.String())
return fmt.Errorf("maximum %s usage per %s is %s, but request is %s", resourceName, limitType, enforced.String(), req.String())
}
return nil
}
@ -339,13 +344,13 @@ func maxConstraint(limitType string, resourceName string, enforced resource.Quan
observedReqValue, observedLimValue, enforcedValue := requestLimitEnforcedValues(req, lim, enforced)
if !limExists {
return fmt.Errorf("maximum %s usage per %s is %s. No limit is specified.", resourceName, limitType, enforced.String())
return fmt.Errorf("maximum %s usage per %s is %s. No limit is specified", resourceName, limitType, enforced.String())
}
if observedLimValue > enforcedValue {
return fmt.Errorf("maximum %s usage per %s is %s, but limit is %s.", resourceName, limitType, enforced.String(), lim.String())
return fmt.Errorf("maximum %s usage per %s is %s, but limit is %s", resourceName, limitType, enforced.String(), lim.String())
}
if reqExists && (observedReqValue > enforcedValue) {
return fmt.Errorf("maximum %s usage per %s is %s, but request is %s.", resourceName, limitType, enforced.String(), req.String())
return fmt.Errorf("maximum %s usage per %s is %s, but request is %s", resourceName, limitType, enforced.String(), req.String())
}
return nil
}
@ -357,10 +362,10 @@ func limitRequestRatioConstraint(limitType string, resourceName string, enforced
observedReqValue, observedLimValue, _ := requestLimitEnforcedValues(req, lim, enforced)
if !reqExists || (observedReqValue == int64(0)) {
return fmt.Errorf("%s max limit to request ratio per %s is %s, but no request is specified or request is 0.", resourceName, limitType, enforced.String())
return fmt.Errorf("%s max limit to request ratio per %s is %s, but no request is specified or request is 0", resourceName, limitType, enforced.String())
}
if !limExists || (observedLimValue == int64(0)) {
return fmt.Errorf("%s max limit to request ratio per %s is %s, but no limit is specified or limit is 0.", resourceName, limitType, enforced.String())
return fmt.Errorf("%s max limit to request ratio per %s is %s, but no limit is specified or limit is 0", resourceName, limitType, enforced.String())
}
observedRatio := float64(observedLimValue) / float64(observedReqValue)
@ -372,7 +377,7 @@ func limitRequestRatioConstraint(limitType string, resourceName string, enforced
}
if observedRatio > maxLimitRequestRatio {
return fmt.Errorf("%s max limit to request ratio per %s is %s, but provided ratio is %f.", resourceName, limitType, enforced.String(), displayObservedRatio)
return fmt.Errorf("%s max limit to request ratio per %s is %s, but provided ratio is %f", resourceName, limitType, enforced.String(), displayObservedRatio)
}
return nil
@ -423,9 +428,10 @@ type DefaultLimitRangerActions struct{}
// ensure DefaultLimitRangerActions implements the LimitRangerActions interface.
var _ LimitRangerActions = &DefaultLimitRangerActions{}
// Limit enforces resource requirements of incoming resources against enumerated constraints
// on the LimitRange. It may modify the incoming object to apply default resource requirements
// if not specified, and enumerated on the LimitRange
// MutateLimit enforces resource requirements of incoming resources
// against enumerated constraints on the LimitRange. It may modify
// the incoming object to apply default resource requirements if not
// specified, and enumerated on the LimitRange
func (d *DefaultLimitRangerActions) MutateLimit(limitRange *corev1.LimitRange, resourceName string, obj runtime.Object) error {
switch resourceName {
case "pods":
@ -434,9 +440,9 @@ func (d *DefaultLimitRangerActions) MutateLimit(limitRange *corev1.LimitRange, r
return nil
}
// Limit enforces resource requirements of incoming resources against enumerated constraints
// on the LimitRange. It may modify the incoming object to apply default resource requirements
// if not specified, and enumerated on the LimitRange
// ValidateLimit verifies the resource requirements of incoming
// resources against enumerated constraints on the LimitRange are
// valid
func (d *DefaultLimitRangerActions) ValidateLimit(limitRange *corev1.LimitRange, resourceName string, obj runtime.Object) error {
switch resourceName {
case "pods":

View File

@ -656,42 +656,42 @@ func TestPodLimitFuncApplyDefault(t *testing.T) {
for i := range testPod.Spec.Containers {
container := testPod.Spec.Containers[i]
limitMemory := container.Resources.Limits.Memory().String()
limitCpu := container.Resources.Limits.Cpu().String()
limitCPU := container.Resources.Limits.Cpu().String()
requestMemory := container.Resources.Requests.Memory().String()
requestCpu := container.Resources.Requests.Cpu().String()
requestCPU := container.Resources.Requests.Cpu().String()
if limitMemory != "10Mi" {
t.Errorf("Unexpected limit memory value %s", limitMemory)
}
if limitCpu != "75m" {
t.Errorf("Unexpected limit cpu value %s", limitCpu)
if limitCPU != "75m" {
t.Errorf("Unexpected limit cpu value %s", limitCPU)
}
if requestMemory != "5Mi" {
t.Errorf("Unexpected request memory value %s", requestMemory)
}
if requestCpu != "50m" {
t.Errorf("Unexpected request cpu value %s", requestCpu)
if requestCPU != "50m" {
t.Errorf("Unexpected request cpu value %s", requestCPU)
}
}
for i := range testPod.Spec.InitContainers {
container := testPod.Spec.InitContainers[i]
limitMemory := container.Resources.Limits.Memory().String()
limitCpu := container.Resources.Limits.Cpu().String()
limitCPU := container.Resources.Limits.Cpu().String()
requestMemory := container.Resources.Requests.Memory().String()
requestCpu := container.Resources.Requests.Cpu().String()
requestCPU := container.Resources.Requests.Cpu().String()
if limitMemory != "10Mi" {
t.Errorf("Unexpected limit memory value %s", limitMemory)
}
if limitCpu != "75m" {
t.Errorf("Unexpected limit cpu value %s", limitCpu)
if limitCPU != "75m" {
t.Errorf("Unexpected limit cpu value %s", limitCPU)
}
if requestMemory != "5Mi" {
t.Errorf("Unexpected request memory value %s", requestMemory)
}
if requestCpu != "50m" {
t.Errorf("Unexpected request cpu value %s", requestCpu)
if requestCPU != "50m" {
t.Errorf("Unexpected request cpu value %s", requestCPU)
}
}
}

View File

@ -22,6 +22,7 @@ import (
"k8s.io/apiserver/pkg/admission"
)
// LimitRangerActions is an interface defining actions to be carried over ranges to identify and manipulate their limits
type LimitRangerActions interface {
// MutateLimit is a pluggable function to set limits on the object.
MutateLimit(limitRange *corev1.LimitRange, kind string, obj runtime.Object) error

View File

@ -45,9 +45,8 @@ import (
kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis"
)
const (
PluginName = "NodeRestriction"
)
// PluginName is a string with the name of the plugin
const PluginName = "NodeRestriction"
// Register registers a plugin
func Register(plugins *admission.Plugins) {
@ -58,16 +57,16 @@ func Register(plugins *admission.Plugins) {
// NewPlugin creates a new NodeRestriction admission plugin.
// This plugin identifies requests from nodes
func NewPlugin(nodeIdentifier nodeidentifier.NodeIdentifier) *nodePlugin {
return &nodePlugin{
func NewPlugin(nodeIdentifier nodeidentifier.NodeIdentifier) *Plugin {
return &Plugin{
Handler: admission.NewHandler(admission.Create, admission.Update, admission.Delete),
nodeIdentifier: nodeIdentifier,
features: utilfeature.DefaultFeatureGate,
}
}
// nodePlugin holds state for and implements the admission plugin.
type nodePlugin struct {
// Plugin holds state for and implements the admission plugin.
type Plugin struct {
*admission.Handler
nodeIdentifier nodeidentifier.NodeIdentifier
podsGetter corev1lister.PodLister
@ -76,15 +75,17 @@ type nodePlugin struct {
}
var (
_ = admission.Interface(&nodePlugin{})
_ = apiserveradmission.WantsExternalKubeInformerFactory(&nodePlugin{})
_ = admission.Interface(&Plugin{})
_ = apiserveradmission.WantsExternalKubeInformerFactory(&Plugin{})
)
func (p *nodePlugin) SetExternalKubeInformerFactory(f informers.SharedInformerFactory) {
// SetExternalKubeInformerFactory registers an informer factory into Plugin
func (p *Plugin) SetExternalKubeInformerFactory(f informers.SharedInformerFactory) {
p.podsGetter = f.Core().V1().Pods().Lister()
}
func (p *nodePlugin) ValidateInitialization() error {
// ValidateInitialization validates the Plugin was initialized properly
func (p *Plugin) ValidateInitialization() error {
if p.nodeIdentifier == nil {
return fmt.Errorf("%s requires a node identifier", PluginName)
}
@ -103,8 +104,9 @@ var (
csiNodeResource = storage.Resource("csinodes")
)
func (c *nodePlugin) Admit(a admission.Attributes, o admission.ObjectInterfaces) error {
nodeName, isNode := c.nodeIdentifier.NodeIdentity(a.GetUserInfo())
// Admit checks the admission policy and triggers corresponding actions
func (p *Plugin) Admit(a admission.Attributes, o admission.ObjectInterfaces) error {
nodeName, isNode := p.nodeIdentifier.NodeIdentity(a.GetUserInfo())
// Our job is just to restrict nodes
if !isNode {
@ -120,41 +122,41 @@ func (c *nodePlugin) Admit(a admission.Attributes, o admission.ObjectInterfaces)
case podResource:
switch a.GetSubresource() {
case "":
return c.admitPod(nodeName, a)
return p.admitPod(nodeName, a)
case "status":
return c.admitPodStatus(nodeName, a)
return p.admitPodStatus(nodeName, a)
case "eviction":
return c.admitPodEviction(nodeName, a)
return p.admitPodEviction(nodeName, a)
default:
return admission.NewForbidden(a, fmt.Errorf("unexpected pod subresource %q, only 'status' and 'eviction' are allowed", a.GetSubresource()))
}
case nodeResource:
return c.admitNode(nodeName, a)
return p.admitNode(nodeName, a)
case pvcResource:
switch a.GetSubresource() {
case "status":
return c.admitPVCStatus(nodeName, a)
return p.admitPVCStatus(nodeName, a)
default:
return admission.NewForbidden(a, fmt.Errorf("may only update PVC status"))
}
case svcacctResource:
if c.features.Enabled(features.TokenRequest) {
return c.admitServiceAccount(nodeName, a)
if p.features.Enabled(features.TokenRequest) {
return p.admitServiceAccount(nodeName, a)
}
return nil
case leaseResource:
if c.features.Enabled(features.NodeLease) {
return c.admitLease(nodeName, a)
if p.features.Enabled(features.NodeLease) {
return p.admitLease(nodeName, a)
}
return admission.NewForbidden(a, fmt.Errorf("disabled by feature gate %s", features.NodeLease))
case csiNodeResource:
if c.features.Enabled(features.KubeletPluginsWatcher) && c.features.Enabled(features.CSINodeInfo) {
return c.admitCSINode(nodeName, a)
if p.features.Enabled(features.KubeletPluginsWatcher) && p.features.Enabled(features.CSINodeInfo) {
return p.admitCSINode(nodeName, a)
}
return admission.NewForbidden(a, fmt.Errorf("disabled by feature gates %s and %s", features.KubeletPluginsWatcher, features.CSINodeInfo))
@ -163,7 +165,9 @@ func (c *nodePlugin) Admit(a admission.Attributes, o admission.ObjectInterfaces)
}
}
func (c *nodePlugin) admitPod(nodeName string, a admission.Attributes) error {
// admitPod allows creating or deleting a pod if it is assigned to the
// current node and fulfills related criteria.
func (p *Plugin) admitPod(nodeName string, a admission.Attributes) error {
switch a.GetOperation() {
case admission.Create:
// require a pod object
@ -206,7 +210,7 @@ func (c *nodePlugin) admitPod(nodeName string, a admission.Attributes) error {
case admission.Delete:
// get the existing pod
existingPod, err := c.podsGetter.Pods(a.GetNamespace()).Get(a.GetName())
existingPod, err := p.podsGetter.Pods(a.GetNamespace()).Get(a.GetName())
if errors.IsNotFound(err) {
return err
}
@ -224,7 +228,9 @@ func (c *nodePlugin) admitPod(nodeName string, a admission.Attributes) error {
}
}
func (c *nodePlugin) admitPodStatus(nodeName string, a admission.Attributes) error {
// admitPodStatus allows to update the status of a pod if it is
// assigned to the current node.
func (p *Plugin) admitPodStatus(nodeName string, a admission.Attributes) error {
switch a.GetOperation() {
case admission.Update:
// require an existing pod
@ -243,7 +249,8 @@ func (c *nodePlugin) admitPodStatus(nodeName string, a admission.Attributes) err
}
}
func (c *nodePlugin) admitPodEviction(nodeName string, a admission.Attributes) error {
// admitPodEviction allows to evict a pod if it is assigned to the current node.
func (p *Plugin) admitPodEviction(nodeName string, a admission.Attributes) error {
switch a.GetOperation() {
case admission.Create:
// require eviction to an existing pod object
@ -260,7 +267,7 @@ func (c *nodePlugin) admitPodEviction(nodeName string, a admission.Attributes) e
podName = eviction.Name
}
// get the existing pod
existingPod, err := c.podsGetter.Pods(a.GetNamespace()).Get(podName)
existingPod, err := p.podsGetter.Pods(a.GetNamespace()).Get(podName)
if errors.IsNotFound(err) {
return err
}
@ -278,10 +285,10 @@ func (c *nodePlugin) admitPodEviction(nodeName string, a admission.Attributes) e
}
}
func (c *nodePlugin) admitPVCStatus(nodeName string, a admission.Attributes) error {
func (p *Plugin) admitPVCStatus(nodeName string, a admission.Attributes) error {
switch a.GetOperation() {
case admission.Update:
if !c.features.Enabled(features.ExpandPersistentVolumes) {
if !p.features.Enabled(features.ExpandPersistentVolumes) {
return admission.NewForbidden(a, fmt.Errorf("node %q is not allowed to update persistentvolumeclaim metadata", nodeName))
}
@ -328,7 +335,7 @@ func (c *nodePlugin) admitPVCStatus(nodeName string, a admission.Attributes) err
}
}
func (c *nodePlugin) admitNode(nodeName string, a admission.Attributes) error {
func (p *Plugin) admitNode(nodeName string, a admission.Attributes) error {
requestedName := a.GetName()
if a.GetOperation() == admission.Create {
node, ok := a.GetObject().(*api.Node)
@ -345,12 +352,12 @@ func (c *nodePlugin) admitNode(nodeName string, a admission.Attributes) error {
// Don't allow a node to register with labels outside the allowed set.
// This would allow a node to add or modify its labels in a way that would let it steer privileged workloads to itself.
modifiedLabels := getModifiedLabels(node.Labels, nil)
if forbiddenLabels := c.getForbiddenCreateLabels(modifiedLabels); len(forbiddenLabels) > 0 {
if forbiddenLabels := p.getForbiddenCreateLabels(modifiedLabels); len(forbiddenLabels) > 0 {
return admission.NewForbidden(a, fmt.Errorf("node %q is not allowed to set the following labels: %s", nodeName, strings.Join(forbiddenLabels.List(), ", ")))
}
// check and warn if nodes set labels on create that would have been forbidden on update
// TODO(liggitt): in 1.17, expand getForbiddenCreateLabels to match getForbiddenUpdateLabels and drop this
if forbiddenUpdateLabels := c.getForbiddenUpdateLabels(modifiedLabels); len(forbiddenUpdateLabels) > 0 {
if forbiddenUpdateLabels := p.getForbiddenUpdateLabels(modifiedLabels); len(forbiddenUpdateLabels) > 0 {
klog.Warningf("node %q added disallowed labels on node creation: %s", nodeName, strings.Join(forbiddenUpdateLabels.List(), ", "))
}
@ -389,7 +396,7 @@ func (c *nodePlugin) admitNode(nodeName string, a admission.Attributes) error {
// Don't allow a node to update labels outside the allowed set.
// This would allow a node to add or modify its labels in a way that would let it steer privileged workloads to itself.
modifiedLabels := getModifiedLabels(node.Labels, oldNode.Labels)
if forbiddenUpdateLabels := c.getForbiddenUpdateLabels(modifiedLabels); len(forbiddenUpdateLabels) > 0 {
if forbiddenUpdateLabels := p.getForbiddenUpdateLabels(modifiedLabels); len(forbiddenUpdateLabels) > 0 {
return admission.NewForbidden(a, fmt.Errorf("is not allowed to modify labels: %s", strings.Join(forbiddenUpdateLabels.List(), ", ")))
}
}
@ -433,7 +440,7 @@ func getLabelNamespace(key string) string {
// getForbiddenCreateLabels returns the set of labels that may not be set by the node.
// TODO(liggitt): in 1.17, expand to match getForbiddenUpdateLabels()
func (c *nodePlugin) getForbiddenCreateLabels(modifiedLabels sets.String) sets.String {
func (p *Plugin) getForbiddenCreateLabels(modifiedLabels sets.String) sets.String {
if len(modifiedLabels) == 0 {
return nil
}
@ -450,7 +457,7 @@ func (c *nodePlugin) getForbiddenCreateLabels(modifiedLabels sets.String) sets.S
}
// getForbiddenLabels returns the set of labels that may not be set by the node on update.
func (c *nodePlugin) getForbiddenUpdateLabels(modifiedLabels sets.String) sets.String {
func (p *Plugin) getForbiddenUpdateLabels(modifiedLabels sets.String) sets.String {
if len(modifiedLabels) == 0 {
return nil
}
@ -471,7 +478,7 @@ func (c *nodePlugin) getForbiddenUpdateLabels(modifiedLabels sets.String) sets.S
return forbiddenLabels
}
func (c *nodePlugin) admitServiceAccount(nodeName string, a admission.Attributes) error {
func (p *Plugin) admitServiceAccount(nodeName string, a admission.Attributes) error {
if a.GetOperation() != admission.Create {
return nil
}
@ -495,7 +502,7 @@ func (c *nodePlugin) admitServiceAccount(nodeName string, a admission.Attributes
if ref.UID == "" {
return admission.NewForbidden(a, fmt.Errorf("node requested token with a pod binding without a uid"))
}
pod, err := c.podsGetter.Pods(a.GetNamespace()).Get(ref.Name)
pod, err := p.podsGetter.Pods(a.GetNamespace()).Get(ref.Name)
if errors.IsNotFound(err) {
return err
}
@ -512,7 +519,7 @@ func (c *nodePlugin) admitServiceAccount(nodeName string, a admission.Attributes
return nil
}
func (r *nodePlugin) admitLease(nodeName string, a admission.Attributes) error {
func (p *Plugin) admitLease(nodeName string, a admission.Attributes) error {
// the request must be against the system namespace reserved for node leases
if a.GetNamespace() != api.NamespaceNodeLease {
return admission.NewForbidden(a, fmt.Errorf("can only access leases in the %q system namespace", api.NamespaceNodeLease))
@ -537,7 +544,7 @@ func (r *nodePlugin) admitLease(nodeName string, a admission.Attributes) error {
return nil
}
func (c *nodePlugin) admitCSINode(nodeName string, a admission.Attributes) error {
func (p *Plugin) admitCSINode(nodeName string, a admission.Attributes) error {
// the request must come from a node with the same name as the CSINode object
if a.GetOperation() == admission.Create {
// a.GetName() won't return the name on create, so we drill down to the proposed object

View File

@ -36,10 +36,12 @@ import (
api "k8s.io/kubernetes/pkg/apis/core"
)
// The annotation key scheduler.alpha.kubernetes.io/node-selector is for assigning
// node selectors labels to namespaces
// NamespaceNodeSelectors is for assigning node selectors labels to
// namespaces. Default value is the annotation key
// scheduler.alpha.kubernetes.io/node-selector
var NamespaceNodeSelectors = []string{"scheduler.alpha.kubernetes.io/node-selector"}
// PluginName is a string with the name of the plugin
const PluginName = "PodNodeSelector"
// Register registers a plugin
@ -52,8 +54,8 @@ func Register(plugins *admission.Plugins) {
})
}
// podNodeSelector is an implementation of admission.Interface.
type podNodeSelector struct {
// Plugin is an implementation of admission.Interface.
type Plugin struct {
*admission.Handler
client kubernetes.Interface
namespaceLister corev1listers.NamespaceLister
@ -61,8 +63,8 @@ type podNodeSelector struct {
clusterNodeSelectors map[string]string
}
var _ = genericadmissioninitializer.WantsExternalKubeClientSet(&podNodeSelector{})
var _ = genericadmissioninitializer.WantsExternalKubeInformerFactory(&podNodeSelector{})
var _ = genericadmissioninitializer.WantsExternalKubeClientSet(&Plugin{})
var _ = genericadmissioninitializer.WantsExternalKubeInformerFactory(&Plugin{})
type pluginConfig struct {
PodNodeSelectorPluginConfig map[string]string
@ -94,7 +96,7 @@ func readConfig(config io.Reader) *pluginConfig {
}
// Admit enforces that pod and its namespace node label selectors matches at least a node in the cluster.
func (p *podNodeSelector) Admit(a admission.Attributes, o admission.ObjectInterfaces) error {
func (p *Plugin) Admit(a admission.Attributes, o admission.ObjectInterfaces) error {
if shouldIgnore(a) {
return nil
}
@ -121,7 +123,7 @@ func (p *podNodeSelector) Admit(a admission.Attributes, o admission.ObjectInterf
}
// Validate ensures that the pod node selector is allowed
func (p *podNodeSelector) Validate(a admission.Attributes, o admission.ObjectInterfaces) error {
func (p *Plugin) Validate(a admission.Attributes, o admission.ObjectInterfaces) error {
if shouldIgnore(a) {
return nil
}
@ -152,7 +154,7 @@ func (p *podNodeSelector) Validate(a admission.Attributes, o admission.ObjectInt
return nil
}
func (p *podNodeSelector) getNamespaceNodeSelectorMap(namespaceName string) (labels.Set, error) {
func (p *Plugin) getNamespaceNodeSelectorMap(namespaceName string) (labels.Set, error) {
namespace, err := p.namespaceLister.Get(namespaceName)
if errors.IsNotFound(err) {
namespace, err = p.defaultGetNamespace(namespaceName)
@ -188,24 +190,28 @@ func shouldIgnore(a admission.Attributes) bool {
return false
}
func NewPodNodeSelector(clusterNodeSelectors map[string]string) *podNodeSelector {
return &podNodeSelector{
// NewPodNodeSelector initializes a podNodeSelector
func NewPodNodeSelector(clusterNodeSelectors map[string]string) *Plugin {
return &Plugin{
Handler: admission.NewHandler(admission.Create),
clusterNodeSelectors: clusterNodeSelectors,
}
}
func (a *podNodeSelector) SetExternalKubeClientSet(client kubernetes.Interface) {
a.client = client
// SetExternalKubeClientSet sets the plugin's client
func (p *Plugin) SetExternalKubeClientSet(client kubernetes.Interface) {
p.client = client
}
func (p *podNodeSelector) SetExternalKubeInformerFactory(f informers.SharedInformerFactory) {
// SetExternalKubeInformerFactory configures the plugin's informer factory
func (p *Plugin) SetExternalKubeInformerFactory(f informers.SharedInformerFactory) {
namespaceInformer := f.Core().V1().Namespaces()
p.namespaceLister = namespaceInformer.Lister()
p.SetReadyFunc(namespaceInformer.Informer().HasSynced)
}
func (p *podNodeSelector) ValidateInitialization() error {
// ValidateInitialization verifies the object has been properly initialized
func (p *Plugin) ValidateInitialization() error {
if p.namespaceLister == nil {
return fmt.Errorf("missing namespaceLister")
}
@ -215,7 +221,7 @@ func (p *podNodeSelector) ValidateInitialization() error {
return nil
}
func (p *podNodeSelector) defaultGetNamespace(name string) (*corev1.Namespace, error) {
func (p *Plugin) defaultGetNamespace(name string) (*corev1.Namespace, error) {
namespace, err := p.client.CoreV1().Namespaces().Get(name, metav1.GetOptions{})
if err != nil {
return nil, fmt.Errorf("namespace %s does not exist", name)
@ -223,7 +229,7 @@ func (p *podNodeSelector) defaultGetNamespace(name string) (*corev1.Namespace, e
return namespace, nil
}
func (p *podNodeSelector) getNodeSelectorMap(namespace *corev1.Namespace) (labels.Set, error) {
func (p *Plugin) getNodeSelectorMap(namespace *corev1.Namespace) (labels.Set, error) {
selector := labels.Set{}
labelsMap := labels.Set{}
var err error

View File

@ -194,7 +194,7 @@ func TestHandles(t *testing.T) {
}
// newHandlerForTest returns the admission controller configured for testing.
func newHandlerForTest(c kubernetes.Interface) (*podNodeSelector, informers.SharedInformerFactory, error) {
func newHandlerForTest(c kubernetes.Interface) (*Plugin, informers.SharedInformerFactory, error) {
f := informers.NewSharedInformerFactory(c, 5*time.Minute)
handler := NewPodNodeSelector(nil)
pluginInitializer := genericadmissioninitializer.New(c, f, nil)

View File

@ -40,7 +40,8 @@ import (
const (
annotationPrefix = "podpreset.admission.kubernetes.io"
PluginName = "PodPreset"
// PluginName is a string with the name of the plugin
PluginName = "PodPreset"
)
// Register registers a plugin
@ -50,47 +51,50 @@ func Register(plugins *admission.Plugins) {
})
}
// podPresetPlugin is an implementation of admission.Interface.
type podPresetPlugin struct {
// Plugin is an implementation of admission.Interface.
type Plugin struct {
*admission.Handler
client kubernetes.Interface
lister settingsv1alpha1listers.PodPresetLister
}
var _ admission.MutationInterface = &podPresetPlugin{}
var _ = genericadmissioninitializer.WantsExternalKubeInformerFactory(&podPresetPlugin{})
var _ = genericadmissioninitializer.WantsExternalKubeClientSet(&podPresetPlugin{})
var _ admission.MutationInterface = &Plugin{}
var _ = genericadmissioninitializer.WantsExternalKubeInformerFactory(&Plugin{})
var _ = genericadmissioninitializer.WantsExternalKubeClientSet(&Plugin{})
// NewPlugin creates a new pod preset admission plugin.
func NewPlugin() *podPresetPlugin {
return &podPresetPlugin{
func NewPlugin() *Plugin {
return &Plugin{
Handler: admission.NewHandler(admission.Create, admission.Update),
}
}
func (plugin *podPresetPlugin) ValidateInitialization() error {
if plugin.client == nil {
// ValidateInitialization validates the Plugin was initialized properly
func (p *Plugin) ValidateInitialization() error {
if p.client == nil {
return fmt.Errorf("%s requires a client", PluginName)
}
if plugin.lister == nil {
if p.lister == nil {
return fmt.Errorf("%s requires a lister", PluginName)
}
return nil
}
func (a *podPresetPlugin) SetExternalKubeClientSet(client kubernetes.Interface) {
a.client = client
// SetExternalKubeClientSet registers the client into Plugin
func (p *Plugin) SetExternalKubeClientSet(client kubernetes.Interface) {
p.client = client
}
func (a *podPresetPlugin) SetExternalKubeInformerFactory(f informers.SharedInformerFactory) {
// SetExternalKubeInformerFactory registers an informer factory into Plugin
func (p *Plugin) SetExternalKubeInformerFactory(f informers.SharedInformerFactory) {
podPresetInformer := f.Settings().V1alpha1().PodPresets()
a.lister = podPresetInformer.Lister()
a.SetReadyFunc(podPresetInformer.Informer().HasSynced)
p.lister = podPresetInformer.Lister()
p.SetReadyFunc(podPresetInformer.Informer().HasSynced)
}
// Admit injects a pod with the specific fields for each pod preset it matches.
func (c *podPresetPlugin) Admit(a admission.Attributes, o admission.ObjectInterfaces) error {
func (p *Plugin) Admit(a admission.Attributes, o admission.ObjectInterfaces) error {
// Ignore all calls to subresources or resources other than pods.
// Ignore all operations other than CREATE.
if len(a.GetSubresource()) != 0 || a.GetResource().GroupResource() != api.Resource("pods") || a.GetOperation() != admission.Create {
@ -114,7 +118,7 @@ func (c *podPresetPlugin) Admit(a admission.Attributes, o admission.ObjectInterf
}
}
list, err := c.lister.PodPresets(a.GetNamespace()).List(labels.Everything())
list, err := p.lister.PodPresets(a.GetNamespace()).List(labels.Everything())
if err != nil {
return fmt.Errorf("listing pod presets failed: %v", err)
}

View File

@ -401,7 +401,7 @@ func NewTestAdmission(lister settingsv1alpha1listers.PodPresetLister, objects ..
// Build a test client that the admission plugin can use to look up the service account missing from its cache
client := fake.NewSimpleClientset(objects...)
return &podPresetPlugin{
return &Plugin{
client: client,
Handler: kadmission.NewHandler(kadmission.Create),
lister: lister,

View File

@ -35,6 +35,7 @@ go_library(
srcs = [
"admission.go",
"config.go",
"doc.go",
],
importpath = "k8s.io/kubernetes/plugin/pkg/admission/podtolerationrestriction",
deps = [

View File

@ -39,6 +39,7 @@ import (
pluginapi "k8s.io/kubernetes/plugin/pkg/admission/podtolerationrestriction/apis/podtolerationrestriction"
)
// PluginName is a string with the name of the plugin
const PluginName = "PodTolerationRestriction"
// Register registers a plugin
@ -58,29 +59,21 @@ const (
NSWLTolerations string = "scheduler.alpha.kubernetes.io/tolerationsWhitelist"
)
var _ admission.MutationInterface = &podTolerationsPlugin{}
var _ admission.ValidationInterface = &podTolerationsPlugin{}
var _ = genericadmissioninitializer.WantsExternalKubeInformerFactory(&podTolerationsPlugin{})
var _ = genericadmissioninitializer.WantsExternalKubeClientSet(&podTolerationsPlugin{})
var _ admission.MutationInterface = &Plugin{}
var _ admission.ValidationInterface = &Plugin{}
var _ = genericadmissioninitializer.WantsExternalKubeInformerFactory(&Plugin{})
var _ = genericadmissioninitializer.WantsExternalKubeClientSet(&Plugin{})
type podTolerationsPlugin struct {
// Plugin contains the client used by the admission controller
type Plugin struct {
*admission.Handler
client kubernetes.Interface
namespaceLister corev1listers.NamespaceLister
pluginConfig *pluginapi.Configuration
}
// This plugin first verifies any conflict between a pod's tolerations and
// its namespace's tolerations, and rejects the pod if there's a conflict.
// If there's no conflict, the pod's tolerations are merged with its namespace's
// toleration. Resulting pod's tolerations are verified against its namespace's
// whitelist of tolerations. If the verification is successful, the pod is admitted
// otherwise rejected. If a namespace does not have associated default or whitelist
// of tolerations, then cluster level default or whitelist of tolerations are used
// instead if specified. Tolerations to a namespace are assigned via
// scheduler.alpha.kubernetes.io/defaultTolerations and scheduler.alpha.kubernetes.io/tolerationsWhitelist
// annotations keys.
func (p *podTolerationsPlugin) Admit(a admission.Attributes, o admission.ObjectInterfaces) error {
// Admit checks the admission policy and triggers corresponding actions
func (p *Plugin) Admit(a admission.Attributes, o admission.ObjectInterfaces) error {
if shouldIgnore(a) {
return nil
}
@ -136,7 +129,9 @@ func (p *podTolerationsPlugin) Admit(a admission.Attributes, o admission.ObjectI
pod.Spec.Tolerations = tolerations.MergeTolerations(finalTolerations, []api.Toleration{})
return p.Validate(a, o)
}
func (p *podTolerationsPlugin) Validate(a admission.Attributes, o admission.ObjectInterfaces) error {
// Validate we can obtain a whitelist of tolerations
func (p *Plugin) Validate(a admission.Attributes, o admission.ObjectInterfaces) error {
if shouldIgnore(a) {
return nil
}
@ -190,25 +185,29 @@ func shouldIgnore(a admission.Attributes) bool {
return false
}
func NewPodTolerationsPlugin(pluginConfig *pluginapi.Configuration) *podTolerationsPlugin {
return &podTolerationsPlugin{
// NewPodTolerationsPlugin initializes a Plugin
func NewPodTolerationsPlugin(pluginConfig *pluginapi.Configuration) *Plugin {
return &Plugin{
Handler: admission.NewHandler(admission.Create, admission.Update),
pluginConfig: pluginConfig,
}
}
func (a *podTolerationsPlugin) SetExternalKubeClientSet(client kubernetes.Interface) {
a.client = client
// SetExternalKubeClientSet sets th client
func (p *Plugin) SetExternalKubeClientSet(client kubernetes.Interface) {
p.client = client
}
func (p *podTolerationsPlugin) SetExternalKubeInformerFactory(f informers.SharedInformerFactory) {
// SetExternalKubeInformerFactory initializes the Informer Factory
func (p *Plugin) SetExternalKubeInformerFactory(f informers.SharedInformerFactory) {
namespaceInformer := f.Core().V1().Namespaces()
p.namespaceLister = namespaceInformer.Lister()
p.SetReadyFunc(namespaceInformer.Informer().HasSynced)
}
func (p *podTolerationsPlugin) ValidateInitialization() error {
// ValidateInitialization checks the object is properly initialized
func (p *Plugin) ValidateInitialization() error {
if p.namespaceLister == nil {
return fmt.Errorf("missing namespaceLister")
}
@ -219,7 +218,7 @@ func (p *podTolerationsPlugin) ValidateInitialization() error {
}
// in exceptional cases, this can result in two live calls, but once the cache catches up, that will stop.
func (p *podTolerationsPlugin) getNamespace(nsName string) (*corev1.Namespace, error) {
func (p *Plugin) getNamespace(nsName string) (*corev1.Namespace, error) {
namespace, err := p.namespaceLister.Get(nsName)
if errors.IsNotFound(err) {
// in case of latency in our caches, make a call direct to storage to verify that it truly exists or not
@ -237,7 +236,7 @@ func (p *podTolerationsPlugin) getNamespace(nsName string) (*corev1.Namespace, e
return namespace, nil
}
func (p *podTolerationsPlugin) getNamespaceDefaultTolerations(nsName string) ([]api.Toleration, error) {
func (p *Plugin) getNamespaceDefaultTolerations(nsName string) ([]api.Toleration, error) {
ns, err := p.getNamespace(nsName)
if err != nil {
return nil, err
@ -245,7 +244,7 @@ func (p *podTolerationsPlugin) getNamespaceDefaultTolerations(nsName string) ([]
return extractNSTolerations(ns, NSDefaultTolerations)
}
func (p *podTolerationsPlugin) getNamespaceTolerationsWhitelist(nsName string) ([]api.Toleration, error) {
func (p *Plugin) getNamespaceTolerationsWhitelist(nsName string) ([]api.Toleration, error) {
ns, err := p.getNamespace(nsName)
if err != nil {
return nil, err

View File

@ -350,7 +350,7 @@ func TestIgnoreUpdatingInitializedPod(t *testing.T) {
}
// newHandlerForTest returns the admission controller configured for testing.
func newHandlerForTest(c kubernetes.Interface) (*podTolerationsPlugin, informers.SharedInformerFactory, error) {
func newHandlerForTest(c kubernetes.Interface) (*Plugin, informers.SharedInformerFactory, error) {
f := informers.NewSharedInformerFactory(c, 5*time.Minute)
pluginConfig, err := loadConfiguration(nil)
// must not fail

View File

@ -30,7 +30,7 @@ var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: runtime.
var (
// SchemeBuilder is the scheme builder with scheme init functions to run for this API package
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
// AddToScheme is a global function that registers this API group & version to a scheme
// AddToScheme is used to register the types to API encoding/decoding machinery
AddToScheme = SchemeBuilder.AddToScheme
)

View File

@ -30,9 +30,12 @@ var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha
var (
// TODO: move SchemeBuilder with zz_generated.deepcopy.go to k8s.io/api.
// localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes.
// SchemeBuilder is a pointer used to call AddToScheme
SchemeBuilder runtime.SchemeBuilder
localSchemeBuilder = &SchemeBuilder
AddToScheme = localSchemeBuilder.AddToScheme
// AddToScheme is used to register the types to API encoding/decoding machinery
AddToScheme = localSchemeBuilder.AddToScheme
)
func init() {

View File

@ -0,0 +1,30 @@
/*
Copyright 2018 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 podtolerationrestriction is a plugin that first verifies
// any conflict between a pod's tolerations and its namespace's
// tolerations, and rejects the pod if there's a conflict. If there's
// no conflict, the pod's tolerations are merged with its namespace's
// toleration. Resulting pod's tolerations are verified against its
// namespace's whitelist of tolerations. If the verification is
// successful, the pod is admitted otherwise rejected. If a namespace
// does not have associated default or whitelist of tolerations, then
// cluster level default or whitelist of tolerations are used instead
// if specified. Tolerations to a namespace are assigned via
// scheduler.alpha.kubernetes.io/defaultTolerations and
// scheduler.alpha.kubernetes.io/tolerationsWhitelist annotations
// keys.
package podtolerationrestriction // import "k8s.io/kubernetes/plugin/pkg/admission/podtolerationrestriction"

View File

@ -33,6 +33,7 @@ import (
"k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/validation"
)
// PluginName is a string with the name of the plugin
const PluginName = "ResourceQuota"
// Register registers a plugin
@ -93,14 +94,17 @@ func NewResourceQuota(config *resourcequotaapi.Configuration, numEvaluators int,
}, nil
}
// SetExternalKubeClientSet registers the client into QuotaAdmission
func (a *QuotaAdmission) SetExternalKubeClientSet(client kubernetes.Interface) {
a.quotaAccessor.client = client
}
// SetExternalKubeInformerFactory registers an informer factory into QuotaAdmission
func (a *QuotaAdmission) SetExternalKubeInformerFactory(f informers.SharedInformerFactory) {
a.quotaAccessor.lister = f.Core().V1().ResourceQuotas().Lister()
}
// SetQuotaConfiguration assigns and initializes configuration and evaluator for QuotaAdmission
func (a *QuotaAdmission) SetQuotaConfiguration(c quota.Configuration) {
a.quotaConfiguration = c
a.evaluator = NewQuotaEvaluator(a.quotaAccessor, a.quotaConfiguration.IgnoredResources(), generic.NewRegistry(a.quotaConfiguration.Evaluators()), nil, a.config, a.numEvaluators, a.stopCh)

View File

@ -22,8 +22,10 @@ import (
)
var (
// SchemeBuilder is a pointer used to call AddToScheme
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
AddToScheme = SchemeBuilder.AddToScheme
// AddToScheme is used to register the types to API encoding/decoding machinery
AddToScheme = SchemeBuilder.AddToScheme
)
// GroupName is the group name use in this package

View File

@ -30,9 +30,12 @@ var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha
var (
// TODO: move SchemeBuilder with zz_generated.deepcopy.go to k8s.io/api.
// localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes.
// SchemeBuilder is a pointer used to call AddToScheme
SchemeBuilder runtime.SchemeBuilder
localSchemeBuilder = &SchemeBuilder
AddToScheme = localSchemeBuilder.AddToScheme
// AddToScheme is used to register the types to API encoding/decoding machinery
AddToScheme = localSchemeBuilder.AddToScheme
)
func init() {

View File

@ -30,9 +30,12 @@ var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1beta1
var (
// TODO: move SchemeBuilder with zz_generated.deepcopy.go to k8s.io/api.
// localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes.
// SchemeBuilder is a pointer used to call AddToScheme
SchemeBuilder runtime.SchemeBuilder
localSchemeBuilder = &SchemeBuilder
AddToScheme = localSchemeBuilder.AddToScheme
// AddToScheme is used to register the types to API encoding/decoding machinery
AddToScheme = localSchemeBuilder.AddToScheme
)
func init() {

View File

@ -14,6 +14,6 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
// resourcequota enforces all incoming requests against any applied quota
// Package resourcequota enforces all incoming requests against any applied quota
// in the namespace context of the request
package resourcequota // import "k8s.io/kubernetes/plugin/pkg/admission/resourcequota"

View File

@ -43,9 +43,8 @@ import (
"k8s.io/kubernetes/pkg/serviceaccount"
)
const (
PluginName = "PodSecurityPolicy"
)
// PluginName is a string with the name of the plugin
const PluginName = "PodSecurityPolicy"
// Register registers a plugin
func Register(plugins *admission.Plugins) {
@ -55,8 +54,8 @@ func Register(plugins *admission.Plugins) {
})
}
// PodSecurityPolicyPlugin holds state for and implements the admission plugin.
type PodSecurityPolicyPlugin struct {
// Plugin holds state for and implements the admission plugin.
type Plugin struct {
*admission.Handler
strategyFactory psp.StrategyFactory
failOnNoPolicies bool
@ -65,40 +64,41 @@ type PodSecurityPolicyPlugin struct {
}
// SetAuthorizer sets the authorizer.
func (plugin *PodSecurityPolicyPlugin) SetAuthorizer(authz authorizer.Authorizer) {
plugin.authz = authz
func (p *Plugin) SetAuthorizer(authz authorizer.Authorizer) {
p.authz = authz
}
// ValidateInitialization ensures an authorizer is set.
func (plugin *PodSecurityPolicyPlugin) ValidateInitialization() error {
if plugin.authz == nil {
func (p *Plugin) ValidateInitialization() error {
if p.authz == nil {
return fmt.Errorf("%s requires an authorizer", PluginName)
}
if plugin.lister == nil {
if p.lister == nil {
return fmt.Errorf("%s requires a lister", PluginName)
}
return nil
}
var _ admission.MutationInterface = &PodSecurityPolicyPlugin{}
var _ admission.ValidationInterface = &PodSecurityPolicyPlugin{}
var _ genericadmissioninit.WantsAuthorizer = &PodSecurityPolicyPlugin{}
var _ genericadmissioninit.WantsExternalKubeInformerFactory = &PodSecurityPolicyPlugin{}
var _ admission.MutationInterface = &Plugin{}
var _ admission.ValidationInterface = &Plugin{}
var _ genericadmissioninit.WantsAuthorizer = &Plugin{}
var _ genericadmissioninit.WantsExternalKubeInformerFactory = &Plugin{}
var auditKeyPrefix = strings.ToLower(PluginName) + "." + policy.GroupName + ".k8s.io"
// newPlugin creates a new PSP admission plugin.
func newPlugin(strategyFactory psp.StrategyFactory, failOnNoPolicies bool) *PodSecurityPolicyPlugin {
return &PodSecurityPolicyPlugin{
func newPlugin(strategyFactory psp.StrategyFactory, failOnNoPolicies bool) *Plugin {
return &Plugin{
Handler: admission.NewHandler(admission.Create, admission.Update),
strategyFactory: strategyFactory,
failOnNoPolicies: failOnNoPolicies,
}
}
func (a *PodSecurityPolicyPlugin) SetExternalKubeInformerFactory(f informers.SharedInformerFactory) {
// SetExternalKubeInformerFactory registers an informer
func (p *Plugin) SetExternalKubeInformerFactory(f informers.SharedInformerFactory) {
podSecurityPolicyInformer := f.Policy().V1beta1().PodSecurityPolicies()
a.lister = podSecurityPolicyInformer.Lister()
a.SetReadyFunc(podSecurityPolicyInformer.Informer().HasSynced)
p.lister = podSecurityPolicyInformer.Lister()
p.SetReadyFunc(podSecurityPolicyInformer.Informer().HasSynced)
}
// Admit determines if the pod should be admitted based on the requested security context
@ -109,7 +109,7 @@ func (a *PodSecurityPolicyPlugin) SetExternalKubeInformerFactory(f informers.Sha
// 3. Try to generate and validate a PSP with providers. If we find one then admit the pod
// with the validated PSP. If we don't find any reject the pod and give all errors from the
// failed attempts.
func (c *PodSecurityPolicyPlugin) Admit(a admission.Attributes, o admission.ObjectInterfaces) error {
func (p *Plugin) Admit(a admission.Attributes, o admission.ObjectInterfaces) error {
if ignore, err := shouldIgnore(a); err != nil {
return err
} else if ignore {
@ -125,7 +125,7 @@ func (c *PodSecurityPolicyPlugin) Admit(a admission.Attributes, o admission.Obje
pod := a.GetObject().(*api.Pod)
// compute the context. Mutation is allowed. ValidatedPSPAnnotation is not taken into account.
allowedPod, pspName, validationErrs, err := c.computeSecurityContext(a, pod, true, "")
allowedPod, pspName, validationErrs, err := p.computeSecurityContext(a, pod, true, "")
if err != nil {
return admission.NewForbidden(a, err)
}
@ -149,7 +149,8 @@ func (c *PodSecurityPolicyPlugin) Admit(a admission.Attributes, o admission.Obje
return admission.NewForbidden(a, fmt.Errorf("unable to validate against any pod security policy: %v", validationErrs))
}
func (c *PodSecurityPolicyPlugin) Validate(a admission.Attributes, o admission.ObjectInterfaces) error {
// Validate verifies attributes against the PodSecurityPolicy
func (p *Plugin) Validate(a admission.Attributes, o admission.ObjectInterfaces) error {
if ignore, err := shouldIgnore(a); err != nil {
return err
} else if ignore {
@ -159,7 +160,7 @@ func (c *PodSecurityPolicyPlugin) Validate(a admission.Attributes, o admission.O
pod := a.GetObject().(*api.Pod)
// compute the context. Mutation is not allowed. ValidatedPSPAnnotation is used as a hint to gain same speed-up.
allowedPod, pspName, validationErrs, err := c.computeSecurityContext(a, pod, false, pod.ObjectMeta.Annotations[psputil.ValidatedPSPAnnotation])
allowedPod, pspName, validationErrs, err := p.computeSecurityContext(a, pod, false, pod.ObjectMeta.Annotations[psputil.ValidatedPSPAnnotation])
if err != nil {
return admission.NewForbidden(a, err)
}
@ -205,7 +206,7 @@ func shouldIgnore(a admission.Attributes) (bool, error) {
// if there is a matching policy with the same security context as given, it will be reused. If there is no
// matching policy the returned pod will be nil and the pspName empty. validatedPSPHint is the validated psp name
// saved in kubernetes.io/psp annotation. This psp is usually the one we are looking for.
func (c *PodSecurityPolicyPlugin) computeSecurityContext(a admission.Attributes, pod *api.Pod, specMutationAllowed bool, validatedPSPHint string) (*api.Pod, string, field.ErrorList, error) {
func (p *Plugin) computeSecurityContext(a admission.Attributes, pod *api.Pod, specMutationAllowed bool, validatedPSPHint string) (*api.Pod, string, field.ErrorList, error) {
// get all constraints that are usable by the user
klog.V(4).Infof("getting pod security policies for pod %s (generate: %s)", pod.Name, pod.GenerateName)
var saInfo user.Info
@ -213,14 +214,14 @@ func (c *PodSecurityPolicyPlugin) computeSecurityContext(a admission.Attributes,
saInfo = serviceaccount.UserInfo(a.GetNamespace(), pod.Spec.ServiceAccountName, "")
}
policies, err := c.lister.List(labels.Everything())
policies, err := p.lister.List(labels.Everything())
if err != nil {
return nil, "", nil, err
}
// if we have no policies and want to succeed then return. Otherwise we'll end up with no
// providers and fail with "unable to validate against any pod security policy" below.
if len(policies) == 0 && !c.failOnNoPolicies {
if len(policies) == 0 && !p.failOnNoPolicies {
return pod, "", nil, nil
}
@ -239,7 +240,7 @@ func (c *PodSecurityPolicyPlugin) computeSecurityContext(a admission.Attributes,
return strings.Compare(policies[i].Name, policies[j].Name) < 0
})
providers, errs := c.createProvidersFromPolicies(policies, pod.Namespace)
providers, errs := p.createProvidersFromPolicies(policies, pod.Namespace)
for _, err := range errs {
klog.V(4).Infof("provider creation error: %v", err)
}
@ -269,7 +270,7 @@ func (c *PodSecurityPolicyPlugin) computeSecurityContext(a admission.Attributes,
continue
}
if !isAuthorizedForPolicy(a.GetUserInfo(), saInfo, a.GetNamespace(), provider.GetPSPName(), c.authz) {
if !isAuthorizedForPolicy(a.GetUserInfo(), saInfo, a.GetNamespace(), provider.GetPSPName(), p.authz) {
continue
}
@ -293,7 +294,7 @@ func (c *PodSecurityPolicyPlugin) computeSecurityContext(a admission.Attributes,
// Pod is rejected. Filter the validation errors to only include errors from authorized PSPs.
aggregate := field.ErrorList{}
for psp, errs := range validationErrs {
if isAuthorizedForPolicy(a.GetUserInfo(), saInfo, a.GetNamespace(), psp, c.authz) {
if isAuthorizedForPolicy(a.GetUserInfo(), saInfo, a.GetNamespace(), psp, p.authz) {
aggregate = append(aggregate, errs...)
}
}
@ -317,7 +318,7 @@ func assignSecurityContext(provider psp.Provider, pod *api.Pod) field.ErrorList
}
// createProvidersFromPolicies creates providers from the constraints supplied.
func (c *PodSecurityPolicyPlugin) createProvidersFromPolicies(psps []*policyv1beta1.PodSecurityPolicy, namespace string) ([]psp.Provider, []error) {
func (p *Plugin) createProvidersFromPolicies(psps []*policyv1beta1.PodSecurityPolicy, namespace string) ([]psp.Provider, []error) {
var (
// collected providers
providers []psp.Provider
@ -326,7 +327,7 @@ func (c *PodSecurityPolicyPlugin) createProvidersFromPolicies(psps []*policyv1be
)
for _, constraint := range psps {
provider, err := psp.NewSimpleProvider(constraint, namespace, c.strategyFactory)
provider, err := psp.NewSimpleProvider(constraint, namespace, p.strategyFactory)
if err != nil {
errs = append(errs, fmt.Errorf("error creating provider for PSP %s: %v", constraint.Name, err))
continue

View File

@ -53,7 +53,7 @@ import (
const defaultContainerName = "test-c"
// NewTestAdmission provides an admission plugin with test implementations of internal structs.
func NewTestAdmission(psps []*policy.PodSecurityPolicy, authz authorizer.Authorizer) *PodSecurityPolicyPlugin {
func NewTestAdmission(psps []*policy.PodSecurityPolicy, authz authorizer.Authorizer) *Plugin {
informerFactory := informers.NewSharedInformerFactory(nil, controller.NoResyncPeriodFunc())
store := informerFactory.Policy().V1beta1().PodSecurityPolicies().Informer().GetStore()
for _, psp := range psps {
@ -63,7 +63,7 @@ func NewTestAdmission(psps []*policy.PodSecurityPolicy, authz authorizer.Authori
if authz == nil {
authz = &TestAuthorizer{}
}
return &PodSecurityPolicyPlugin{
return &Plugin{
Handler: kadmission.NewHandler(kadmission.Create, kadmission.Update),
strategyFactory: kpsp.NewSimpleStrategyFactory(),
authz: authz,
@ -1963,7 +1963,7 @@ func TestCreateProvidersFromConstraints(t *testing.T) {
}
for k, v := range testCases {
admit := &PodSecurityPolicyPlugin{
admit := &Plugin{
Handler: kadmission.NewHandler(kadmission.Create, kadmission.Update),
strategyFactory: kpsp.NewSimpleStrategyFactory(),
}

View File

@ -52,6 +52,7 @@ const (
// The value must be true to have this annotation take effect
EnforceMountableSecretsAnnotation = "kubernetes.io/enforce-mountable-secrets"
// ServiceAccountVolumeName is the prefix name that will be added to volumes that mount ServiceAccount secrets
ServiceAccountVolumeName = "kube-api-access"
// DefaultAPITokenMountPath is the path that ServiceAccountToken secrets are automounted to.
@ -70,9 +71,10 @@ func Register(plugins *admission.Plugins) {
})
}
var _ = admission.Interface(&serviceAccount{})
var _ = admission.Interface(&Plugin{})
type serviceAccount struct {
// Plugin contains the client used by the admission controller
type Plugin struct {
*admission.Handler
// LimitSecretReferences rejects pods that reference secrets their service accounts do not reference
@ -92,10 +94,10 @@ type serviceAccount struct {
featureGate featuregate.FeatureGate
}
var _ admission.MutationInterface = &serviceAccount{}
var _ admission.ValidationInterface = &serviceAccount{}
var _ = genericadmissioninitializer.WantsExternalKubeClientSet(&serviceAccount{})
var _ = genericadmissioninitializer.WantsExternalKubeInformerFactory(&serviceAccount{})
var _ admission.MutationInterface = &Plugin{}
var _ admission.ValidationInterface = &Plugin{}
var _ = genericadmissioninitializer.WantsExternalKubeClientSet(&Plugin{})
var _ = genericadmissioninitializer.WantsExternalKubeInformerFactory(&Plugin{})
// NewServiceAccount returns an admission.Interface implementation which limits admission of Pod CREATE requests based on the pod's ServiceAccount:
// 1. If the pod does not specify a ServiceAccount, it sets the pod's ServiceAccount to "default"
@ -103,8 +105,8 @@ var _ = genericadmissioninitializer.WantsExternalKubeInformerFactory(&serviceAcc
// 3. If LimitSecretReferences is true, it rejects the pod if the pod references Secret objects which the pod's ServiceAccount does not reference
// 4. If the pod does not contain any ImagePullSecrets, the ImagePullSecrets of the service account are added.
// 5. If MountServiceAccountToken is true, it adds a VolumeMount with the pod's ServiceAccount's api token secret to containers
func NewServiceAccount() *serviceAccount {
return &serviceAccount{
func NewServiceAccount() *Plugin {
return &Plugin{
Handler: admission.NewHandler(admission.Create),
// TODO: enable this once we've swept secret usage to account for adding secret references to service accounts
LimitSecretReferences: false,
@ -119,11 +121,13 @@ func NewServiceAccount() *serviceAccount {
}
}
func (s *serviceAccount) SetExternalKubeClientSet(cl kubernetes.Interface) {
// SetExternalKubeClientSet sets the client for the plugin
func (s *Plugin) SetExternalKubeClientSet(cl kubernetes.Interface) {
s.client = cl
}
func (s *serviceAccount) SetExternalKubeInformerFactory(f informers.SharedInformerFactory) {
// SetExternalKubeInformerFactory registers informers with the plugin
func (s *Plugin) SetExternalKubeInformerFactory(f informers.SharedInformerFactory) {
serviceAccountInformer := f.Core().V1().ServiceAccounts()
s.serviceAccountLister = serviceAccountInformer.Lister()
@ -136,7 +140,7 @@ func (s *serviceAccount) SetExternalKubeInformerFactory(f informers.SharedInform
}
// ValidateInitialization ensures an authorizer is set.
func (s *serviceAccount) ValidateInitialization() error {
func (s *Plugin) ValidateInitialization() error {
if s.client == nil {
return fmt.Errorf("missing client")
}
@ -149,7 +153,8 @@ func (s *serviceAccount) ValidateInitialization() error {
return nil
}
func (s *serviceAccount) Admit(a admission.Attributes, o admission.ObjectInterfaces) (err error) {
// Admit verifies if the pod should be admitted
func (s *Plugin) Admit(a admission.Attributes, o admission.ObjectInterfaces) (err error) {
if shouldIgnore(a) {
return nil
}
@ -190,7 +195,8 @@ func (s *serviceAccount) Admit(a admission.Attributes, o admission.ObjectInterfa
return s.Validate(a, o)
}
func (s *serviceAccount) Validate(a admission.Attributes, o admission.ObjectInterfaces) (err error) {
// Validate the data we obtained
func (s *Plugin) Validate(a admission.Attributes, o admission.ObjectInterfaces) (err error) {
if shouldIgnore(a) {
return nil
}
@ -271,7 +277,7 @@ func shouldAutomount(sa *corev1.ServiceAccount, pod *api.Pod) bool {
// enforceMountableSecrets indicates whether mountable secrets should be enforced for a particular service account
// A global setting of true will override any flag set on the individual service account
func (s *serviceAccount) enforceMountableSecrets(serviceAccount *corev1.ServiceAccount) bool {
func (s *Plugin) enforceMountableSecrets(serviceAccount *corev1.ServiceAccount) bool {
if s.LimitSecretReferences {
return true
}
@ -285,7 +291,7 @@ func (s *serviceAccount) enforceMountableSecrets(serviceAccount *corev1.ServiceA
}
// getServiceAccount returns the ServiceAccount for the given namespace and name if it exists
func (s *serviceAccount) getServiceAccount(namespace string, name string) (*corev1.ServiceAccount, error) {
func (s *Plugin) getServiceAccount(namespace string, name string) (*corev1.ServiceAccount, error) {
serviceAccount, err := s.serviceAccountLister.ServiceAccounts(namespace).Get(name)
if err == nil {
return serviceAccount, nil
@ -318,7 +324,7 @@ func (s *serviceAccount) getServiceAccount(namespace string, name string) (*core
}
// getReferencedServiceAccountToken returns the name of the first referenced secret which is a ServiceAccountToken for the service account
func (s *serviceAccount) getReferencedServiceAccountToken(serviceAccount *corev1.ServiceAccount) (string, error) {
func (s *Plugin) getReferencedServiceAccountToken(serviceAccount *corev1.ServiceAccount) (string, error) {
if len(serviceAccount.Secrets) == 0 {
return "", nil
}
@ -343,7 +349,7 @@ func (s *serviceAccount) getReferencedServiceAccountToken(serviceAccount *corev1
}
// getServiceAccountTokens returns all ServiceAccountToken secrets for the given ServiceAccount
func (s *serviceAccount) getServiceAccountTokens(serviceAccount *corev1.ServiceAccount) ([]*corev1.Secret, error) {
func (s *Plugin) getServiceAccountTokens(serviceAccount *corev1.ServiceAccount) ([]*corev1.Secret, error) {
secrets, err := s.secretLister.Secrets(serviceAccount.Namespace).List(labels.Everything())
if err != nil {
return nil, err
@ -363,7 +369,7 @@ func (s *serviceAccount) getServiceAccountTokens(serviceAccount *corev1.ServiceA
return tokens, nil
}
func (s *serviceAccount) limitSecretReferences(serviceAccount *corev1.ServiceAccount, pod *api.Pod) error {
func (s *Plugin) limitSecretReferences(serviceAccount *corev1.ServiceAccount, pod *api.Pod) error {
// Ensure all secrets the pod references are allowed by the service account
mountableSecrets := sets.NewString()
for _, s := range serviceAccount.Secrets {
@ -413,7 +419,7 @@ func (s *serviceAccount) limitSecretReferences(serviceAccount *corev1.ServiceAcc
return nil
}
func (s *serviceAccount) mountServiceAccountToken(serviceAccount *corev1.ServiceAccount, pod *api.Pod) error {
func (s *Plugin) mountServiceAccountToken(serviceAccount *corev1.ServiceAccount, pod *api.Pod) error {
// Find the name of a referenced ServiceAccountToken secret we can mount
serviceAccountToken, err := s.getReferencedServiceAccountToken(serviceAccount)
if err != nil {
@ -502,7 +508,7 @@ func (s *serviceAccount) mountServiceAccountToken(serviceAccount *corev1.Service
return nil
}
func (s *serviceAccount) createVolume(tokenVolumeName, secretName string) api.Volume {
func (s *Plugin) createVolume(tokenVolumeName, secretName string) api.Volume {
if s.featureGate.Enabled(kubefeatures.BoundServiceAccountTokenVolume) {
return api.Volume{
Name: tokenVolumeName,

View File

@ -275,7 +275,7 @@ func TestDeniesInvalidServiceAccount(t *testing.T) {
}
func TestAutomountsAPIToken(t *testing.T) {
testBoundServiceAccountTokenVolumePhases(t, func(t *testing.T, applyFeatures func(*serviceAccount) *serviceAccount) {
testBoundServiceAccountTokenVolumePhases(t, func(t *testing.T, applyFeatures func(*Plugin) *Plugin) {
admit := applyFeatures(NewServiceAccount())
informerFactory := informers.NewSharedInformerFactory(nil, controller.NoResyncPeriodFunc())
@ -385,7 +385,7 @@ func TestAutomountsAPIToken(t *testing.T) {
}
func TestRespectsExistingMount(t *testing.T) {
testBoundServiceAccountTokenVolumePhases(t, func(t *testing.T, applyFeatures func(*serviceAccount) *serviceAccount) {
testBoundServiceAccountTokenVolumePhases(t, func(t *testing.T, applyFeatures func(*Plugin) *Plugin) {
ns := "myns"
tokenName := "token-name"
serviceAccountName := DefaultServiceAccountName
@ -914,7 +914,7 @@ func newSecret(secretType corev1.SecretType, namespace, name, serviceAccountName
}
func TestGetServiceAccountTokens(t *testing.T) {
testBoundServiceAccountTokenVolumePhases(t, func(t *testing.T, applyFeatures func(*serviceAccount) *serviceAccount) {
testBoundServiceAccountTokenVolumePhases(t, func(t *testing.T, applyFeatures func(*Plugin) *Plugin) {
admit := applyFeatures(NewServiceAccount())
indexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{})
admit.secretLister = corev1listers.NewSecretLister(indexer)
@ -1070,16 +1070,16 @@ func testGenerateName(n string) string {
var generatedVolumeName = testGenerateName(ServiceAccountVolumeName + "-")
func testBoundServiceAccountTokenVolumePhases(t *testing.T, f func(*testing.T, func(*serviceAccount) *serviceAccount)) {
func testBoundServiceAccountTokenVolumePhases(t *testing.T, f func(*testing.T, func(*Plugin) *Plugin)) {
t.Run("BoundServiceAccountTokenVolume disabled", func(t *testing.T) {
f(t, func(s *serviceAccount) *serviceAccount {
f(t, func(s *Plugin) *Plugin {
s.featureGate = deprecationDisabledFeature
return s
})
})
t.Run("BoundServiceAccountTokenVolume enabled", func(t *testing.T) {
f(t, func(s *serviceAccount) *serviceAccount {
f(t, func(s *Plugin) *Plugin {
s.featureGate = deprecationEnabledFeature
return s
})

View File

@ -14,6 +14,6 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
// serviceaccount enforces all pods having an associated serviceaccount,
// Package serviceaccount enforces all pods having an associated serviceaccount,
// and all containers mounting the API token for that serviceaccount at a known location
package serviceaccount // import "k8s.io/kubernetes/plugin/pkg/admission/serviceaccount"