diff --git a/pkg/controller/namespace/namespace_controller.go b/pkg/controller/namespace/namespace_controller.go index b9035d658b1bb63de4e1bc588d2baf49b0c8ceed..c7739c2d02401569d8f1e3e94f30c4f0c1eef560 100644 --- a/pkg/controller/namespace/namespace_controller.go +++ b/pkg/controller/namespace/namespace_controller.go @@ -21,7 +21,6 @@ package namespace import ( "context" "fmt" - "github.com/golang/glog" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" rbac "k8s.io/api/rbac/v1" @@ -30,6 +29,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" + "k8s.io/klog" "k8s.io/kubernetes/pkg/apis/core" "kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha1" "kubesphere.io/kubesphere/pkg/constants" @@ -44,7 +44,6 @@ import ( "sigs.k8s.io/controller-runtime/pkg/handler" "sigs.k8s.io/controller-runtime/pkg/manager" "sigs.k8s.io/controller-runtime/pkg/reconcile" - logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" "sigs.k8s.io/controller-runtime/pkg/source" "time" ) @@ -56,13 +55,11 @@ const ( ) var ( - log = logf.Log.WithName("namespace-controller") - defaultRoles = []rbac.Role{ - {ObjectMeta: metav1.ObjectMeta{Name: "admin", Annotations: map[string]string{constants.DescriptionAnnotationKey: adminDescription, constants.CreatorAnnotationKey: constants.System}}, Rules: []rbac.PolicyRule{{Verbs: []string{"*"}, APIGroups: []string{"*"}, Resources: []string{"*"}}}}, - {ObjectMeta: metav1.ObjectMeta{Name: "operator", Annotations: map[string]string{constants.DescriptionAnnotationKey: operatorDescription, constants.CreatorAnnotationKey: constants.System}}, Rules: []rbac.PolicyRule{{Verbs: []string{"get", "list", "watch"}, APIGroups: []string{"*"}, Resources: []string{"*"}}, - {Verbs: []string{"*"}, APIGroups: []string{"", "apps", "extensions", "batch", "logging.kubesphere.io", "monitoring.kubesphere.io", "iam.kubesphere.io", "resources.kubesphere.io", "autoscaling", "alerting.kubesphere.io", "app.k8s.io", "servicemesh.kubesphere.io", "operations.kubesphere.io"}, Resources: []string{"*"}}}}, - {ObjectMeta: metav1.ObjectMeta{Name: "viewer", Annotations: map[string]string{constants.DescriptionAnnotationKey: viewerDescription, constants.CreatorAnnotationKey: constants.System}}, Rules: []rbac.PolicyRule{{Verbs: []string{"get", "list", "watch"}, APIGroups: []string{"*"}, Resources: []string{"*"}}}}, - } + admin = rbac.Role{ObjectMeta: metav1.ObjectMeta{Name: "admin", Annotations: map[string]string{constants.DescriptionAnnotationKey: adminDescription, constants.CreatorAnnotationKey: constants.System}}, Rules: []rbac.PolicyRule{{Verbs: []string{"*"}, APIGroups: []string{"*"}, Resources: []string{"*"}}}} + operator = rbac.Role{ObjectMeta: metav1.ObjectMeta{Name: "operator", Annotations: map[string]string{constants.DescriptionAnnotationKey: operatorDescription, constants.CreatorAnnotationKey: constants.System}}, Rules: []rbac.PolicyRule{{Verbs: []string{"get", "list", "watch"}, APIGroups: []string{"*"}, Resources: []string{"*"}}, + {Verbs: []string{"*"}, APIGroups: []string{"", "apps", "extensions", "batch", "logging.kubesphere.io", "monitoring.kubesphere.io", "iam.kubesphere.io", "resources.kubesphere.io", "autoscaling", "alerting.kubesphere.io", "app.k8s.io", "servicemesh.kubesphere.io", "operations.kubesphere.io"}, Resources: []string{"*"}}}} + viewer = rbac.Role{ObjectMeta: metav1.ObjectMeta{Name: "viewer", Annotations: map[string]string{constants.DescriptionAnnotationKey: viewerDescription, constants.CreatorAnnotationKey: constants.System}}, Rules: []rbac.PolicyRule{{Verbs: []string{"get", "list", "watch"}, APIGroups: []string{"*"}, Resources: []string{"*"}}}} + defaultRoles = []rbac.Role{admin, operator, viewer} ) /** @@ -162,27 +159,17 @@ func (r *ReconcileNamespace) Reconcile(request reconcile.Request) (reconcile.Res return reconcile.Result{}, nil } - workspaceName := instance.Labels[constants.WorkspaceLabelKey] + controlledByWorkspace, err := r.isControlledByWorkspace(instance) - // delete default role bindings - if workspaceName == "" { - adminBinding := &rbac.RoleBinding{} - adminBinding.Name = "admin" - adminBinding.Namespace = instance.Name - log.Info("Deleting default role binding", "namespace", instance.Name, "name", adminBinding.Name) - err := r.Delete(context.TODO(), adminBinding) - if err != nil && !errors.IsNotFound(err) { - return reconcile.Result{}, err - } - viewerBinding := &rbac.RoleBinding{} - viewerBinding.Name = "viewer" - viewerBinding.Namespace = instance.Name - log.Info("Deleting default role binding", "namespace", instance.Name, "name", viewerBinding.Name) - err = r.Delete(context.TODO(), viewerBinding) - if err != nil && !errors.IsNotFound(err) { - return reconcile.Result{}, err - } - return reconcile.Result{}, nil + if err != nil { + return reconcile.Result{}, err + } + + if !controlledByWorkspace { + + err = r.deleteRoleBindings(instance) + + return reconcile.Result{}, err } if err = r.checkAndBindWorkspace(instance); err != nil { @@ -208,6 +195,18 @@ func (r *ReconcileNamespace) Reconcile(request reconcile.Request) (reconcile.Res return reconcile.Result{}, nil } +func (r *ReconcileNamespace) isControlledByWorkspace(namespace *corev1.Namespace) (bool, error) { + + workspaceName := namespace.Labels[constants.WorkspaceLabelKey] + + // without workspace label + if workspaceName == "" { + return false, nil + } + + return true, nil +} + // Create default roles func (r *ReconcileNamespace) checkAndCreateRoles(namespace *corev1.Namespace) error { for _, role := range defaultRoles { @@ -217,14 +216,21 @@ func (r *ReconcileNamespace) checkAndCreateRoles(namespace *corev1.Namespace) er if errors.IsNotFound(err) { role := role.DeepCopy() role.Namespace = namespace.Name - log.Info("Creating default role", "namespace", namespace.Name, "role", role.Name) err = r.Create(context.TODO(), role) if err != nil { - log.Info("Creating default role failed", "namespace", namespace.Name, "role", role.Name) + klog.Errorf("creating role namespace: %s,role: %s,error: %s", namespace.Name, role.Name, err) return err } } else { - log.Info("Get default role failed", "namespace", namespace.Name, "role", role.Name) + klog.Errorf("get role namespace: %s,role: %s,error: %s", namespace.Name, role.Name, err) + return err + } + } + if !reflect.DeepEqual(found.Rules, role.Rules) { + found.Rules = role.Rules + err := r.Update(context.TODO(), found) + if err != nil { + klog.Errorf("updating default role namespace: %s, role: %s,error: %s", namespace.Name, role.Name, err) return err } } @@ -248,9 +254,9 @@ func (r *ReconcileNamespace) checkAndCreateRoleBindings(namespace *corev1.Namesp } adminBinding := &rbac.RoleBinding{} - adminBinding.Name = "admin" + adminBinding.Name = admin.Name adminBinding.Namespace = namespace.Name - adminBinding.RoleRef = rbac.RoleRef{Name: "admin", APIGroup: "rbac.authorization.k8s.io", Kind: "Role"} + adminBinding.RoleRef = rbac.RoleRef{Name: admin.Name, APIGroup: "rbac.authorization.k8s.io", Kind: "Role"} adminBinding.Subjects = workspaceAdminBinding.Subjects if creator.Name != "" { @@ -267,30 +273,33 @@ func (r *ReconcileNamespace) checkAndCreateRoleBindings(namespace *corev1.Namesp err = r.Get(context.TODO(), types.NamespacedName{Namespace: namespace.Name, Name: adminBinding.Name}, found) if errors.IsNotFound(err) { - log.Info("Creating default role binding", "namespace", namespace.Name, "name", adminBinding.Name) err = r.Create(context.TODO(), adminBinding) if err != nil { + klog.Errorf("creating role binding namespace: %s,role binding: %s, error: %s", namespace.Name, adminBinding.Name, err) return err } found = adminBinding } else if err != nil { + klog.Errorf("get role binding namespace: %s,role binding: %s, error: %s", namespace.Name, adminBinding.Name, err) return err } if !reflect.DeepEqual(found.RoleRef, adminBinding.RoleRef) { - log.Info("Deleting conflict role binding", "namespace", namespace.Name, "name", adminBinding.Name) err = r.Delete(context.TODO(), found) if err != nil { + klog.Errorf("deleting role binding namespace: %s, role binding: %s, error: %s", namespace.Name, adminBinding.Name, err) return err } - return fmt.Errorf("conflict role binding %s.%s, waiting for recreate", namespace.Name, adminBinding.Name) + err = fmt.Errorf("conflict role binding %s.%s, waiting for recreate", namespace.Name, adminBinding.Name) + klog.Errorf("conflict role binding namespace: %s, role binding: %s, error: %s", namespace.Name, adminBinding.Name, err) + return err } if !reflect.DeepEqual(found.Subjects, adminBinding.Subjects) { found.Subjects = adminBinding.Subjects - log.Info("Updating role binding", "namespace", namespace.Name, "name", adminBinding.Name) err = r.Update(context.TODO(), found) if err != nil { + klog.Errorf("updating role binding namespace: %s, role binding: %s, error: %s", namespace.Name, adminBinding.Name, err) return err } } @@ -304,17 +313,17 @@ func (r *ReconcileNamespace) checkAndCreateRoleBindings(namespace *corev1.Namesp } viewerBinding := &rbac.RoleBinding{} - viewerBinding.Name = "viewer" + viewerBinding.Name = viewer.Name viewerBinding.Namespace = namespace.Name - viewerBinding.RoleRef = rbac.RoleRef{Name: "viewer", APIGroup: "rbac.authorization.k8s.io", Kind: "Role"} + viewerBinding.RoleRef = rbac.RoleRef{Name: viewer.Name, APIGroup: "rbac.authorization.k8s.io", Kind: "Role"} viewerBinding.Subjects = workspaceViewerBinding.Subjects err = r.Get(context.TODO(), types.NamespacedName{Namespace: namespace.Name, Name: viewerBinding.Name}, found) if errors.IsNotFound(err) { - log.Info("Creating default role binding", "namespace", namespace.Name, "name", viewerBinding.Name) err = r.Create(context.TODO(), viewerBinding) if err != nil { + klog.Errorf("creating role binding namespace: %s, role binding: %s, error: %s", namespace.Name, viewerBinding.Name, err) return err } found = viewerBinding @@ -323,19 +332,21 @@ func (r *ReconcileNamespace) checkAndCreateRoleBindings(namespace *corev1.Namesp } if !reflect.DeepEqual(found.RoleRef, viewerBinding.RoleRef) { - log.Info("Deleting conflict role binding", "namespace", namespace.Name, "name", viewerBinding.Name) err = r.Delete(context.TODO(), found) if err != nil { + klog.Errorf("deleting conflict role binding namespace: %s, role binding: %s, %s", namespace.Name, viewerBinding.Name, err) return err } - return fmt.Errorf("conflict role binding %s.%s, waiting for recreate", namespace.Name, viewerBinding.Name) + err = fmt.Errorf("conflict role binding %s.%s, waiting for recreate", namespace.Name, viewerBinding.Name) + klog.Errorf("conflict role binding namespace: %s, role binding: %s, error: %s", namespace.Name, viewerBinding.Name, err) + return err } if !reflect.DeepEqual(found.Subjects, viewerBinding.Subjects) { found.Subjects = viewerBinding.Subjects - log.Info("Updating role binding", "namespace", namespace.Name, "name", viewerBinding.Name) err = r.Update(context.TODO(), found) if err != nil { + klog.Errorf("updating role binding namespace: %s, role binding: %s, error: %s", namespace.Name, viewerBinding.Name, err) return err } } @@ -360,8 +371,8 @@ func (r *ReconcileNamespace) checkAndCreateRuntime(namespace *corev1.Namespace) runtime := &openpitrix.RunTime{Name: namespace.Name, Zone: namespace.Name, Provider: "kubernetes", RuntimeCredential: cm.Data["config"]} - log.Info("Creating openpitrix runtime", "namespace", namespace.Name) if err := openpitrix.Client().CreateRuntime(runtime); err != nil { + klog.Errorf("creating openpitrix runtime namespace: %s, error: %s", namespace.Name, err) return err } @@ -375,14 +386,14 @@ func (r *ReconcileNamespace) deleteRuntime(namespace *corev1.Namespace) error { maxRetries := float64(3) for i := float64(0); i < maxRetries; i++ { time.Sleep(time.Duration(i*math.Pow(2, i)) * time.Second) - log.Info("Deleting openpitrix runtime", "namespace", namespace.Name, "runtime", runtimeId) + err := openpitrix.Client().DeleteRuntime(runtimeId) if err == nil || openpitrix.IsNotFound(err) || openpitrix.IsDeleted(err) { return nil } - log.Error(err, fmt.Sprintf("Deleteing openpitrix runtime failed: %v times left", maxRetries-i-1)) + klog.Errorf("delete openpitrix runtime: %v times left, error: %s", maxRetries-i-1, err) } } @@ -403,20 +414,22 @@ func (r *ReconcileNamespace) checkAndBindWorkspace(namespace *corev1.Namespace) err := r.Get(context.TODO(), types.NamespacedName{Name: workspaceName}, workspace) if err != nil { + // skip if workspace not found if errors.IsNotFound(err) { - log.Error(err, fmt.Sprintf("namespace %s bind workspace %s but not found", namespace.Name, workspaceName)) return nil } + klog.Errorf("bind workspace namespace: %s, workspace: %s, error: %s", namespace.Name, workspaceName, err) return err } if !metav1.IsControlledBy(namespace, workspace) { if err := controllerutil.SetControllerReference(workspace, namespace, r.scheme); err != nil { + klog.Errorf("bind workspace namespace: %s, workspace: %s, error: %s", namespace.Name, workspaceName, err) return err } - log.Info("Bind workspace", "namespace", namespace.Name, "workspace", workspaceName) err = r.Update(context.TODO(), namespace) if err != nil { + klog.Errorf("bind workspace namespace: %s, workspace: %s, error: %s", namespace.Name, workspaceName, err) return err } } @@ -431,23 +444,22 @@ func (r *ReconcileNamespace) checkAndCreateCephSecret(namespace *corev1.Namespac scList := &v1.StorageClassList{} err := r.List(context.TODO(), &client.ListOptions{}, scList) if err != nil { + klog.Errorln(err) return err } for _, sc := range scList.Items { if sc.Provisioner == "kubernetes.io/rbd" { - log.Info("would create Ceph user secret in storage class %s at namespace %s", sc.GetName(), newNsName) if secretName, ok := sc.Parameters["userSecretName"]; ok { secret := &corev1.Secret{} - r.Get(context.TODO(), types.NamespacedName{Namespace: core.NamespaceSystem, Name: secretName}, secret) + err = r.Get(context.TODO(), types.NamespacedName{Namespace: core.NamespaceSystem, Name: secretName}, secret) if err != nil { if errors.IsNotFound(err) { - log.Error(err, "cannot find secret in namespace %s, error: %s", core.NamespaceSystem, secretName) + klog.Errorf("cannot find secret %s in namespace %s, error: %s", secretName, core.NamespaceSystem, err) continue } - log.Error(err, fmt.Sprintf("failed to find secret in namespace %s", core.NamespaceSystem)) + klog.Errorf("failed to find secret in namespace %s, error: %s", core.NamespaceSystem, err) continue } - glog.Infof("succeed to find secret %s in namespace %s", secret.GetName(), secret.GetNamespace()) newSecret := &corev1.Secret{ TypeMeta: metav1.TypeMeta{ @@ -466,15 +478,14 @@ func (r *ReconcileNamespace) checkAndCreateCephSecret(namespace *corev1.Namespac StringData: secret.StringData, Type: secret.Type, } - log.Info(fmt.Sprintf("creating secret %s in namespace %s...", newSecret.GetName(), newSecret.GetNamespace())) err = r.Create(context.TODO(), newSecret) if err != nil { - log.Error(err, fmt.Sprintf("failed to create secret in namespace %s", newSecret.GetNamespace())) + klog.Errorf("failed to create secret in namespace %s,error: %s", newSecret.GetNamespace(), err) continue } } else { - log.Error(err, fmt.Sprintf("failed to find user secret name in storage class %s", sc.GetName())) + klog.Errorf("failed to find user secret name in storage class %s,error: %s", sc.GetName(), err) } } } @@ -492,12 +503,12 @@ func (r *ReconcileNamespace) deleteRouter(namespace string) error { if errors.IsNotFound(err) { return nil } - log.V(2).Info("get router service failed", err) + klog.V(6).Info("get router service failed", err) } err = r.Delete(context.TODO(), &found) if err != nil { - log.Error(err, "delete router failed") + klog.Error(err, "delete router failed") return err } @@ -508,16 +519,37 @@ func (r *ReconcileNamespace) deleteRouter(namespace string) error { if errors.IsNotFound(err) { return nil } - log.V(2).Info("get router deployment failed", err) + klog.V(6).Info("get router deployment failed", err) return err } err = r.Delete(context.TODO(), &deploy) if err != nil { - log.Error(err, "delete router deployment failed") + klog.Error(err, "delete router deployment failed") return err } return nil } + +func (r *ReconcileNamespace) deleteRoleBindings(namespace *corev1.Namespace) error { + klog.V(6).Info("deleting role bindings namespace: ", namespace.Name) + adminBinding := &rbac.RoleBinding{} + adminBinding.Name = admin.Name + adminBinding.Namespace = namespace.Name + err := r.Delete(context.TODO(), adminBinding) + if err != nil && !errors.IsNotFound(err) { + klog.Errorf("deleting role binding namespace: %s, role binding: %s,error: %s", namespace.Name, adminBinding.Name, err) + return err + } + viewerBinding := &rbac.RoleBinding{} + viewerBinding.Name = viewer.Name + viewerBinding.Namespace = namespace.Name + err = r.Delete(context.TODO(), viewerBinding) + if err != nil && !errors.IsNotFound(err) { + klog.Errorf("deleting role binding namespace: %s,role binding: %s,error: %s", namespace.Name, viewerBinding.Name, err) + return err + } + return nil +}