vendor files

This commit is contained in:
Serguei Bezverkhi
2018-01-09 13:57:14 -05:00
parent 558bc6c02a
commit 7b24313bd6
16547 changed files with 4527373 additions and 0 deletions

View File

@ -0,0 +1,62 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_test(
name = "go_default_test",
srcs = [
"reconcile_role_test.go",
"reconcile_rolebindings_test.go",
],
importpath = "k8s.io/kubernetes/pkg/registry/rbac/reconciliation",
library = ":go_default_library",
deps = [
"//pkg/apis/core/helper:go_default_library",
"//pkg/apis/rbac:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/diff:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"clusterrole_interfaces.go",
"clusterrolebinding_interfaces.go",
"reconcile_role.go",
"reconcile_rolebindings.go",
"role_interfaces.go",
"rolebinding_interfaces.go",
"zz_generated.deepcopy.go",
],
importpath = "k8s.io/kubernetes/pkg/registry/rbac/reconciliation",
deps = [
"//pkg/apis/core:go_default_library",
"//pkg/apis/rbac:go_default_library",
"//pkg/client/clientset_generated/internalclientset/typed/core/internalversion:go_default_library",
"//pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion:go_default_library",
"//pkg/registry/rbac/validation:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)

View File

@ -0,0 +1,104 @@
/*
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 reconciliation
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/kubernetes/pkg/apis/rbac"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion"
)
// +k8s:deepcopy-gen=true
// +k8s:deepcopy-gen:interfaces=k8s.io/kubernetes/pkg/registry/rbac/reconciliation.RuleOwner
// +k8s:deepcopy-gen:nonpointer-interfaces=true
type ClusterRoleRuleOwner struct {
ClusterRole *rbac.ClusterRole
}
func (o ClusterRoleRuleOwner) GetObject() runtime.Object {
return o.ClusterRole
}
func (o ClusterRoleRuleOwner) GetNamespace() string {
return o.ClusterRole.Namespace
}
func (o ClusterRoleRuleOwner) GetName() string {
return o.ClusterRole.Name
}
func (o ClusterRoleRuleOwner) GetLabels() map[string]string {
return o.ClusterRole.Labels
}
func (o ClusterRoleRuleOwner) SetLabels(in map[string]string) {
o.ClusterRole.Labels = in
}
func (o ClusterRoleRuleOwner) GetAnnotations() map[string]string {
return o.ClusterRole.Annotations
}
func (o ClusterRoleRuleOwner) SetAnnotations(in map[string]string) {
o.ClusterRole.Annotations = in
}
func (o ClusterRoleRuleOwner) GetRules() []rbac.PolicyRule {
return o.ClusterRole.Rules
}
func (o ClusterRoleRuleOwner) SetRules(in []rbac.PolicyRule) {
o.ClusterRole.Rules = in
}
func (o ClusterRoleRuleOwner) GetAggregationRule() *rbac.AggregationRule {
return o.ClusterRole.AggregationRule
}
func (o ClusterRoleRuleOwner) SetAggregationRule(in *rbac.AggregationRule) {
o.ClusterRole.AggregationRule = in
}
type ClusterRoleModifier struct {
Client internalversion.ClusterRoleInterface
}
func (c ClusterRoleModifier) Get(namespace, name string) (RuleOwner, error) {
ret, err := c.Client.Get(name, metav1.GetOptions{})
if err != nil {
return nil, err
}
return ClusterRoleRuleOwner{ClusterRole: ret}, err
}
func (c ClusterRoleModifier) Create(in RuleOwner) (RuleOwner, error) {
ret, err := c.Client.Create(in.(ClusterRoleRuleOwner).ClusterRole)
if err != nil {
return nil, err
}
return ClusterRoleRuleOwner{ClusterRole: ret}, err
}
func (c ClusterRoleModifier) Update(in RuleOwner) (RuleOwner, error) {
ret, err := c.Client.Update(in.(ClusterRoleRuleOwner).ClusterRole)
if err != nil {
return nil, err
}
return ClusterRoleRuleOwner{ClusterRole: ret}, err
}

View File

@ -0,0 +1,109 @@
/*
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 reconciliation
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
"k8s.io/kubernetes/pkg/apis/rbac"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion"
)
// +k8s:deepcopy-gen=true
// +k8s:deepcopy-gen:interfaces=k8s.io/kubernetes/pkg/registry/rbac/reconciliation.RoleBinding
// +k8s:deepcopy-gen:nonpointer-interfaces=true
type ClusterRoleBindingAdapter struct {
ClusterRoleBinding *rbac.ClusterRoleBinding
}
func (o ClusterRoleBindingAdapter) GetObject() runtime.Object {
return o.ClusterRoleBinding
}
func (o ClusterRoleBindingAdapter) GetNamespace() string {
return o.ClusterRoleBinding.Namespace
}
func (o ClusterRoleBindingAdapter) GetName() string {
return o.ClusterRoleBinding.Name
}
func (o ClusterRoleBindingAdapter) GetUID() types.UID {
return o.ClusterRoleBinding.UID
}
func (o ClusterRoleBindingAdapter) GetLabels() map[string]string {
return o.ClusterRoleBinding.Labels
}
func (o ClusterRoleBindingAdapter) SetLabels(in map[string]string) {
o.ClusterRoleBinding.Labels = in
}
func (o ClusterRoleBindingAdapter) GetAnnotations() map[string]string {
return o.ClusterRoleBinding.Annotations
}
func (o ClusterRoleBindingAdapter) SetAnnotations(in map[string]string) {
o.ClusterRoleBinding.Annotations = in
}
func (o ClusterRoleBindingAdapter) GetRoleRef() rbac.RoleRef {
return o.ClusterRoleBinding.RoleRef
}
func (o ClusterRoleBindingAdapter) GetSubjects() []rbac.Subject {
return o.ClusterRoleBinding.Subjects
}
func (o ClusterRoleBindingAdapter) SetSubjects(in []rbac.Subject) {
o.ClusterRoleBinding.Subjects = in
}
type ClusterRoleBindingClientAdapter struct {
Client internalversion.ClusterRoleBindingInterface
}
func (c ClusterRoleBindingClientAdapter) Get(namespace, name string) (RoleBinding, error) {
ret, err := c.Client.Get(name, metav1.GetOptions{})
if err != nil {
return nil, err
}
return ClusterRoleBindingAdapter{ClusterRoleBinding: ret}, err
}
func (c ClusterRoleBindingClientAdapter) Create(in RoleBinding) (RoleBinding, error) {
ret, err := c.Client.Create(in.(ClusterRoleBindingAdapter).ClusterRoleBinding)
if err != nil {
return nil, err
}
return ClusterRoleBindingAdapter{ClusterRoleBinding: ret}, err
}
func (c ClusterRoleBindingClientAdapter) Update(in RoleBinding) (RoleBinding, error) {
ret, err := c.Client.Update(in.(ClusterRoleBindingAdapter).ClusterRoleBinding)
if err != nil {
return nil, err
}
return ClusterRoleBindingAdapter{ClusterRoleBinding: ret}, err
}
func (c ClusterRoleBindingClientAdapter) Delete(namespace, name string, uid types.UID) error {
return c.Client.Delete(name, &metav1.DeleteOptions{Preconditions: &metav1.Preconditions{UID: &uid}})
}

View File

@ -0,0 +1,281 @@
/*
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 reconciliation
import (
"fmt"
"reflect"
"k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/kubernetes/pkg/apis/rbac"
"k8s.io/kubernetes/pkg/registry/rbac/validation"
)
type ReconcileOperation string
var (
ReconcileCreate ReconcileOperation = "create"
ReconcileUpdate ReconcileOperation = "update"
ReconcileRecreate ReconcileOperation = "recreate"
ReconcileNone ReconcileOperation = "none"
)
type RuleOwnerModifier interface {
Get(namespace, name string) (RuleOwner, error)
Create(RuleOwner) (RuleOwner, error)
Update(RuleOwner) (RuleOwner, error)
}
type RuleOwner interface {
GetObject() runtime.Object
GetNamespace() string
GetName() string
GetLabels() map[string]string
SetLabels(map[string]string)
GetAnnotations() map[string]string
SetAnnotations(map[string]string)
GetRules() []rbac.PolicyRule
SetRules([]rbac.PolicyRule)
GetAggregationRule() *rbac.AggregationRule
SetAggregationRule(*rbac.AggregationRule)
DeepCopyRuleOwner() RuleOwner
}
type ReconcileRoleOptions struct {
// Role is the expected role that will be reconciled
Role RuleOwner
// Confirm indicates writes should be performed. When false, results are returned as a dry-run.
Confirm bool
// RemoveExtraPermissions indicates reconciliation should remove extra permissions from an existing role
RemoveExtraPermissions bool
// Client is used to look up existing roles, and create/update the role when Confirm=true
Client RuleOwnerModifier
}
type ReconcileClusterRoleResult struct {
// Role is the reconciled role from the reconciliation operation.
// If the reconcile was performed as a dry-run, or the existing role was protected, the reconciled role is not persisted.
Role RuleOwner
// MissingRules contains expected rules that were missing from the currently persisted role
MissingRules []rbac.PolicyRule
// ExtraRules contains extra permissions the currently persisted role had
ExtraRules []rbac.PolicyRule
// MissingAggregationRuleSelectors contains expected selectors that were missing from the currently persisted role
MissingAggregationRuleSelectors []metav1.LabelSelector
// ExtraAggregationRuleSelectors contains extra selectors the currently persisted role had
ExtraAggregationRuleSelectors []metav1.LabelSelector
// Operation is the API operation required to reconcile.
// If no reconciliation was needed, it is set to ReconcileNone.
// If options.Confirm == false, the reconcile was in dry-run mode, so the operation was not performed.
// If result.Protected == true, the role opted out of reconciliation, so the operation was not performed.
// Otherwise, the operation was performed.
Operation ReconcileOperation
// Protected indicates an existing role prevented reconciliation
Protected bool
}
func (o *ReconcileRoleOptions) Run() (*ReconcileClusterRoleResult, error) {
return o.run(0)
}
func (o *ReconcileRoleOptions) run(attempts int) (*ReconcileClusterRoleResult, error) {
// This keeps us from retrying forever if a role keeps appearing and disappearing as we reconcile.
// Conflict errors on update are handled at a higher level.
if attempts > 2 {
return nil, fmt.Errorf("exceeded maximum attempts")
}
var result *ReconcileClusterRoleResult
existing, err := o.Client.Get(o.Role.GetNamespace(), o.Role.GetName())
switch {
case errors.IsNotFound(err):
aggregationRule := o.Role.GetAggregationRule()
if aggregationRule == nil {
aggregationRule = &rbac.AggregationRule{}
}
result = &ReconcileClusterRoleResult{
Role: o.Role,
MissingRules: o.Role.GetRules(),
MissingAggregationRuleSelectors: aggregationRule.ClusterRoleSelectors,
Operation: ReconcileCreate,
}
case err != nil:
return nil, err
default:
result, err = computeReconciledRole(existing, o.Role, o.RemoveExtraPermissions)
if err != nil {
return nil, err
}
}
// If reconcile-protected, short-circuit
if result.Protected {
return result, nil
}
// If we're in dry-run mode, short-circuit
if !o.Confirm {
return result, nil
}
switch result.Operation {
case ReconcileCreate:
created, err := o.Client.Create(result.Role)
// If created since we started this reconcile, re-run
if errors.IsAlreadyExists(err) {
return o.run(attempts + 1)
}
if err != nil {
return nil, err
}
result.Role = created
case ReconcileUpdate:
updated, err := o.Client.Update(result.Role)
// If deleted since we started this reconcile, re-run
if errors.IsNotFound(err) {
return o.run(attempts + 1)
}
if err != nil {
return nil, err
}
result.Role = updated
case ReconcileNone:
// no-op
default:
return nil, fmt.Errorf("invalid operation: %v", result.Operation)
}
return result, nil
}
// computeReconciledRole returns the role that must be created and/or updated to make the
// existing role's permissions match the expected role's permissions
func computeReconciledRole(existing, expected RuleOwner, removeExtraPermissions bool) (*ReconcileClusterRoleResult, error) {
result := &ReconcileClusterRoleResult{Operation: ReconcileNone}
result.Protected = (existing.GetAnnotations()[rbac.AutoUpdateAnnotationKey] == "false")
// Start with a copy of the existing object
result.Role = existing.DeepCopyRuleOwner()
// Merge expected annotations and labels
result.Role.SetAnnotations(merge(expected.GetAnnotations(), result.Role.GetAnnotations()))
if !reflect.DeepEqual(result.Role.GetAnnotations(), existing.GetAnnotations()) {
result.Operation = ReconcileUpdate
}
result.Role.SetLabels(merge(expected.GetLabels(), result.Role.GetLabels()))
if !reflect.DeepEqual(result.Role.GetLabels(), existing.GetLabels()) {
result.Operation = ReconcileUpdate
}
// Compute extra and missing rules
_, result.ExtraRules = validation.Covers(expected.GetRules(), existing.GetRules())
_, result.MissingRules = validation.Covers(existing.GetRules(), expected.GetRules())
switch {
case !removeExtraPermissions && len(result.MissingRules) > 0:
// add missing rules in the union case
result.Role.SetRules(append(result.Role.GetRules(), result.MissingRules...))
result.Operation = ReconcileUpdate
case removeExtraPermissions && (len(result.MissingRules) > 0 || len(result.ExtraRules) > 0):
// stomp to expected rules in the non-union case
result.Role.SetRules(expected.GetRules())
result.Operation = ReconcileUpdate
}
// Compute extra and missing rules
_, result.ExtraAggregationRuleSelectors = aggregationRuleCovers(expected.GetAggregationRule(), existing.GetAggregationRule())
_, result.MissingAggregationRuleSelectors = aggregationRuleCovers(existing.GetAggregationRule(), expected.GetAggregationRule())
switch {
case !removeExtraPermissions && len(result.MissingAggregationRuleSelectors) > 0:
// add missing rules in the union case
aggregationRule := result.Role.GetAggregationRule()
if aggregationRule == nil {
aggregationRule = &rbac.AggregationRule{}
}
aggregationRule.ClusterRoleSelectors = append(aggregationRule.ClusterRoleSelectors, result.MissingAggregationRuleSelectors...)
result.Role.SetAggregationRule(aggregationRule)
result.Operation = ReconcileUpdate
case removeExtraPermissions && (len(result.MissingAggregationRuleSelectors) > 0 || len(result.ExtraAggregationRuleSelectors) > 0):
result.Role.SetAggregationRule(expected.GetAggregationRule())
result.Operation = ReconcileUpdate
}
return result, nil
}
// merge combines the given maps with the later annotations having higher precedence
func merge(maps ...map[string]string) map[string]string {
var output map[string]string = nil
for _, m := range maps {
if m != nil && output == nil {
output = map[string]string{}
}
for k, v := range m {
output[k] = v
}
}
return output
}
// aggregationRuleCovers determines whether or not the ownerSelectors cover the servantSelectors in terms of semantically
// equal label selectors.
// It returns whether or not the ownerSelectors cover and a list of the rules that the ownerSelectors do not cover.
func aggregationRuleCovers(ownerRule, servantRule *rbac.AggregationRule) (bool, []metav1.LabelSelector) {
switch {
case ownerRule == nil && servantRule == nil:
return true, []metav1.LabelSelector{}
case ownerRule == nil && servantRule != nil:
return false, servantRule.ClusterRoleSelectors
case ownerRule != nil && servantRule == nil:
return true, []metav1.LabelSelector{}
}
ownerSelectors := ownerRule.ClusterRoleSelectors
servantSelectors := servantRule.ClusterRoleSelectors
uncoveredSelectors := []metav1.LabelSelector{}
for _, servantSelector := range servantSelectors {
covered := false
for _, ownerSelector := range ownerSelectors {
if equality.Semantic.DeepEqual(ownerSelector, servantSelector) {
covered = true
break
}
}
if !covered {
uncoveredSelectors = append(uncoveredSelectors, servantSelector)
}
}
return (len(uncoveredSelectors) == 0), uncoveredSelectors
}

View File

@ -0,0 +1,372 @@
/*
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 reconciliation
import (
"testing"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/diff"
"k8s.io/kubernetes/pkg/apis/core/helper"
"k8s.io/kubernetes/pkg/apis/rbac"
)
func role(rules []rbac.PolicyRule, labels map[string]string, annotations map[string]string) *rbac.ClusterRole {
return &rbac.ClusterRole{
Rules: rules,
ObjectMeta: metav1.ObjectMeta{Labels: labels, Annotations: annotations},
}
}
func rules(resources ...string) []rbac.PolicyRule {
r := []rbac.PolicyRule{}
for _, resource := range resources {
r = append(r, rbac.PolicyRule{APIGroups: []string{""}, Verbs: []string{"get"}, Resources: []string{resource}})
}
return r
}
type ss map[string]string
func TestComputeReconciledRoleRules(t *testing.T) {
tests := map[string]struct {
expectedRole *rbac.ClusterRole
actualRole *rbac.ClusterRole
removeExtraPermissions bool
expectedReconciledRole *rbac.ClusterRole
expectedReconciliationNeeded bool
}{
"empty": {
expectedRole: role(rules(), nil, nil),
actualRole: role(rules(), nil, nil),
removeExtraPermissions: true,
expectedReconciledRole: nil,
expectedReconciliationNeeded: false,
},
"match without union": {
expectedRole: role(rules("a"), nil, nil),
actualRole: role(rules("a"), nil, nil),
removeExtraPermissions: true,
expectedReconciledRole: nil,
expectedReconciliationNeeded: false,
},
"match with union": {
expectedRole: role(rules("a"), nil, nil),
actualRole: role(rules("a"), nil, nil),
removeExtraPermissions: false,
expectedReconciledRole: nil,
expectedReconciliationNeeded: false,
},
"different rules without union": {
expectedRole: role(rules("a"), nil, nil),
actualRole: role(rules("b"), nil, nil),
removeExtraPermissions: true,
expectedReconciledRole: role(rules("a"), nil, nil),
expectedReconciliationNeeded: true,
},
"different rules with union": {
expectedRole: role(rules("a"), nil, nil),
actualRole: role(rules("b"), nil, nil),
removeExtraPermissions: false,
expectedReconciledRole: role(rules("b", "a"), nil, nil),
expectedReconciliationNeeded: true,
},
"match labels without union": {
expectedRole: role(rules("a"), ss{"1": "a"}, nil),
actualRole: role(rules("a"), ss{"1": "a"}, nil),
removeExtraPermissions: true,
expectedReconciledRole: nil,
expectedReconciliationNeeded: false,
},
"match labels with union": {
expectedRole: role(rules("a"), ss{"1": "a"}, nil),
actualRole: role(rules("a"), ss{"1": "a"}, nil),
removeExtraPermissions: false,
expectedReconciledRole: nil,
expectedReconciliationNeeded: false,
},
"different labels without union": {
expectedRole: role(rules("a"), ss{"1": "a"}, nil),
actualRole: role(rules("a"), ss{"2": "b"}, nil),
removeExtraPermissions: true,
expectedReconciledRole: role(rules("a"), ss{"1": "a", "2": "b"}, nil),
expectedReconciliationNeeded: true,
},
"different labels with union": {
expectedRole: role(rules("a"), ss{"1": "a"}, nil),
actualRole: role(rules("a"), ss{"2": "b"}, nil),
removeExtraPermissions: false,
expectedReconciledRole: role(rules("a"), ss{"1": "a", "2": "b"}, nil),
expectedReconciliationNeeded: true,
},
"different labels and rules without union": {
expectedRole: role(rules("a"), ss{"1": "a"}, nil),
actualRole: role(rules("b"), ss{"2": "b"}, nil),
removeExtraPermissions: true,
expectedReconciledRole: role(rules("a"), ss{"1": "a", "2": "b"}, nil),
expectedReconciliationNeeded: true,
},
"different labels and rules with union": {
expectedRole: role(rules("a"), ss{"1": "a"}, nil),
actualRole: role(rules("b"), ss{"2": "b"}, nil),
removeExtraPermissions: false,
expectedReconciledRole: role(rules("b", "a"), ss{"1": "a", "2": "b"}, nil),
expectedReconciliationNeeded: true,
},
"conflicting labels and rules without union": {
expectedRole: role(rules("a"), ss{"1": "a"}, nil),
actualRole: role(rules("b"), ss{"1": "b"}, nil),
removeExtraPermissions: true,
expectedReconciledRole: role(rules("a"), ss{"1": "b"}, nil),
expectedReconciliationNeeded: true,
},
"conflicting labels and rules with union": {
expectedRole: role(rules("a"), ss{"1": "a"}, nil),
actualRole: role(rules("b"), ss{"1": "b"}, nil),
removeExtraPermissions: false,
expectedReconciledRole: role(rules("b", "a"), ss{"1": "b"}, nil),
expectedReconciliationNeeded: true,
},
"match annotations without union": {
expectedRole: role(rules("a"), nil, ss{"1": "a"}),
actualRole: role(rules("a"), nil, ss{"1": "a"}),
removeExtraPermissions: true,
expectedReconciledRole: nil,
expectedReconciliationNeeded: false,
},
"match annotations with union": {
expectedRole: role(rules("a"), nil, ss{"1": "a"}),
actualRole: role(rules("a"), nil, ss{"1": "a"}),
removeExtraPermissions: false,
expectedReconciledRole: nil,
expectedReconciliationNeeded: false,
},
"different annotations without union": {
expectedRole: role(rules("a"), nil, ss{"1": "a"}),
actualRole: role(rules("a"), nil, ss{"2": "b"}),
removeExtraPermissions: true,
expectedReconciledRole: role(rules("a"), nil, ss{"1": "a", "2": "b"}),
expectedReconciliationNeeded: true,
},
"different annotations with union": {
expectedRole: role(rules("a"), nil, ss{"1": "a"}),
actualRole: role(rules("a"), nil, ss{"2": "b"}),
removeExtraPermissions: false,
expectedReconciledRole: role(rules("a"), nil, ss{"1": "a", "2": "b"}),
expectedReconciliationNeeded: true,
},
"different annotations and rules without union": {
expectedRole: role(rules("a"), nil, ss{"1": "a"}),
actualRole: role(rules("b"), nil, ss{"2": "b"}),
removeExtraPermissions: true,
expectedReconciledRole: role(rules("a"), nil, ss{"1": "a", "2": "b"}),
expectedReconciliationNeeded: true,
},
"different annotations and rules with union": {
expectedRole: role(rules("a"), nil, ss{"1": "a"}),
actualRole: role(rules("b"), nil, ss{"2": "b"}),
removeExtraPermissions: false,
expectedReconciledRole: role(rules("b", "a"), nil, ss{"1": "a", "2": "b"}),
expectedReconciliationNeeded: true,
},
"conflicting annotations and rules without union": {
expectedRole: role(rules("a"), nil, ss{"1": "a"}),
actualRole: role(rules("b"), nil, ss{"1": "b"}),
removeExtraPermissions: true,
expectedReconciledRole: role(rules("a"), nil, ss{"1": "b"}),
expectedReconciliationNeeded: true,
},
"conflicting annotations and rules with union": {
expectedRole: role(rules("a"), nil, ss{"1": "a"}),
actualRole: role(rules("b"), nil, ss{"1": "b"}),
removeExtraPermissions: false,
expectedReconciledRole: role(rules("b", "a"), nil, ss{"1": "b"}),
expectedReconciliationNeeded: true,
},
"conflicting labels/annotations and rules without union": {
expectedRole: role(rules("a"), ss{"3": "d"}, ss{"1": "a"}),
actualRole: role(rules("b"), ss{"4": "e"}, ss{"1": "b"}),
removeExtraPermissions: true,
expectedReconciledRole: role(rules("a"), ss{"3": "d", "4": "e"}, ss{"1": "b"}),
expectedReconciliationNeeded: true,
},
"conflicting labels/annotations and rules with union": {
expectedRole: role(rules("a"), ss{"3": "d"}, ss{"1": "a"}),
actualRole: role(rules("b"), ss{"4": "e"}, ss{"1": "b"}),
removeExtraPermissions: false,
expectedReconciledRole: role(rules("b", "a"), ss{"3": "d", "4": "e"}, ss{"1": "b"}),
expectedReconciliationNeeded: true,
},
"complex labels/annotations and rules without union": {
expectedRole: role(rules("pods", "nodes", "secrets"), ss{"env": "prod", "color": "blue"}, ss{"description": "fancy", "system": "true"}),
actualRole: role(rules("nodes", "images", "projects"), ss{"color": "red", "team": "pm"}, ss{"system": "false", "owner": "admin", "vip": "yes"}),
removeExtraPermissions: true,
expectedReconciledRole: role(
rules("pods", "nodes", "secrets"),
ss{"env": "prod", "color": "red", "team": "pm"},
ss{"description": "fancy", "system": "false", "owner": "admin", "vip": "yes"}),
expectedReconciliationNeeded: true,
},
"complex labels/annotations and rules with union": {
expectedRole: role(rules("pods", "nodes", "secrets"), ss{"env": "prod", "color": "blue", "manager": "randy"}, ss{"description": "fancy", "system": "true", "up": "true"}),
actualRole: role(rules("nodes", "images", "projects"), ss{"color": "red", "team": "pm"}, ss{"system": "false", "owner": "admin", "vip": "yes", "rate": "down"}),
removeExtraPermissions: false,
expectedReconciledRole: role(
rules("nodes", "images", "projects", "pods", "secrets"),
ss{"env": "prod", "manager": "randy", "color": "red", "team": "pm"},
ss{"description": "fancy", "system": "false", "owner": "admin", "vip": "yes", "rate": "down", "up": "true"}),
expectedReconciliationNeeded: true,
},
}
for k, tc := range tests {
actualRole := ClusterRoleRuleOwner{ClusterRole: tc.actualRole}
expectedRole := ClusterRoleRuleOwner{ClusterRole: tc.expectedRole}
result, err := computeReconciledRole(actualRole, expectedRole, tc.removeExtraPermissions)
if err != nil {
t.Errorf("%s: %v", k, err)
continue
}
reconciliationNeeded := result.Operation != ReconcileNone
if reconciliationNeeded != tc.expectedReconciliationNeeded {
t.Errorf("%s: Expected\n\t%v\ngot\n\t%v", k, tc.expectedReconciliationNeeded, reconciliationNeeded)
continue
}
if reconciliationNeeded && !helper.Semantic.DeepEqual(result.Role.(ClusterRoleRuleOwner).ClusterRole, tc.expectedReconciledRole) {
t.Errorf("%s: Expected\n\t%#v\ngot\n\t%#v", k, tc.expectedReconciledRole, result.Role)
}
}
}
func aggregatedRole(aggregationRule *rbac.AggregationRule) *rbac.ClusterRole {
return &rbac.ClusterRole{
AggregationRule: aggregationRule,
}
}
func aggregationrule(selectors []map[string]string) *rbac.AggregationRule {
ret := &rbac.AggregationRule{}
for _, selector := range selectors {
ret.ClusterRoleSelectors = append(ret.ClusterRoleSelectors,
metav1.LabelSelector{MatchLabels: selector})
}
return ret
}
func TestComputeReconciledRoleAggregationRules(t *testing.T) {
tests := map[string]struct {
expectedRole *rbac.ClusterRole
actualRole *rbac.ClusterRole
removeExtraPermissions bool
expectedReconciledRole *rbac.ClusterRole
expectedReconciliationNeeded bool
}{
"empty": {
expectedRole: aggregatedRole(&rbac.AggregationRule{}),
actualRole: aggregatedRole(nil),
removeExtraPermissions: true,
expectedReconciledRole: nil,
expectedReconciliationNeeded: false,
},
"empty-2": {
expectedRole: aggregatedRole(&rbac.AggregationRule{}),
actualRole: aggregatedRole(&rbac.AggregationRule{}),
removeExtraPermissions: true,
expectedReconciledRole: nil,
expectedReconciliationNeeded: false,
},
"match without union": {
expectedRole: aggregatedRole(aggregationrule([]map[string]string{{"foo": "bar"}})),
actualRole: aggregatedRole(aggregationrule([]map[string]string{{"foo": "bar"}})),
removeExtraPermissions: true,
expectedReconciledRole: nil,
expectedReconciliationNeeded: false,
},
"match with union": {
expectedRole: aggregatedRole(aggregationrule([]map[string]string{{"foo": "bar"}})),
actualRole: aggregatedRole(aggregationrule([]map[string]string{{"foo": "bar"}})),
removeExtraPermissions: false,
expectedReconciledRole: nil,
expectedReconciliationNeeded: false,
},
"different rules without union": {
expectedRole: aggregatedRole(aggregationrule([]map[string]string{{"foo": "bar"}})),
actualRole: aggregatedRole(aggregationrule([]map[string]string{{"alpha": "bravo"}})),
removeExtraPermissions: true,
expectedReconciledRole: aggregatedRole(aggregationrule([]map[string]string{{"foo": "bar"}})),
expectedReconciliationNeeded: true,
},
"different rules with union": {
expectedRole: aggregatedRole(aggregationrule([]map[string]string{{"foo": "bar"}})),
actualRole: aggregatedRole(aggregationrule([]map[string]string{{"alpha": "bravo"}})),
removeExtraPermissions: false,
expectedReconciledRole: aggregatedRole(aggregationrule([]map[string]string{{"alpha": "bravo"}, {"foo": "bar"}})),
expectedReconciliationNeeded: true,
},
}
for k, tc := range tests {
actualRole := ClusterRoleRuleOwner{ClusterRole: tc.actualRole}
expectedRole := ClusterRoleRuleOwner{ClusterRole: tc.expectedRole}
result, err := computeReconciledRole(actualRole, expectedRole, tc.removeExtraPermissions)
if err != nil {
t.Errorf("%s: %v", k, err)
continue
}
reconciliationNeeded := result.Operation != ReconcileNone
if reconciliationNeeded != tc.expectedReconciliationNeeded {
t.Errorf("%s: Expected\n\t%v\ngot\n\t%v", k, tc.expectedReconciliationNeeded, reconciliationNeeded)
continue
}
if reconciliationNeeded && !helper.Semantic.DeepEqual(result.Role.(ClusterRoleRuleOwner).ClusterRole, tc.expectedReconciledRole) {
t.Errorf("%s: %v", k, diff.ObjectDiff(tc.expectedReconciledRole, result.Role.(ClusterRoleRuleOwner).ClusterRole))
}
}
}

View File

@ -0,0 +1,248 @@
/*
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 reconciliation
import (
"fmt"
"reflect"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
"k8s.io/kubernetes/pkg/apis/rbac"
)
type RoleBindingModifier interface {
Get(namespace, name string) (RoleBinding, error)
Delete(namespace, name string, uid types.UID) error
Create(RoleBinding) (RoleBinding, error)
Update(RoleBinding) (RoleBinding, error)
}
type RoleBinding interface {
GetObject() runtime.Object
GetNamespace() string
GetName() string
GetUID() types.UID
GetLabels() map[string]string
SetLabels(map[string]string)
GetAnnotations() map[string]string
SetAnnotations(map[string]string)
GetRoleRef() rbac.RoleRef
GetSubjects() []rbac.Subject
SetSubjects([]rbac.Subject)
DeepCopyRoleBinding() RoleBinding
}
// ReconcileRoleBindingOptions holds options for running a role binding reconciliation
type ReconcileRoleBindingOptions struct {
// RoleBinding is the expected rolebinding that will be reconciled
RoleBinding RoleBinding
// Confirm indicates writes should be performed. When false, results are returned as a dry-run.
Confirm bool
// RemoveExtraSubjects indicates reconciliation should remove extra subjects from an existing role binding
RemoveExtraSubjects bool
// Client is used to look up existing rolebindings, and create/update the rolebinding when Confirm=true
Client RoleBindingModifier
}
// ReconcileClusterRoleBindingResult holds the result of a reconciliation operation.
type ReconcileClusterRoleBindingResult struct {
// RoleBinding is the reconciled rolebinding from the reconciliation operation.
// If the reconcile was performed as a dry-run, or the existing rolebinding was protected, the reconciled rolebinding is not persisted.
RoleBinding RoleBinding
// MissingSubjects contains expected subjects that were missing from the currently persisted rolebinding
MissingSubjects []rbac.Subject
// ExtraSubjects contains extra subjects the currently persisted rolebinding had
ExtraSubjects []rbac.Subject
// Operation is the API operation required to reconcile.
// If no reconciliation was needed, it is set to ReconcileNone.
// If options.Confirm == false, the reconcile was in dry-run mode, so the operation was not performed.
// If result.Protected == true, the rolebinding opted out of reconciliation, so the operation was not performed.
// Otherwise, the operation was performed.
Operation ReconcileOperation
// Protected indicates an existing role prevented reconciliation
Protected bool
}
func (o *ReconcileRoleBindingOptions) Run() (*ReconcileClusterRoleBindingResult, error) {
return o.run(0)
}
func (o *ReconcileRoleBindingOptions) run(attempts int) (*ReconcileClusterRoleBindingResult, error) {
// This keeps us from retrying forever if a rolebinding keeps appearing and disappearing as we reconcile.
// Conflict errors on update are handled at a higher level.
if attempts > 3 {
return nil, fmt.Errorf("exceeded maximum attempts")
}
var result *ReconcileClusterRoleBindingResult
existingBinding, err := o.Client.Get(o.RoleBinding.GetNamespace(), o.RoleBinding.GetName())
switch {
case errors.IsNotFound(err):
result = &ReconcileClusterRoleBindingResult{
RoleBinding: o.RoleBinding,
MissingSubjects: o.RoleBinding.GetSubjects(),
Operation: ReconcileCreate,
}
case err != nil:
return nil, err
default:
result, err = computeReconciledRoleBinding(existingBinding, o.RoleBinding, o.RemoveExtraSubjects)
if err != nil {
return nil, err
}
}
// If reconcile-protected, short-circuit
if result.Protected {
return result, nil
}
// If we're in dry-run mode, short-circuit
if !o.Confirm {
return result, nil
}
switch result.Operation {
case ReconcileRecreate:
// Try deleting
err := o.Client.Delete(existingBinding.GetNamespace(), existingBinding.GetName(), existingBinding.GetUID())
switch {
case err == nil, errors.IsNotFound(err):
// object no longer exists, as desired
case errors.IsConflict(err):
// delete failed because our UID precondition conflicted
// this could mean another object exists with a different UID, re-run
return o.run(attempts + 1)
default:
// return other errors
return nil, err
}
// continue to create
fallthrough
case ReconcileCreate:
created, err := o.Client.Create(result.RoleBinding)
// If created since we started this reconcile, re-run
if errors.IsAlreadyExists(err) {
return o.run(attempts + 1)
}
if err != nil {
return nil, err
}
result.RoleBinding = created
case ReconcileUpdate:
updated, err := o.Client.Update(result.RoleBinding)
// If deleted since we started this reconcile, re-run
if errors.IsNotFound(err) {
return o.run(attempts + 1)
}
if err != nil {
return nil, err
}
result.RoleBinding = updated
case ReconcileNone:
// no-op
default:
return nil, fmt.Errorf("invalid operation: %v", result.Operation)
}
return result, nil
}
// computeReconciledRoleBinding returns the rolebinding that must be created and/or updated to make the
// existing rolebinding's subjects, roleref, labels, and annotations match the expected rolebinding
func computeReconciledRoleBinding(existing, expected RoleBinding, removeExtraSubjects bool) (*ReconcileClusterRoleBindingResult, error) {
result := &ReconcileClusterRoleBindingResult{Operation: ReconcileNone}
result.Protected = (existing.GetAnnotations()[rbac.AutoUpdateAnnotationKey] == "false")
// Reset the binding completely if the roleRef is different
if expected.GetRoleRef() != existing.GetRoleRef() {
result.RoleBinding = expected
result.Operation = ReconcileRecreate
return result, nil
}
// Start with a copy of the existing object
result.RoleBinding = existing.DeepCopyRoleBinding()
// Merge expected annotations and labels
result.RoleBinding.SetAnnotations(merge(expected.GetAnnotations(), result.RoleBinding.GetAnnotations()))
if !reflect.DeepEqual(result.RoleBinding.GetAnnotations(), existing.GetAnnotations()) {
result.Operation = ReconcileUpdate
}
result.RoleBinding.SetLabels(merge(expected.GetLabels(), result.RoleBinding.GetLabels()))
if !reflect.DeepEqual(result.RoleBinding.GetLabels(), existing.GetLabels()) {
result.Operation = ReconcileUpdate
}
// Compute extra and missing subjects
result.MissingSubjects, result.ExtraSubjects = diffSubjectLists(expected.GetSubjects(), existing.GetSubjects())
switch {
case !removeExtraSubjects && len(result.MissingSubjects) > 0:
// add missing subjects in the union case
result.RoleBinding.SetSubjects(append(result.RoleBinding.GetSubjects(), result.MissingSubjects...))
result.Operation = ReconcileUpdate
case removeExtraSubjects && (len(result.MissingSubjects) > 0 || len(result.ExtraSubjects) > 0):
// stomp to expected subjects in the non-union case
result.RoleBinding.SetSubjects(expected.GetSubjects())
result.Operation = ReconcileUpdate
}
return result, nil
}
func contains(list []rbac.Subject, item rbac.Subject) bool {
for _, listItem := range list {
if listItem == item {
return true
}
}
return false
}
// diffSubjectLists returns lists containing the items unique to each provided list:
// list1Only = list1 - list2
// list2Only = list2 - list1
// if both returned lists are empty, the provided lists are equal
func diffSubjectLists(list1 []rbac.Subject, list2 []rbac.Subject) (list1Only []rbac.Subject, list2Only []rbac.Subject) {
for _, list1Item := range list1 {
if !contains(list2, list1Item) {
if !contains(list1Only, list1Item) {
list1Only = append(list1Only, list1Item)
}
}
}
for _, list2Item := range list2 {
if !contains(list1, list2Item) {
if !contains(list2Only, list2Item) {
list2Only = append(list2Only, list2Item)
}
}
}
return
}

View File

@ -0,0 +1,181 @@
/*
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 reconciliation
import (
"testing"
"k8s.io/kubernetes/pkg/apis/core/helper"
"k8s.io/kubernetes/pkg/apis/rbac"
)
func binding(roleRef rbac.RoleRef, subjects []rbac.Subject) *rbac.ClusterRoleBinding {
return &rbac.ClusterRoleBinding{RoleRef: roleRef, Subjects: subjects}
}
func ref(name string) rbac.RoleRef {
return rbac.RoleRef{Name: name}
}
func subject(name string) rbac.Subject {
return rbac.Subject{Name: name}
}
func subjects(names ...string) []rbac.Subject {
r := []rbac.Subject{}
for _, name := range names {
r = append(r, subject(name))
}
return r
}
func TestDiffObjectReferenceLists(t *testing.T) {
tests := map[string]struct {
A []rbac.Subject
B []rbac.Subject
ExpectedOnlyA []rbac.Subject
ExpectedOnlyB []rbac.Subject
}{
"empty": {},
"matching, order-independent": {
A: subjects("foo", "bar"),
B: subjects("bar", "foo"),
},
"partial match": {
A: subjects("foo", "bar"),
B: subjects("foo", "baz"),
ExpectedOnlyA: subjects("bar"),
ExpectedOnlyB: subjects("baz"),
},
"missing": {
A: subjects("foo"),
B: subjects("bar"),
ExpectedOnlyA: subjects("foo"),
ExpectedOnlyB: subjects("bar"),
},
"remove duplicates": {
A: subjects("foo", "foo"),
B: subjects("bar", "bar"),
ExpectedOnlyA: subjects("foo"),
ExpectedOnlyB: subjects("bar"),
},
}
for k, tc := range tests {
onlyA, onlyB := diffSubjectLists(tc.A, tc.B)
if !helper.Semantic.DeepEqual(onlyA, tc.ExpectedOnlyA) {
t.Errorf("%s: Expected %#v, got %#v", k, tc.ExpectedOnlyA, onlyA)
}
if !helper.Semantic.DeepEqual(onlyB, tc.ExpectedOnlyB) {
t.Errorf("%s: Expected %#v, got %#v", k, tc.ExpectedOnlyB, onlyB)
}
}
}
func TestComputeUpdate(t *testing.T) {
tests := map[string]struct {
ExpectedBinding *rbac.ClusterRoleBinding
ActualBinding *rbac.ClusterRoleBinding
RemoveExtraSubjects bool
ExpectedUpdatedBinding *rbac.ClusterRoleBinding
ExpectedUpdateNeeded bool
}{
"match without union": {
ExpectedBinding: binding(ref("role"), subjects("a")),
ActualBinding: binding(ref("role"), subjects("a")),
RemoveExtraSubjects: true,
ExpectedUpdatedBinding: nil,
ExpectedUpdateNeeded: false,
},
"match with union": {
ExpectedBinding: binding(ref("role"), subjects("a")),
ActualBinding: binding(ref("role"), subjects("a")),
RemoveExtraSubjects: false,
ExpectedUpdatedBinding: nil,
ExpectedUpdateNeeded: false,
},
"different roleref with identical subjects": {
ExpectedBinding: binding(ref("role"), subjects("a")),
ActualBinding: binding(ref("differentRole"), subjects("a")),
RemoveExtraSubjects: false,
ExpectedUpdatedBinding: binding(ref("role"), subjects("a")),
ExpectedUpdateNeeded: true,
},
"extra subjects without union": {
ExpectedBinding: binding(ref("role"), subjects("a")),
ActualBinding: binding(ref("role"), subjects("a", "b")),
RemoveExtraSubjects: true,
ExpectedUpdatedBinding: binding(ref("role"), subjects("a")),
ExpectedUpdateNeeded: true,
},
"extra subjects with union": {
ExpectedBinding: binding(ref("role"), subjects("a")),
ActualBinding: binding(ref("role"), subjects("a", "b")),
RemoveExtraSubjects: false,
ExpectedUpdatedBinding: nil,
ExpectedUpdateNeeded: false,
},
"missing subjects without union": {
ExpectedBinding: binding(ref("role"), subjects("a", "c")),
ActualBinding: binding(ref("role"), subjects("a", "b")),
RemoveExtraSubjects: true,
ExpectedUpdatedBinding: binding(ref("role"), subjects("a", "c")),
ExpectedUpdateNeeded: true,
},
"missing subjects with union": {
ExpectedBinding: binding(ref("role"), subjects("a", "c")),
ActualBinding: binding(ref("role"), subjects("a", "b")),
RemoveExtraSubjects: false,
ExpectedUpdatedBinding: binding(ref("role"), subjects("a", "b", "c")),
ExpectedUpdateNeeded: true,
},
}
for k, tc := range tests {
actualRoleBinding := ClusterRoleBindingAdapter{ClusterRoleBinding: tc.ActualBinding}
expectedRoleBinding := ClusterRoleBindingAdapter{ClusterRoleBinding: tc.ExpectedBinding}
result, err := computeReconciledRoleBinding(actualRoleBinding, expectedRoleBinding, tc.RemoveExtraSubjects)
if err != nil {
t.Errorf("%s: %v", k, err)
continue
}
updateNeeded := result.Operation != ReconcileNone
updatedBinding := result.RoleBinding.(ClusterRoleBindingAdapter).ClusterRoleBinding
if updateNeeded != tc.ExpectedUpdateNeeded {
t.Errorf("%s: Expected\n\t%v\ngot\n\t%v (%v)", k, tc.ExpectedUpdateNeeded, updateNeeded, result.Operation)
continue
}
if updateNeeded && !helper.Semantic.DeepEqual(updatedBinding, tc.ExpectedUpdatedBinding) {
t.Errorf("%s: Expected\n\t%v %v\ngot\n\t%v %v", k, tc.ExpectedUpdatedBinding.RoleRef, tc.ExpectedUpdatedBinding.Subjects, updatedBinding.RoleRef, updatedBinding.Subjects)
}
}
}

View File

@ -0,0 +1,112 @@
/*
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 reconciliation
import (
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/apis/rbac"
core "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion"
)
// +k8s:deepcopy-gen=true
// +k8s:deepcopy-gen:interfaces=k8s.io/kubernetes/pkg/registry/rbac/reconciliation.RuleOwner
// +k8s:deepcopy-gen:nonpointer-interfaces=true
type RoleRuleOwner struct {
Role *rbac.Role
}
func (o RoleRuleOwner) GetObject() runtime.Object {
return o.Role
}
func (o RoleRuleOwner) GetNamespace() string {
return o.Role.Namespace
}
func (o RoleRuleOwner) GetName() string {
return o.Role.Name
}
func (o RoleRuleOwner) GetLabels() map[string]string {
return o.Role.Labels
}
func (o RoleRuleOwner) SetLabels(in map[string]string) {
o.Role.Labels = in
}
func (o RoleRuleOwner) GetAnnotations() map[string]string {
return o.Role.Annotations
}
func (o RoleRuleOwner) SetAnnotations(in map[string]string) {
o.Role.Annotations = in
}
func (o RoleRuleOwner) GetRules() []rbac.PolicyRule {
return o.Role.Rules
}
func (o RoleRuleOwner) SetRules(in []rbac.PolicyRule) {
o.Role.Rules = in
}
func (o RoleRuleOwner) GetAggregationRule() *rbac.AggregationRule {
return nil
}
func (o RoleRuleOwner) SetAggregationRule(in *rbac.AggregationRule) {
}
type RoleModifier struct {
Client internalversion.RolesGetter
NamespaceClient core.NamespaceInterface
}
func (c RoleModifier) Get(namespace, name string) (RuleOwner, error) {
ret, err := c.Client.Roles(namespace).Get(name, metav1.GetOptions{})
if err != nil {
return nil, err
}
return RoleRuleOwner{Role: ret}, err
}
func (c RoleModifier) Create(in RuleOwner) (RuleOwner, error) {
ns := &api.Namespace{ObjectMeta: metav1.ObjectMeta{Name: in.GetNamespace()}}
if _, err := c.NamespaceClient.Create(ns); err != nil && !apierrors.IsAlreadyExists(err) {
return nil, err
}
ret, err := c.Client.Roles(in.GetNamespace()).Create(in.(RoleRuleOwner).Role)
if err != nil {
return nil, err
}
return RoleRuleOwner{Role: ret}, err
}
func (c RoleModifier) Update(in RuleOwner) (RuleOwner, error) {
ret, err := c.Client.Roles(in.GetNamespace()).Update(in.(RoleRuleOwner).Role)
if err != nil {
return nil, err
}
return RoleRuleOwner{Role: ret}, err
}

View File

@ -0,0 +1,118 @@
/*
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 reconciliation
import (
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/apis/rbac"
core "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion"
)
// +k8s:deepcopy-gen=true
// +k8s:deepcopy-gen:interfaces=k8s.io/kubernetes/pkg/registry/rbac/reconciliation.RoleBinding
// +k8s:deepcopy-gen:nonpointer-interfaces=true
type RoleBindingAdapter struct {
RoleBinding *rbac.RoleBinding
}
func (o RoleBindingAdapter) GetObject() runtime.Object {
return o.RoleBinding
}
func (o RoleBindingAdapter) GetNamespace() string {
return o.RoleBinding.Namespace
}
func (o RoleBindingAdapter) GetName() string {
return o.RoleBinding.Name
}
func (o RoleBindingAdapter) GetUID() types.UID {
return o.RoleBinding.UID
}
func (o RoleBindingAdapter) GetLabels() map[string]string {
return o.RoleBinding.Labels
}
func (o RoleBindingAdapter) SetLabels(in map[string]string) {
o.RoleBinding.Labels = in
}
func (o RoleBindingAdapter) GetAnnotations() map[string]string {
return o.RoleBinding.Annotations
}
func (o RoleBindingAdapter) SetAnnotations(in map[string]string) {
o.RoleBinding.Annotations = in
}
func (o RoleBindingAdapter) GetRoleRef() rbac.RoleRef {
return o.RoleBinding.RoleRef
}
func (o RoleBindingAdapter) GetSubjects() []rbac.Subject {
return o.RoleBinding.Subjects
}
func (o RoleBindingAdapter) SetSubjects(in []rbac.Subject) {
o.RoleBinding.Subjects = in
}
type RoleBindingClientAdapter struct {
Client internalversion.RoleBindingsGetter
NamespaceClient core.NamespaceInterface
}
func (c RoleBindingClientAdapter) Get(namespace, name string) (RoleBinding, error) {
ret, err := c.Client.RoleBindings(namespace).Get(name, metav1.GetOptions{})
if err != nil {
return nil, err
}
return RoleBindingAdapter{RoleBinding: ret}, err
}
func (c RoleBindingClientAdapter) Create(in RoleBinding) (RoleBinding, error) {
ns := &api.Namespace{ObjectMeta: metav1.ObjectMeta{Name: in.GetNamespace()}}
if _, err := c.NamespaceClient.Create(ns); err != nil && !apierrors.IsAlreadyExists(err) {
return nil, err
}
ret, err := c.Client.RoleBindings(in.GetNamespace()).Create(in.(RoleBindingAdapter).RoleBinding)
if err != nil {
return nil, err
}
return RoleBindingAdapter{RoleBinding: ret}, err
}
func (c RoleBindingClientAdapter) Update(in RoleBinding) (RoleBinding, error) {
ret, err := c.Client.RoleBindings(in.GetNamespace()).Update(in.(RoleBindingAdapter).RoleBinding)
if err != nil {
return nil, err
}
return RoleBindingAdapter{RoleBinding: ret}, err
}
func (c RoleBindingClientAdapter) Delete(namespace, name string, uid types.UID) error {
return c.Client.RoleBindings(namespace).Delete(name, &metav1.DeleteOptions{Preconditions: &metav1.Preconditions{UID: &uid}})
}

View File

@ -0,0 +1,145 @@
// +build !ignore_autogenerated
/*
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.
*/
// This file was autogenerated by deepcopy-gen. Do not edit it manually!
package reconciliation
import (
rbac "k8s.io/kubernetes/pkg/apis/rbac"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ClusterRoleBindingAdapter) DeepCopyInto(out *ClusterRoleBindingAdapter) {
*out = *in
if in.ClusterRoleBinding != nil {
in, out := &in.ClusterRoleBinding, &out.ClusterRoleBinding
if *in == nil {
*out = nil
} else {
*out = new(rbac.ClusterRoleBinding)
(*in).DeepCopyInto(*out)
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterRoleBindingAdapter.
func (in *ClusterRoleBindingAdapter) DeepCopy() *ClusterRoleBindingAdapter {
if in == nil {
return nil
}
out := new(ClusterRoleBindingAdapter)
in.DeepCopyInto(out)
return out
}
// DeepCopyRoleBinding is an autogenerated deepcopy function, copying the receiver, creating a new RoleBinding.
func (in ClusterRoleBindingAdapter) DeepCopyRoleBinding() RoleBinding {
return *in.DeepCopy()
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ClusterRoleRuleOwner) DeepCopyInto(out *ClusterRoleRuleOwner) {
*out = *in
if in.ClusterRole != nil {
in, out := &in.ClusterRole, &out.ClusterRole
if *in == nil {
*out = nil
} else {
*out = new(rbac.ClusterRole)
(*in).DeepCopyInto(*out)
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterRoleRuleOwner.
func (in *ClusterRoleRuleOwner) DeepCopy() *ClusterRoleRuleOwner {
if in == nil {
return nil
}
out := new(ClusterRoleRuleOwner)
in.DeepCopyInto(out)
return out
}
// DeepCopyRuleOwner is an autogenerated deepcopy function, copying the receiver, creating a new RuleOwner.
func (in ClusterRoleRuleOwner) DeepCopyRuleOwner() RuleOwner {
return *in.DeepCopy()
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *RoleBindingAdapter) DeepCopyInto(out *RoleBindingAdapter) {
*out = *in
if in.RoleBinding != nil {
in, out := &in.RoleBinding, &out.RoleBinding
if *in == nil {
*out = nil
} else {
*out = new(rbac.RoleBinding)
(*in).DeepCopyInto(*out)
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RoleBindingAdapter.
func (in *RoleBindingAdapter) DeepCopy() *RoleBindingAdapter {
if in == nil {
return nil
}
out := new(RoleBindingAdapter)
in.DeepCopyInto(out)
return out
}
// DeepCopyRoleBinding is an autogenerated deepcopy function, copying the receiver, creating a new RoleBinding.
func (in RoleBindingAdapter) DeepCopyRoleBinding() RoleBinding {
return *in.DeepCopy()
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *RoleRuleOwner) DeepCopyInto(out *RoleRuleOwner) {
*out = *in
if in.Role != nil {
in, out := &in.Role, &out.Role
if *in == nil {
*out = nil
} else {
*out = new(rbac.Role)
(*in).DeepCopyInto(*out)
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RoleRuleOwner.
func (in *RoleRuleOwner) DeepCopy() *RoleRuleOwner {
if in == nil {
return nil
}
out := new(RoleRuleOwner)
in.DeepCopyInto(out)
return out
}
// DeepCopyRuleOwner is an autogenerated deepcopy function, copying the receiver, creating a new RuleOwner.
func (in RoleRuleOwner) DeepCopyRuleOwner() RuleOwner {
return *in.DeepCopy()
}