Commit b12314e2 authored by Kubernetes Submit Queue's avatar Kubernetes Submit Queue Committed by GitHub

Merge pull request #48480 from liggitt/namespace-reconcile

Automatic merge from submit-queue (batch tested with PRs 48480, 48353) Ensure namespace exists as part of RBAC reconciliation reconciliation can race with the controller that creates the namespaces containing the bootstrap roles. if it loses, it gets a NotFound error trying to create the namespaced role/rolebinding. Fixes https://github.com/kubernetes/kubeadm/issues/335 ```release-note RBAC role and role-binding reconciliation now ensures namespaces exist when reconciling on startup. ```
parents bce32b66 d5730f40
...@@ -37,6 +37,7 @@ go_library( ...@@ -37,6 +37,7 @@ go_library(
deps = [ deps = [
"//pkg/api:go_default_library", "//pkg/api:go_default_library",
"//pkg/apis/rbac: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/client/clientset_generated/internalclientset/typed/rbac/internalversion:go_default_library",
"//pkg/registry/rbac/validation:go_default_library", "//pkg/registry/rbac/validation:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
......
...@@ -17,8 +17,11 @@ limitations under the License. ...@@ -17,8 +17,11 @@ limitations under the License.
package reconciliation package reconciliation
import ( import (
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/apis/rbac" "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.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion"
) )
...@@ -59,7 +62,8 @@ func (o RoleRuleOwner) SetRules(in []rbac.PolicyRule) { ...@@ -59,7 +62,8 @@ func (o RoleRuleOwner) SetRules(in []rbac.PolicyRule) {
} }
type RoleModifier struct { type RoleModifier struct {
Client internalversion.RolesGetter Client internalversion.RolesGetter
NamespaceClient core.NamespaceInterface
} }
func (c RoleModifier) Get(namespace, name string) (RuleOwner, error) { func (c RoleModifier) Get(namespace, name string) (RuleOwner, error) {
...@@ -71,6 +75,11 @@ func (c RoleModifier) Get(namespace, name string) (RuleOwner, error) { ...@@ -71,6 +75,11 @@ func (c RoleModifier) Get(namespace, name string) (RuleOwner, error) {
} }
func (c RoleModifier) Create(in RuleOwner) (RuleOwner, error) { 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) ret, err := c.Client.Roles(in.GetNamespace()).Create(in.(RoleRuleOwner).Role)
if err != nil { if err != nil {
return nil, err return nil, err
......
...@@ -17,9 +17,12 @@ limitations under the License. ...@@ -17,9 +17,12 @@ limitations under the License.
package reconciliation package reconciliation
import ( import (
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/apis/rbac" "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.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion"
) )
...@@ -68,7 +71,8 @@ func (o RoleBindingAdapter) SetSubjects(in []rbac.Subject) { ...@@ -68,7 +71,8 @@ func (o RoleBindingAdapter) SetSubjects(in []rbac.Subject) {
} }
type RoleBindingClientAdapter struct { type RoleBindingClientAdapter struct {
Client internalversion.RoleBindingsGetter Client internalversion.RoleBindingsGetter
NamespaceClient core.NamespaceInterface
} }
func (c RoleBindingClientAdapter) Get(namespace, name string) (RoleBinding, error) { func (c RoleBindingClientAdapter) Get(namespace, name string) (RoleBinding, error) {
...@@ -80,6 +84,11 @@ func (c RoleBindingClientAdapter) Get(namespace, name string) (RoleBinding, erro ...@@ -80,6 +84,11 @@ func (c RoleBindingClientAdapter) Get(namespace, name string) (RoleBinding, erro
} }
func (c RoleBindingClientAdapter) Create(in RoleBinding) (RoleBinding, error) { 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) ret, err := c.Client.RoleBindings(in.GetNamespace()).Create(in.(RoleBindingAdapter).RoleBinding)
if err != nil { if err != nil {
return nil, err return nil, err
......
...@@ -14,6 +14,7 @@ go_library( ...@@ -14,6 +14,7 @@ go_library(
deps = [ deps = [
"//pkg/api:go_default_library", "//pkg/api:go_default_library",
"//pkg/apis/rbac: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/client/clientset_generated/internalclientset/typed/rbac/internalversion:go_default_library",
"//pkg/client/retry:go_default_library", "//pkg/client/retry:go_default_library",
"//pkg/registry/rbac/clusterrole:go_default_library", "//pkg/registry/rbac/clusterrole:go_default_library",
......
...@@ -36,6 +36,7 @@ import ( ...@@ -36,6 +36,7 @@ import (
serverstorage "k8s.io/apiserver/pkg/server/storage" serverstorage "k8s.io/apiserver/pkg/server/storage"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/apis/rbac" "k8s.io/kubernetes/pkg/apis/rbac"
coreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
rbacclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion" rbacclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion"
"k8s.io/kubernetes/pkg/client/retry" "k8s.io/kubernetes/pkg/client/retry"
"k8s.io/kubernetes/pkg/registry/rbac/clusterrole" "k8s.io/kubernetes/pkg/registry/rbac/clusterrole"
...@@ -134,6 +135,13 @@ func PostStartHook(hookContext genericapiserver.PostStartHookContext) error { ...@@ -134,6 +135,13 @@ func PostStartHook(hookContext genericapiserver.PostStartHookContext) error {
// intializing roles is really important. On some e2e runs, we've seen cases where etcd is down when the server // intializing roles is really important. On some e2e runs, we've seen cases where etcd is down when the server
// starts, the roles don't initialize, and nothing works. // starts, the roles don't initialize, and nothing works.
err := wait.Poll(1*time.Second, 30*time.Second, func() (done bool, err error) { err := wait.Poll(1*time.Second, 30*time.Second, func() (done bool, err error) {
coreclientset, err := coreclient.NewForConfig(hookContext.LoopbackClientConfig)
if err != nil {
utilruntime.HandleError(fmt.Errorf("unable to initialize client: %v", err))
return false, nil
}
clientset, err := rbacclient.NewForConfig(hookContext.LoopbackClientConfig) clientset, err := rbacclient.NewForConfig(hookContext.LoopbackClientConfig)
if err != nil { if err != nil {
utilruntime.HandleError(fmt.Errorf("unable to initialize client: %v", err)) utilruntime.HandleError(fmt.Errorf("unable to initialize client: %v", err))
...@@ -212,7 +220,7 @@ func PostStartHook(hookContext genericapiserver.PostStartHookContext) error { ...@@ -212,7 +220,7 @@ func PostStartHook(hookContext genericapiserver.PostStartHookContext) error {
for _, role := range roles { for _, role := range roles {
opts := reconciliation.ReconcileRoleOptions{ opts := reconciliation.ReconcileRoleOptions{
Role: reconciliation.RoleRuleOwner{Role: &role}, Role: reconciliation.RoleRuleOwner{Role: &role},
Client: reconciliation.RoleModifier{Client: clientset}, Client: reconciliation.RoleModifier{Client: clientset, NamespaceClient: coreclientset.Namespaces()},
Confirm: true, Confirm: true,
} }
err := retry.RetryOnConflict(retry.DefaultBackoff, func() error { err := retry.RetryOnConflict(retry.DefaultBackoff, func() error {
...@@ -242,7 +250,7 @@ func PostStartHook(hookContext genericapiserver.PostStartHookContext) error { ...@@ -242,7 +250,7 @@ func PostStartHook(hookContext genericapiserver.PostStartHookContext) error {
for _, roleBinding := range roleBindings { for _, roleBinding := range roleBindings {
opts := reconciliation.ReconcileRoleBindingOptions{ opts := reconciliation.ReconcileRoleBindingOptions{
RoleBinding: reconciliation.RoleBindingAdapter{RoleBinding: &roleBinding}, RoleBinding: reconciliation.RoleBindingAdapter{RoleBinding: &roleBinding},
Client: reconciliation.RoleBindingClientAdapter{Client: clientset}, Client: reconciliation.RoleBindingClientAdapter{Client: clientset, NamespaceClient: coreclientset.Namespaces()},
Confirm: true, Confirm: true,
} }
err := retry.RetryOnConflict(retry.DefaultBackoff, func() error { err := retry.RetryOnConflict(retry.DefaultBackoff, func() error {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment