allow reconcilation of namespaced rolebindings
This commit is contained in:
@@ -11,8 +11,8 @@ load(
|
|||||||
go_test(
|
go_test(
|
||||||
name = "go_default_test",
|
name = "go_default_test",
|
||||||
srcs = [
|
srcs = [
|
||||||
"reconcile_clusterrolebindings_test.go",
|
|
||||||
"reconcile_role_test.go",
|
"reconcile_role_test.go",
|
||||||
|
"reconcile_rolebindings_test.go",
|
||||||
],
|
],
|
||||||
library = ":go_default_library",
|
library = ":go_default_library",
|
||||||
tags = ["automanaged"],
|
tags = ["automanaged"],
|
||||||
@@ -26,9 +26,12 @@ go_test(
|
|||||||
go_library(
|
go_library(
|
||||||
name = "go_default_library",
|
name = "go_default_library",
|
||||||
srcs = [
|
srcs = [
|
||||||
"reconcile_clusterrolebindings.go",
|
"clusterrole_interfaces.go",
|
||||||
|
"clusterrolebinding_interfaces.go",
|
||||||
"reconcile_role.go",
|
"reconcile_role.go",
|
||||||
|
"reconcile_rolebindings.go",
|
||||||
"role_interfaces.go",
|
"role_interfaces.go",
|
||||||
|
"rolebinding_interfaces.go",
|
||||||
],
|
],
|
||||||
tags = ["automanaged"],
|
tags = ["automanaged"],
|
||||||
deps = [
|
deps = [
|
||||||
@@ -38,6 +41,7 @@ go_library(
|
|||||||
"//pkg/registry/rbac/validation:go_default_library",
|
"//pkg/registry/rbac/validation:go_default_library",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/api/errors",
|
"//vendor:k8s.io/apimachinery/pkg/api/errors",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||||
|
"//vendor:k8s.io/apimachinery/pkg/types",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
88
pkg/registry/rbac/reconciliation/clusterrole_interfaces.go
Normal file
88
pkg/registry/rbac/reconciliation/clusterrole_interfaces.go
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
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/kubernetes/pkg/apis/rbac"
|
||||||
|
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ClusterRoleRuleOwner struct {
|
||||||
|
ClusterRole *rbac.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
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
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/types"
|
||||||
|
"k8s.io/kubernetes/pkg/apis/rbac"
|
||||||
|
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ClusterRoleBindingAdapter struct {
|
||||||
|
ClusterRoleBinding *rbac.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}})
|
||||||
|
}
|
@@ -21,10 +21,8 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/api/errors"
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/apis/rbac"
|
"k8s.io/kubernetes/pkg/apis/rbac"
|
||||||
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion"
|
|
||||||
"k8s.io/kubernetes/pkg/registry/rbac/validation"
|
"k8s.io/kubernetes/pkg/registry/rbac/validation"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -54,7 +52,7 @@ type RuleOwner interface {
|
|||||||
SetRules([]rbac.PolicyRule)
|
SetRules([]rbac.PolicyRule)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ReconcileClusterRoleOptions struct {
|
type ReconcileRoleOptions struct {
|
||||||
// Role is the expected role that will be reconciled
|
// Role is the expected role that will be reconciled
|
||||||
Role RuleOwner
|
Role RuleOwner
|
||||||
// Confirm indicates writes should be performed. When false, results are returned as a dry-run.
|
// Confirm indicates writes should be performed. When false, results are returned as a dry-run.
|
||||||
@@ -85,11 +83,11 @@ type ReconcileClusterRoleResult struct {
|
|||||||
Protected bool
|
Protected bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *ReconcileClusterRoleOptions) Run() (*ReconcileClusterRoleResult, error) {
|
func (o *ReconcileRoleOptions) Run() (*ReconcileClusterRoleResult, error) {
|
||||||
return o.run(0)
|
return o.run(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *ReconcileClusterRoleOptions) run(attempts int) (*ReconcileClusterRoleResult, error) {
|
func (o *ReconcileRoleOptions) run(attempts int) (*ReconcileClusterRoleResult, error) {
|
||||||
// This keeps us from retrying forever if a role keeps appearing and disappearing as we reconcile.
|
// 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.
|
// Conflict errors on update are handled at a higher level.
|
||||||
if attempts > 2 {
|
if attempts > 2 {
|
||||||
@@ -215,68 +213,3 @@ func merge(maps ...map[string]string) map[string]string {
|
|||||||
}
|
}
|
||||||
return output
|
return output
|
||||||
}
|
}
|
||||||
|
|
||||||
type ClusterRoleRuleOwner struct {
|
|
||||||
ClusterRole *rbac.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
|
|
||||||
}
|
|
||||||
|
|
||||||
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.Create(in.(ClusterRoleRuleOwner).ClusterRole)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return ClusterRoleRuleOwner{ClusterRole: ret}, err
|
|
||||||
|
|
||||||
}
|
|
||||||
|
@@ -21,29 +21,48 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/api/errors"
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/apis/rbac"
|
"k8s.io/kubernetes/pkg/apis/rbac"
|
||||||
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ReconcileClusterRoleBindingOptions holds options for running a role binding reconciliation
|
type RoleBindingModifier interface {
|
||||||
type ReconcileClusterRoleBindingOptions struct {
|
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 {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReconcileRoleBindingOptions holds options for running a role binding reconciliation
|
||||||
|
type ReconcileRoleBindingOptions struct {
|
||||||
// RoleBinding is the expected rolebinding that will be reconciled
|
// RoleBinding is the expected rolebinding that will be reconciled
|
||||||
RoleBinding *rbac.ClusterRoleBinding
|
RoleBinding RoleBinding
|
||||||
// Confirm indicates writes should be performed. When false, results are returned as a dry-run.
|
// Confirm indicates writes should be performed. When false, results are returned as a dry-run.
|
||||||
Confirm bool
|
Confirm bool
|
||||||
// RemoveExtraSubjects indicates reconciliation should remove extra subjects from an existing role binding
|
// RemoveExtraSubjects indicates reconciliation should remove extra subjects from an existing role binding
|
||||||
RemoveExtraSubjects bool
|
RemoveExtraSubjects bool
|
||||||
// Client is used to look up existing rolebindings, and create/update the rolebinding when Confirm=true
|
// Client is used to look up existing rolebindings, and create/update the rolebinding when Confirm=true
|
||||||
Client internalversion.ClusterRoleBindingInterface
|
Client RoleBindingModifier
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReconcileClusterRoleBindingResult holds the result of a reconciliation operation.
|
// ReconcileClusterRoleBindingResult holds the result of a reconciliation operation.
|
||||||
type ReconcileClusterRoleBindingResult struct {
|
type ReconcileClusterRoleBindingResult struct {
|
||||||
// RoleBinding is the reconciled rolebinding from the reconciliation operation.
|
// 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.
|
// If the reconcile was performed as a dry-run, or the existing rolebinding was protected, the reconciled rolebinding is not persisted.
|
||||||
RoleBinding *rbac.ClusterRoleBinding
|
RoleBinding RoleBinding
|
||||||
|
|
||||||
// MissingSubjects contains expected subjects that were missing from the currently persisted rolebinding
|
// MissingSubjects contains expected subjects that were missing from the currently persisted rolebinding
|
||||||
MissingSubjects []rbac.Subject
|
MissingSubjects []rbac.Subject
|
||||||
@@ -60,11 +79,11 @@ type ReconcileClusterRoleBindingResult struct {
|
|||||||
Protected bool
|
Protected bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *ReconcileClusterRoleBindingOptions) Run() (*ReconcileClusterRoleBindingResult, error) {
|
func (o *ReconcileRoleBindingOptions) Run() (*ReconcileClusterRoleBindingResult, error) {
|
||||||
return o.run(0)
|
return o.run(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *ReconcileClusterRoleBindingOptions) run(attempts int) (*ReconcileClusterRoleBindingResult, error) {
|
func (o *ReconcileRoleBindingOptions) run(attempts int) (*ReconcileClusterRoleBindingResult, error) {
|
||||||
// This keeps us from retrying forever if a rolebinding keeps appearing and disappearing as we reconcile.
|
// 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.
|
// Conflict errors on update are handled at a higher level.
|
||||||
if attempts > 3 {
|
if attempts > 3 {
|
||||||
@@ -73,12 +92,12 @@ func (o *ReconcileClusterRoleBindingOptions) run(attempts int) (*ReconcileCluste
|
|||||||
|
|
||||||
var result *ReconcileClusterRoleBindingResult
|
var result *ReconcileClusterRoleBindingResult
|
||||||
|
|
||||||
existingBinding, err := o.Client.Get(o.RoleBinding.Name, metav1.GetOptions{})
|
existingBinding, err := o.Client.Get(o.RoleBinding.GetNamespace(), o.RoleBinding.GetName())
|
||||||
switch {
|
switch {
|
||||||
case errors.IsNotFound(err):
|
case errors.IsNotFound(err):
|
||||||
result = &ReconcileClusterRoleBindingResult{
|
result = &ReconcileClusterRoleBindingResult{
|
||||||
RoleBinding: o.RoleBinding,
|
RoleBinding: o.RoleBinding,
|
||||||
MissingSubjects: o.RoleBinding.Subjects,
|
MissingSubjects: o.RoleBinding.GetSubjects(),
|
||||||
Operation: ReconcileCreate,
|
Operation: ReconcileCreate,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,10 +123,7 @@ func (o *ReconcileClusterRoleBindingOptions) run(attempts int) (*ReconcileCluste
|
|||||||
switch result.Operation {
|
switch result.Operation {
|
||||||
case ReconcileRecreate:
|
case ReconcileRecreate:
|
||||||
// Try deleting
|
// Try deleting
|
||||||
err := o.Client.Delete(
|
err := o.Client.Delete(existingBinding.GetNamespace(), existingBinding.GetName(), existingBinding.GetUID())
|
||||||
existingBinding.Name,
|
|
||||||
&metav1.DeleteOptions{Preconditions: &metav1.Preconditions{UID: &existingBinding.UID}},
|
|
||||||
)
|
|
||||||
switch {
|
switch {
|
||||||
case err == nil, errors.IsNotFound(err):
|
case err == nil, errors.IsNotFound(err):
|
||||||
// object no longer exists, as desired
|
// object no longer exists, as desired
|
||||||
@@ -155,13 +171,13 @@ func (o *ReconcileClusterRoleBindingOptions) run(attempts int) (*ReconcileCluste
|
|||||||
|
|
||||||
// computeReconciledRoleBinding returns the rolebinding that must be created and/or updated to make the
|
// 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
|
// existing rolebinding's subjects, roleref, labels, and annotations match the expected rolebinding
|
||||||
func computeReconciledRoleBinding(existing, expected *rbac.ClusterRoleBinding, removeExtraSubjects bool) (*ReconcileClusterRoleBindingResult, error) {
|
func computeReconciledRoleBinding(existing, expected RoleBinding, removeExtraSubjects bool) (*ReconcileClusterRoleBindingResult, error) {
|
||||||
result := &ReconcileClusterRoleBindingResult{Operation: ReconcileNone}
|
result := &ReconcileClusterRoleBindingResult{Operation: ReconcileNone}
|
||||||
|
|
||||||
result.Protected = (existing.Annotations[rbac.AutoUpdateAnnotationKey] == "false")
|
result.Protected = (existing.GetAnnotations()[rbac.AutoUpdateAnnotationKey] == "false")
|
||||||
|
|
||||||
// Reset the binding completely if the roleRef is different
|
// Reset the binding completely if the roleRef is different
|
||||||
if expected.RoleRef != existing.RoleRef {
|
if expected.GetRoleRef() != existing.GetRoleRef() {
|
||||||
result.RoleBinding = expected
|
result.RoleBinding = expected
|
||||||
result.Operation = ReconcileRecreate
|
result.Operation = ReconcileRecreate
|
||||||
return result, nil
|
return result, nil
|
||||||
@@ -172,30 +188,30 @@ func computeReconciledRoleBinding(existing, expected *rbac.ClusterRoleBinding, r
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
result.RoleBinding = changedObj.(*rbac.ClusterRoleBinding)
|
result.RoleBinding = changedObj.(RoleBinding)
|
||||||
|
|
||||||
// Merge expected annotations and labels
|
// Merge expected annotations and labels
|
||||||
result.RoleBinding.Annotations = merge(expected.Annotations, result.RoleBinding.Annotations)
|
result.RoleBinding.SetAnnotations(merge(expected.GetAnnotations(), result.RoleBinding.GetAnnotations()))
|
||||||
if !reflect.DeepEqual(result.RoleBinding.Annotations, existing.Annotations) {
|
if !reflect.DeepEqual(result.RoleBinding.GetAnnotations(), existing.GetAnnotations()) {
|
||||||
result.Operation = ReconcileUpdate
|
result.Operation = ReconcileUpdate
|
||||||
}
|
}
|
||||||
result.RoleBinding.Labels = merge(expected.Labels, result.RoleBinding.Labels)
|
result.RoleBinding.SetLabels(merge(expected.GetLabels(), result.RoleBinding.GetLabels()))
|
||||||
if !reflect.DeepEqual(result.RoleBinding.Labels, existing.Labels) {
|
if !reflect.DeepEqual(result.RoleBinding.GetLabels(), existing.GetLabels()) {
|
||||||
result.Operation = ReconcileUpdate
|
result.Operation = ReconcileUpdate
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute extra and missing subjects
|
// Compute extra and missing subjects
|
||||||
result.MissingSubjects, result.ExtraSubjects = diffSubjectLists(expected.Subjects, existing.Subjects)
|
result.MissingSubjects, result.ExtraSubjects = diffSubjectLists(expected.GetSubjects(), existing.GetSubjects())
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case !removeExtraSubjects && len(result.MissingSubjects) > 0:
|
case !removeExtraSubjects && len(result.MissingSubjects) > 0:
|
||||||
// add missing subjects in the union case
|
// add missing subjects in the union case
|
||||||
result.RoleBinding.Subjects = append(result.RoleBinding.Subjects, result.MissingSubjects...)
|
result.RoleBinding.SetSubjects(append(result.RoleBinding.GetSubjects(), result.MissingSubjects...))
|
||||||
result.Operation = ReconcileUpdate
|
result.Operation = ReconcileUpdate
|
||||||
|
|
||||||
case removeExtraSubjects && (len(result.MissingSubjects) > 0 || len(result.ExtraSubjects) > 0):
|
case removeExtraSubjects && (len(result.MissingSubjects) > 0 || len(result.ExtraSubjects) > 0):
|
||||||
// stomp to expected subjects in the non-union case
|
// stomp to expected subjects in the non-union case
|
||||||
result.RoleBinding.Subjects = expected.Subjects
|
result.RoleBinding.SetSubjects(expected.GetSubjects())
|
||||||
result.Operation = ReconcileUpdate
|
result.Operation = ReconcileUpdate
|
||||||
}
|
}
|
||||||
|
|
@@ -161,13 +161,15 @@ func TestComputeUpdate(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for k, tc := range tests {
|
for k, tc := range tests {
|
||||||
result, err := computeReconciledRoleBinding(tc.ActualBinding, tc.ExpectedBinding, tc.RemoveExtraSubjects)
|
actualRoleBinding := ClusterRoleBindingAdapter{ClusterRoleBinding: tc.ActualBinding}
|
||||||
|
expectedRoleBinding := ClusterRoleBindingAdapter{ClusterRoleBinding: tc.ExpectedBinding}
|
||||||
|
result, err := computeReconciledRoleBinding(actualRoleBinding, expectedRoleBinding, tc.RemoveExtraSubjects)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("%s: %v", k, err)
|
t.Errorf("%s: %v", k, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
updateNeeded := result.Operation != ReconcileNone
|
updateNeeded := result.Operation != ReconcileNone
|
||||||
updatedBinding := result.RoleBinding
|
updatedBinding := result.RoleBinding.(ClusterRoleBindingAdapter).ClusterRoleBinding
|
||||||
if updateNeeded != tc.ExpectedUpdateNeeded {
|
if updateNeeded != tc.ExpectedUpdateNeeded {
|
||||||
t.Errorf("%s: Expected\n\t%v\ngot\n\t%v (%v)", k, tc.ExpectedUpdateNeeded, updateNeeded, result.Operation)
|
t.Errorf("%s: Expected\n\t%v\ngot\n\t%v (%v)", k, tc.ExpectedUpdateNeeded, updateNeeded, result.Operation)
|
||||||
continue
|
continue
|
@@ -79,7 +79,7 @@ func (c RoleModifier) Create(in RuleOwner) (RuleOwner, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c RoleModifier) Update(in RuleOwner) (RuleOwner, error) {
|
func (c RoleModifier) Update(in RuleOwner) (RuleOwner, error) {
|
||||||
ret, err := c.Client.Roles(in.GetNamespace()).Create(in.(RoleRuleOwner).Role)
|
ret, err := c.Client.Roles(in.GetNamespace()).Update(in.(RoleRuleOwner).Role)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
101
pkg/registry/rbac/reconciliation/rolebinding_interfaces.go
Normal file
101
pkg/registry/rbac/reconciliation/rolebinding_interfaces.go
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
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/types"
|
||||||
|
"k8s.io/kubernetes/pkg/apis/rbac"
|
||||||
|
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RoleBindingAdapter struct {
|
||||||
|
RoleBinding *rbac.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
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
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}})
|
||||||
|
}
|
@@ -147,7 +147,7 @@ func PostStartHook(hookContext genericapiserver.PostStartHookContext) error {
|
|||||||
|
|
||||||
// ensure bootstrap roles are created or reconciled
|
// ensure bootstrap roles are created or reconciled
|
||||||
for _, clusterRole := range append(bootstrappolicy.ClusterRoles(), bootstrappolicy.ControllerRoles()...) {
|
for _, clusterRole := range append(bootstrappolicy.ClusterRoles(), bootstrappolicy.ControllerRoles()...) {
|
||||||
opts := reconciliation.ReconcileClusterRoleOptions{
|
opts := reconciliation.ReconcileRoleOptions{
|
||||||
Role: reconciliation.ClusterRoleRuleOwner{ClusterRole: &clusterRole},
|
Role: reconciliation.ClusterRoleRuleOwner{ClusterRole: &clusterRole},
|
||||||
Client: reconciliation.ClusterRoleModifier{Client: clientset.ClusterRoles()},
|
Client: reconciliation.ClusterRoleModifier{Client: clientset.ClusterRoles()},
|
||||||
Confirm: true,
|
Confirm: true,
|
||||||
@@ -175,9 +175,9 @@ func PostStartHook(hookContext genericapiserver.PostStartHookContext) error {
|
|||||||
|
|
||||||
// ensure bootstrap rolebindings are created or reconciled
|
// ensure bootstrap rolebindings are created or reconciled
|
||||||
for _, clusterRoleBinding := range append(bootstrappolicy.ClusterRoleBindings(), bootstrappolicy.ControllerRoleBindings()...) {
|
for _, clusterRoleBinding := range append(bootstrappolicy.ClusterRoleBindings(), bootstrappolicy.ControllerRoleBindings()...) {
|
||||||
opts := reconciliation.ReconcileClusterRoleBindingOptions{
|
opts := reconciliation.ReconcileRoleBindingOptions{
|
||||||
RoleBinding: &clusterRoleBinding,
|
RoleBinding: reconciliation.ClusterRoleBindingAdapter{ClusterRoleBinding: &clusterRoleBinding},
|
||||||
Client: clientset.ClusterRoleBindings(),
|
Client: reconciliation.ClusterRoleBindingClientAdapter{Client: clientset.ClusterRoleBindings()},
|
||||||
Confirm: true,
|
Confirm: true,
|
||||||
}
|
}
|
||||||
err := retry.RetryOnConflict(retry.DefaultBackoff, func() error {
|
err := retry.RetryOnConflict(retry.DefaultBackoff, func() error {
|
||||||
@@ -206,7 +206,7 @@ func PostStartHook(hookContext genericapiserver.PostStartHookContext) error {
|
|||||||
// ensure bootstrap namespaced roles are created or reconciled
|
// ensure bootstrap namespaced roles are created or reconciled
|
||||||
for namespace, roles := range bootstrappolicy.NamespaceRoles() {
|
for namespace, roles := range bootstrappolicy.NamespaceRoles() {
|
||||||
for _, role := range roles {
|
for _, role := range roles {
|
||||||
opts := reconciliation.ReconcileClusterRoleOptions{
|
opts := reconciliation.ReconcileRoleOptions{
|
||||||
Role: reconciliation.RoleRuleOwner{Role: &role},
|
Role: reconciliation.RoleRuleOwner{Role: &role},
|
||||||
Client: reconciliation.RoleModifier{Client: clientset},
|
Client: reconciliation.RoleModifier{Client: clientset},
|
||||||
Confirm: true,
|
Confirm: true,
|
||||||
|
Reference in New Issue
Block a user