mirror of https://github.com/k3s-io/k3s
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. ```pull/6/head
commit
b12314e246
|
@ -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.
|
||||||
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"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -60,6 +63,7 @@ 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) {
|
||||||
}
|
}
|
||||||
|
|
||||||
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.
|
||||||
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"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -69,6 +72,7 @@ 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
|
||||||
}
|
}
|
||||||
|
|
||||||
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(
|
||||||
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 (
|
||||||
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 {
|
||||||
// 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 {
|
||||||
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 {
|
||||||
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 {
|
||||||
|
|
Loading…
Reference in New Issue