提交 ed224612 编写于 作者: H hongming 提交者: zryfish

fix: runtime release

Signed-off-by: Nhongming <talonwan@yunify.com>
上级 e9402059
...@@ -20,11 +20,14 @@ package v1alpha2 ...@@ -20,11 +20,14 @@ package v1alpha2
import ( import (
"github.com/emicklei/go-restful" "github.com/emicklei/go-restful"
"github.com/emicklei/go-restful-openapi" "github.com/emicklei/go-restful-openapi"
rbacv1 "k8s.io/api/rbac/v1"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"kubesphere.io/kubesphere/pkg/apiserver/iam" "kubesphere.io/kubesphere/pkg/apiserver/iam"
"kubesphere.io/kubesphere/pkg/apiserver/runtime" "kubesphere.io/kubesphere/pkg/apiserver/runtime"
"kubesphere.io/kubesphere/pkg/errors" "kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models" "kubesphere.io/kubesphere/pkg/models"
"kubesphere.io/kubesphere/pkg/models/iam/policy"
"net/http"
) )
const GroupName = "iam.kubesphere.io" const GroupName = "iam.kubesphere.io"
...@@ -40,181 +43,220 @@ func addWebService(c *restful.Container) error { ...@@ -40,181 +43,220 @@ func addWebService(c *restful.Container) error {
tags := []string{"IAM"} tags := []string{"IAM"}
ws := runtime.NewWebService(GroupVersion) ws := runtime.NewWebService(GroupVersion)
ok := "ok"
pageableUserList := struct {
Items []models.User `json:"items"`
TotalCount int `json:"total_count"`
}{}
ws.Route(ws.POST("/authenticate"). ws.Route(ws.POST("/authenticate").
To(iam.TokenReviewHandler). To(iam.TokenReviewHandler).
Doc("Token review"). Doc("TokenReview attempts to authenticate a token to a known user. Note: TokenReview requests may be cached by the webhook token authenticator plugin in the kube-apiserver.").
Reads(iam.TokenReview{}). Reads(iam.TokenReview{}).
Writes(iam.TokenReview{}). Returns(http.StatusOK, ok, iam.TokenReview{}).
Doc("k8s token review").
Metadata(restfulspec.KeyOpenAPITags, tags)) Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.POST("/login"). ws.Route(ws.POST("/login").
To(iam.LoginHandler). To(iam.LoginHandler).
Doc("User login"). Doc("KubeSphere APIs support token-based authentication via the Authtoken request header. The POST Login API is used to retrieve the authentication token. After the authentication token is obtained, it must be inserted into the Authtoken header for all requests.").
Reads(iam.LoginRequest{}). Reads(iam.LoginRequest{}).
Writes(models.Token{}). Returns(http.StatusOK, ok, models.Token{}).
Metadata(restfulspec.KeyOpenAPITags, tags)) Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/users/{username}"). ws.Route(ws.GET("/users/{username}").
To(iam.DescribeUser). To(iam.DescribeUser).
Doc("User detail"). Doc("Describes the specified user.").
Param(ws.PathParameter("username", "username")). Param(ws.PathParameter("username", "username")).
Writes(models.User{}). Returns(http.StatusOK, ok, models.User{}).
Metadata(restfulspec.KeyOpenAPITags, tags)) Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.POST("/users"). ws.Route(ws.POST("/users").
To(iam.CreateUser). To(iam.CreateUser).
Doc("Create a user account.").
Reads(models.User{}). Reads(models.User{}).
Writes(errors.Error{}). Returns(http.StatusOK, ok, errors.Error{}).
Doc("Create user").
Metadata(restfulspec.KeyOpenAPITags, tags)) Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.DELETE("/users/{name}"). ws.Route(ws.DELETE("/users/{name}").
To(iam.DeleteUser). To(iam.DeleteUser).
Doc("Remove a specified user.").
Param(ws.PathParameter("name", "username")). Param(ws.PathParameter("name", "username")).
Doc("Delete user"). Returns(http.StatusOK, ok, errors.Error{}).
Writes(errors.Error{}).
Metadata(restfulspec.KeyOpenAPITags, tags)) Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.PUT("/users/{name}"). ws.Route(ws.PUT("/users/{name}").
To(iam.UpdateUser). To(iam.UpdateUser).
Doc("Updates information about the specified user.").
Param(ws.PathParameter("name", "username")). Param(ws.PathParameter("name", "username")).
Reads(models.User{}). Reads(models.User{}).
Writes(errors.Error{}). Returns(http.StatusOK, ok, errors.Error{}).
Doc("Update user").
Metadata(restfulspec.KeyOpenAPITags, tags)) Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/users/{name}/log"). ws.Route(ws.GET("/users/{name}/log").
To(iam.UserLoginLog). To(iam.UserLoginLog).
Doc("This method is used to retrieve the \"login logs\" for the specified user.").
Param(ws.PathParameter("name", "username")). Param(ws.PathParameter("name", "username")).
Doc("User login log"). Returns(http.StatusOK, ok, struct {
Writes([]map[string]string{}). LoginTime string `json:"login_time"`
LoginIP string `json:"login_ip"`
}{}).
Metadata(restfulspec.KeyOpenAPITags, tags)) Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/users"). ws.Route(ws.GET("/users").
To(iam.ListUsers). To(iam.ListUsers).
Doc("User list"). Doc("List all users.").
Writes(models.PageableResponse{}). Returns(http.StatusOK, ok, pageableUserList).
Metadata(restfulspec.KeyOpenAPITags, tags)) Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/groups"). ws.Route(ws.GET("/groups").
To(iam.ListGroups). To(iam.ListGroups).
Writes([]models.Group{}). Doc("List all user groups.").
Doc("User group list"). Returns(http.StatusOK, ok, []models.Group{}).
Metadata(restfulspec.KeyOpenAPITags, tags)) Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/groups/{path}"). ws.Route(ws.GET("/groups/{path}").
To(iam.DescribeGroup). To(iam.DescribeGroup).
Param(ws.PathParameter("path", "group path")). Doc("Describes the specified user group.").
Doc("User group detail"). Param(ws.PathParameter("path", "user group path separated by colon.")).
Returns(http.StatusOK, ok, models.Group{}).
Metadata(restfulspec.KeyOpenAPITags, tags)) Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/groups/{path}/users"). ws.Route(ws.GET("/groups/{path}/users").
To(iam.ListGroupUsers). To(iam.ListGroupUsers).
Param(ws.PathParameter("path", "group path")). Doc("List all users in the specified user group.").
Doc("Group user list"). Param(ws.PathParameter("path", "user group path separated by colon.")).
Returns(http.StatusOK, ok, []models.User{}).
Metadata(restfulspec.KeyOpenAPITags, tags)) Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.POST("/groups"). ws.Route(ws.POST("/groups").
To(iam.CreateGroup). To(iam.CreateGroup).
Doc("Create a user group.").
Reads(models.Group{}). Reads(models.Group{}).
Doc("Create user group"). Returns(http.StatusOK, ok, models.Group{}).
Metadata(restfulspec.KeyOpenAPITags, tags)) Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.DELETE("/groups/{path}"). ws.Route(ws.DELETE("/groups/{path}").
To(iam.DeleteGroup). To(iam.DeleteGroup).
Param(ws.PathParameter("path", "group path")). Doc("Delete a user group.").
Doc("Delete user group"). Param(ws.PathParameter("path", "user group path separated by colon.")).
Returns(http.StatusOK, ok, errors.Error{}).
Metadata(restfulspec.KeyOpenAPITags, tags)) Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.PUT("/groups/{path}"). ws.Route(ws.PUT("/groups/{path}").
To(iam.UpdateGroup). To(iam.UpdateGroup).
Param(ws.PathParameter("path", "group path")). Doc("Updates information about the user group.").
Doc("Update user group"). Param(ws.PathParameter("path", "user group path separated by colon.")).
Reads(models.Group{}).
Returns(http.StatusOK, ok, models.Group{}).
Metadata(restfulspec.KeyOpenAPITags, tags)) Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/users/{username}/roles"). ws.Route(ws.GET("/users/{username}/roles").
To(iam.ListUserRoles). To(iam.ListUserRoles).
Doc("This method is used to retrieve all the roles that are assigned to the user.").
Param(ws.PathParameter("username", "username")). Param(ws.PathParameter("username", "username")).
Doc("Get user role list"). Returns(http.StatusOK, ok, iam.RoleList{}).
Metadata(restfulspec.KeyOpenAPITags, tags)) Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/namespaces/{namespace}/roles"). ws.Route(ws.GET("/namespaces/{namespace}/roles").
To(iam.ListRoles). To(iam.ListRoles).
Param(ws.PathParameter("namespace", "namespace")). Doc("This method is used to retrieve the roles that are assigned to the user in the specified namespace.").
Doc("Get role list"). Param(ws.PathParameter("namespace", "kubernetes namespace")).
Returns(http.StatusOK, ok, struct {
Items []rbacv1.Role `json:"items"`
TotalCount int `json:"total_count"`
}{}).
Metadata(restfulspec.KeyOpenAPITags, tags)) Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/clusterroles"). ws.Route(ws.GET("/clusterroles").
To(iam.ListClusterRoles). To(iam.ListClusterRoles).
Doc("Get cluster role list"). Doc("List all cluster roles.").
Returns(http.StatusOK, ok, struct {
Items []rbacv1.ClusterRole `json:"items"`
TotalCount int `json:"total_count"`
}{}).
Metadata(restfulspec.KeyOpenAPITags, tags)) Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/namespaces/{namespace}/roles/{role}/users"). ws.Route(ws.GET("/namespaces/{namespace}/roles/{role}/users").
To(iam.ListRoleUsers). To(iam.ListRoleUsers).
Param(ws.PathParameter("namespace", "namespace")). Doc("This method is used to retrieve the users that are bind the role in the specified namespace.").
Param(ws.PathParameter("namespace", "kubernetes namespace")).
Param(ws.PathParameter("role", "role name")). Param(ws.PathParameter("role", "role name")).
Doc("Get user list by role"). Returns(http.StatusOK, ok, []models.User{}).
Metadata(restfulspec.KeyOpenAPITags, tags)) Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/namespaces/{namespace}/users"). ws.Route(ws.GET("/namespaces/{namespace}/users").
To(iam.ListNamespaceUsers). To(iam.ListNamespaceUsers).
Param(ws.PathParameter("namespace", "namespace")). Doc("List all users in the specified namespace").
Doc("Get user list by namespace"). Param(ws.PathParameter("namespace", "kubernetes namespace")).
Returns(http.StatusOK, ok, []models.User{}).
Metadata(restfulspec.KeyOpenAPITags, tags)) Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/clusterroles/{clusterrole}/users"). ws.Route(ws.GET("/clusterroles/{clusterrole}/users").
To(iam.ListClusterRoleUsers). To(iam.ListClusterRoleUsers).
Doc("List all users that are bind the cluster role.").
Param(ws.PathParameter("clusterrole", "cluster role name")). Param(ws.PathParameter("clusterrole", "cluster role name")).
Doc("Get user list by cluster role"). Returns(http.StatusOK, ok, pageableUserList).
Metadata(restfulspec.KeyOpenAPITags, tags)) Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/clusterroles/{clusterrole}/rules"). ws.Route(ws.GET("/clusterroles/{clusterrole}/rules").
To(iam.ListClusterRoleRules). To(iam.ListClusterRoleRules).
Doc("List all policy rules of the specified cluster role.").
Param(ws.PathParameter("clusterrole", "cluster role name")). Param(ws.PathParameter("clusterrole", "cluster role name")).
Doc("Get cluster role detail"). Returns(http.StatusOK, ok, []models.SimpleRule{}).
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/namespaces/{namespace}/roles/{role}/rules").
To(iam.ListRoleRules).
Doc("List all policy rules of the specified role.").
Param(ws.PathParameter("namespace", "kubernetes namespace")).
Param(ws.PathParameter("role", "role name")).
Returns(http.StatusOK, ok, []models.SimpleRule{}).
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/devops/{devops}/roles/{role}/rules").
To(iam.ListDevopsRoleRules).
Doc("List all policy rules of the specified role.").
Param(ws.PathParameter("devops", "devops project id")).
Param(ws.PathParameter("role", "devops role name")).
Returns(http.StatusOK, ok, []models.SimpleRule{}).
Metadata(restfulspec.KeyOpenAPITags, tags)) Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/rulesmapping/clusterroles"). ws.Route(ws.GET("/rulesmapping/clusterroles").
To(iam.ClusterRulesMapping). To(iam.ClusterRulesMapping).
Doc("Get cluster role policy rules mapping"). Doc("Get the mapping relationships between cluster roles and policy rules.").
Returns(http.StatusOK, ok, policy.ClusterRoleRuleMapping).
Metadata(restfulspec.KeyOpenAPITags, tags)) Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/rulesmapping/roles"). ws.Route(ws.GET("/rulesmapping/roles").
To(iam.RulesMapping). To(iam.RulesMapping).
Doc("Get role policy rules mapping"). Doc("Get the mapping relationships between namespaced roles and policy rules.").
Returns(http.StatusOK, ok, policy.RoleRuleMapping).
Metadata(restfulspec.KeyOpenAPITags, tags)) Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/workspaces/{workspace}/roles"). ws.Route(ws.GET("/workspaces/{workspace}/roles").
To(iam.ListWorkspaceRoles). To(iam.ListWorkspaceRoles).
Doc("List all workspace roles.").
Param(ws.PathParameter("workspace", "workspace name")). Param(ws.PathParameter("workspace", "workspace name")).
Doc("List workspace role"). Returns(http.StatusOK, ok, struct {
Items []rbacv1.ClusterRole `json:"items"`
TotalCount int `json:"total_count"`
}{}).
Metadata(restfulspec.KeyOpenAPITags, tags)) Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/workspaces/{workspace}/roles/{role}"). ws.Route(ws.GET("/workspaces/{workspace}/roles/{role}").
To(iam.DescribeWorkspaceRole). To(iam.DescribeWorkspaceRole).
Doc("Describes the workspace role.").
Param(ws.PathParameter("workspace", "workspace name")). Param(ws.PathParameter("workspace", "workspace name")).
Param(ws.PathParameter("role", "workspace role name")). Param(ws.PathParameter("role", "workspace role name")).
Doc("Describe workspace role"). Returns(http.StatusOK, ok, rbacv1.ClusterRole{}).
Metadata(restfulspec.KeyOpenAPITags, tags)) Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/workspaces/{workspace}/roles/{role}/rules"). ws.Route(ws.GET("/workspaces/{workspace}/roles/{role}/rules").
To(iam.ListWorkspaceRoleRules). To(iam.ListWorkspaceRoleRules).
Doc("List all policy rules of the specified workspace role.").
Param(ws.PathParameter("workspace", "workspace name")). Param(ws.PathParameter("workspace", "workspace name")).
Param(ws.PathParameter("role", "workspace role name")). Param(ws.PathParameter("role", "workspace role name")).
Doc("Get workspace role policy rules"). Returns(http.StatusOK, ok, []models.SimpleRule{}).
Metadata(restfulspec.KeyOpenAPITags, tags)) Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/workspaces/{workspace}/members"). ws.Route(ws.GET("/workspaces/{workspace}/members").
To(iam.ListWorkspaceUsers). To(iam.ListWorkspaceUsers).
Doc("List all members in the specified workspace.").
Param(ws.PathParameter("workspace", "workspace name")). Param(ws.PathParameter("workspace", "workspace name")).
Doc("Get workspace member list"). Returns(http.StatusOK, ok, pageableUserList).
Metadata(restfulspec.KeyOpenAPITags, tags)) Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.POST("/workspaces/{workspace}/members"). ws.Route(ws.POST("/workspaces/{workspace}/members").
To(iam.InviteUser). To(iam.InviteUser).
Doc("Invite members to a workspace.").
Param(ws.PathParameter("workspace", "workspace name")). Param(ws.PathParameter("workspace", "workspace name")).
Doc("Add user to workspace"). Reads(models.User{}).
Returns(http.StatusOK, ok, errors.Error{}).
Metadata(restfulspec.KeyOpenAPITags, tags)) Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.DELETE("/workspaces/{workspace}/members/{username}"). ws.Route(ws.DELETE("/workspaces/{workspace}/members/{username}").
To(iam.RemoveUser). To(iam.RemoveUser).
Doc("Remove members from workspace.").
Param(ws.PathParameter("workspace", "workspace name")). Param(ws.PathParameter("workspace", "workspace name")).
Param(ws.PathParameter("name", "username")). Param(ws.PathParameter("name", "username")).
Doc("Remove user from workspace"). Returns(http.StatusOK, ok, errors.Error{}).
Metadata(restfulspec.KeyOpenAPITags, tags)) Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/workspaces/{workspace}/members/{username}"). ws.Route(ws.GET("/workspaces/{workspace}/members/{username}").
To(iam.DescribeWorkspaceUser). To(iam.DescribeWorkspaceUser).
Doc("Describes the specified user.").
Param(ws.PathParameter("workspace", "workspace name")). Param(ws.PathParameter("workspace", "workspace name")).
Param(ws.PathParameter("username", "username")). Param(ws.PathParameter("username", "username")).
Doc("Describe user in workspace"). Returns(http.StatusOK, ok, models.User{}).
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/namespaces/{namespace}/roles/{role}/rules").
To(iam.ListRoleRules).
Param(ws.PathParameter("namespace", "namespace")).
Param(ws.PathParameter("role", "role name")).
Doc("Get namespace role policy rules").
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/devops/{devops}/roles/{role}/rules").
To(iam.ListDevopsRoleRules).
Param(ws.PathParameter("devops", "devops project id")).
Param(ws.PathParameter("role", "devops role name")).
Doc("Get devops role policy rules").
Metadata(restfulspec.KeyOpenAPITags, tags)) Metadata(restfulspec.KeyOpenAPITags, tags))
c.Add(ws) c.Add(ws)
return nil return nil
......
...@@ -30,7 +30,7 @@ import ( ...@@ -30,7 +30,7 @@ import (
"kubesphere.io/kubesphere/pkg/models/iam/policy" "kubesphere.io/kubesphere/pkg/models/iam/policy"
) )
type roleList struct { type RoleList struct {
ClusterRoles []*v1.ClusterRole `json:"clusterRole" protobuf:"bytes,2,rep,name=clusterRoles"` ClusterRoles []*v1.ClusterRole `json:"clusterRole" protobuf:"bytes,2,rep,name=clusterRoles"`
Roles []*v1.Role `json:"roles" protobuf:"bytes,2,rep,name=roles"` Roles []*v1.Role `json:"roles" protobuf:"bytes,2,rep,name=roles"`
} }
...@@ -132,7 +132,7 @@ func ListUserRoles(req *restful.Request, resp *restful.Response) { ...@@ -132,7 +132,7 @@ func ListUserRoles(req *restful.Request, resp *restful.Response) {
return return
} }
roleList := roleList{} roleList := RoleList{}
roleList.Roles = roles roleList.Roles = roles
roleList.ClusterRoles = clusterRoles roleList.ClusterRoles = clusterRoles
......
...@@ -35,6 +35,8 @@ import ( ...@@ -35,6 +35,8 @@ import (
"kubesphere.io/kubesphere/pkg/constants" "kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/simple/client/openpitrix" "kubesphere.io/kubesphere/pkg/simple/client/openpitrix"
"kubesphere.io/kubesphere/pkg/utils/k8sutil" "kubesphere.io/kubesphere/pkg/utils/k8sutil"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"math"
"reflect" "reflect"
"sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller" "sigs.k8s.io/controller-runtime/pkg/controller"
...@@ -44,6 +46,7 @@ import ( ...@@ -44,6 +46,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/reconcile" "sigs.k8s.io/controller-runtime/pkg/reconcile"
logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
"sigs.k8s.io/controller-runtime/pkg/source" "sigs.k8s.io/controller-runtime/pkg/source"
"time"
) )
const ( const (
...@@ -115,25 +118,47 @@ func (r *ReconcileNamespace) Reconcile(request reconcile.Request) (reconcile.Res ...@@ -115,25 +118,47 @@ func (r *ReconcileNamespace) Reconcile(request reconcile.Request) (reconcile.Res
if errors.IsNotFound(err) { if errors.IsNotFound(err) {
// Object not found, return. Created objects are automatically garbage collected. // Object not found, return. Created objects are automatically garbage collected.
// For additional cleanup logic use finalizers. // For additional cleanup logic use finalizers.
// The object is being deleted
// our finalizer is present, so lets handle our external dependency
return reconcile.Result{}, nil return reconcile.Result{}, nil
} }
// Error reading the object - requeue the request. // Error reading the object - requeue the request.
return reconcile.Result{}, err return reconcile.Result{}, err
} }
if !instance.ObjectMeta.DeletionTimestamp.IsZero() { // name of your custom finalizer
// The object is being deleted finalizer := "finalizers.kubesphere.io/namespaces"
if instance.ObjectMeta.DeletionTimestamp.IsZero() {
// The object is not being deleted, so if it does not have our finalizer,
// then lets add the finalizer and update the object.
if !sliceutil.HasString(instance.ObjectMeta.Finalizers, finalizer) {
instance.ObjectMeta.Finalizers = append(instance.ObjectMeta.Finalizers, finalizer)
if err := r.Update(context.Background(), instance); err != nil {
return reconcile.Result{}, err
}
}
} else {
// The object is being deleted
if sliceutil.HasString(instance.ObjectMeta.Finalizers, finalizer) {
if err := r.deleteRouter(instance.Name); err != nil { if err := r.deleteRouter(instance.Name); err != nil {
return reconcile.Result{}, err return reconcile.Result{}, err
} }
if err := r.deleteRuntime(instance); err != nil { // delete runtime in the background, retry 3 times
// if fail to delete the external dependency here, return with error go r.deleteRuntime(instance)
// so that it can be retried
// remove our finalizer from the list and update it.
instance.ObjectMeta.Finalizers = sliceutil.RemoveString(instance.ObjectMeta.Finalizers, func(item string) bool {
return item == finalizer
})
if err := r.Update(context.Background(), instance); err != nil {
return reconcile.Result{}, err return reconcile.Result{}, err
} }
}
// Our finalizer has finished, so the reconciler can do nothing.
return reconcile.Result{}, nil return reconcile.Result{}, nil
} }
...@@ -347,9 +372,17 @@ func (r *ReconcileNamespace) checkAndCreateRuntime(namespace *corev1.Namespace) ...@@ -347,9 +372,17 @@ func (r *ReconcileNamespace) checkAndCreateRuntime(namespace *corev1.Namespace)
func (r *ReconcileNamespace) deleteRuntime(namespace *corev1.Namespace) error { func (r *ReconcileNamespace) deleteRuntime(namespace *corev1.Namespace) error {
if runtimeId := namespace.Annotations[constants.OpenPitrixRuntimeAnnotationKey]; runtimeId != "" { if runtimeId := namespace.Annotations[constants.OpenPitrixRuntimeAnnotationKey]; runtimeId != "" {
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) log.Info("Deleting openpitrix runtime", "namespace", namespace.Name, "runtime", runtimeId)
if err := openpitrix.Client().DeleteRuntime(runtimeId); err != nil { err := openpitrix.Client().DeleteRuntime(runtimeId)
return err
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))
} }
} }
......
...@@ -284,7 +284,7 @@ func ListUsers(conditions *params.Conditions, orderBy string, reverse bool, limi ...@@ -284,7 +284,7 @@ func ListUsers(conditions *params.Conditions, orderBy string, reverse bool, limi
defer conn.Close() defer conn.Close()
pageControl := ldap.NewControlPaging(80) pageControl := ldap.NewControlPaging(1000)
users := make([]models.User, 0) users := make([]models.User, 0)
......
...@@ -905,7 +905,7 @@ var ( ...@@ -905,7 +905,7 @@ var (
Rules: []v1.PolicyRule{ Rules: []v1.PolicyRule{
{ {
Verbs: []string{"get", "list"}, Verbs: []string{"get", "list"},
APIGroups: []string{"resources.kubesphere.io"}, APIGroups: []string{"resources.kubesphere.io", "app.k8s.io"},
Resources: []string{"applications"}, Resources: []string{"applications"},
}, { }, {
Verbs: []string{"get", "list"}, Verbs: []string{"get", "list"},
...@@ -927,7 +927,7 @@ var ( ...@@ -927,7 +927,7 @@ var (
Rules: []v1.PolicyRule{ Rules: []v1.PolicyRule{
{ {
Verbs: []string{"create", "update", "patch"}, Verbs: []string{"create", "update", "patch"},
APIGroups: []string{"resources.kubesphere.io"}, APIGroups: []string{"resources.kubesphere.io", "app.k8s.io"},
Resources: []string{"applications"}, Resources: []string{"applications"},
}, { }, {
Verbs: []string{"create", "update", "patch"}, Verbs: []string{"create", "update", "patch"},
...@@ -940,7 +940,7 @@ var ( ...@@ -940,7 +940,7 @@ var (
Rules: []v1.PolicyRule{ Rules: []v1.PolicyRule{
{ {
Verbs: []string{"delete"}, Verbs: []string{"delete"},
APIGroups: []string{"resources.kubesphere.io"}, APIGroups: []string{"resources.kubesphere.io", "app.k8s.io"},
Resources: []string{"applications"}, Resources: []string{"applications"},
}, },
{ {
......
...@@ -24,7 +24,9 @@ import ( ...@@ -24,7 +24,9 @@ import (
"fmt" "fmt"
"github.com/golang/glog" "github.com/golang/glog"
"io/ioutil" "io/ioutil"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"net/http" "net/http"
"strings"
"sync" "sync"
) )
...@@ -48,6 +50,10 @@ type Interface interface { ...@@ -48,6 +50,10 @@ type Interface interface {
CreateRuntime(runtime *RunTime) error CreateRuntime(runtime *RunTime) error
DeleteRuntime(runtimeId string) error DeleteRuntime(runtimeId string) error
} }
type cluster struct {
Status string `json:"status"`
ClusterId string `json:"cluster_id"`
}
type Error struct { type Error struct {
status int status int
...@@ -78,14 +84,12 @@ func (c client) CreateRuntime(runtime *RunTime) error { ...@@ -78,14 +84,12 @@ func (c client) CreateRuntime(runtime *RunTime) error {
data, err := json.Marshal(runtime) data, err := json.Marshal(runtime)
if err != nil { if err != nil {
glog.Error(err)
return err return err
} }
req, err := http.NewRequest(http.MethodPost, fmt.Sprintf("%s/v1/runtimes", openpitrixAPIServer), bytes.NewReader(data)) req, err := http.NewRequest(http.MethodPost, fmt.Sprintf("%s/v1/runtimes", openpitrixAPIServer), bytes.NewReader(data))
if err != nil { if err != nil {
glog.Error(err)
return err return err
} }
req.Header.Add("Content-Type", "application/json") req.Header.Add("Content-Type", "application/json")
...@@ -106,30 +110,46 @@ func (c client) CreateRuntime(runtime *RunTime) error { ...@@ -106,30 +110,46 @@ func (c client) CreateRuntime(runtime *RunTime) error {
} }
if resp.StatusCode > http.StatusOK { if resp.StatusCode > http.StatusOK {
return Error{resp.StatusCode, string(data)} err = Error{resp.StatusCode, string(data)}
glog.Error(err)
return err
} }
return nil return nil
} }
func (c client) DeleteRuntime(runtimeId string) error { func (c client) deleteClusters(clusters []cluster) error {
data := []byte(fmt.Sprintf(`{"runtime_id":"%s"}`, runtimeId)) clusterId := make([]string, 0)
req, err := http.NewRequest(http.MethodDelete, fmt.Sprintf("%s/v1/runtimes", openpitrixAPIServer), bytes.NewReader(data))
if err != nil { for _, cluster := range clusters {
glog.Error(err) if cluster.Status != "deleted" && cluster.Status != "deleting" && !sliceutil.HasString(clusterId, cluster.ClusterId) {
clusterId = append(clusterId, cluster.ClusterId)
}
}
return err if len(clusterId) == 0 {
return nil
}
deleteRequest := struct {
ClusterId []string `json:"cluster_id"`
}{
ClusterId: clusterId,
} }
data, _ := json.Marshal(deleteRequest)
req, err := http.NewRequest(http.MethodPost, fmt.Sprintf("%s/v1/clusters/delete", openpitrixAPIServer), bytes.NewReader(data))
if err != nil {
return err
}
req.Header.Add("Authorization", openpitrixProxyToken) req.Header.Add("Authorization", openpitrixProxyToken)
resp, err := c.client.Do(req) resp, err := c.client.Do(req)
if err != nil { if err != nil {
glog.Error(err) glog.Error(err)
return err return err
} }
defer resp.Body.Close() defer resp.Body.Close()
data, err = ioutil.ReadAll(resp.Body) data, err = ioutil.ReadAll(resp.Body)
...@@ -139,8 +159,110 @@ func (c client) DeleteRuntime(runtimeId string) error { ...@@ -139,8 +159,110 @@ func (c client) DeleteRuntime(runtimeId string) error {
} }
if resp.StatusCode > http.StatusOK { if resp.StatusCode > http.StatusOK {
return Error{resp.StatusCode, string(data)} err = Error{resp.StatusCode, string(data)}
glog.Error(err)
return err
} }
return nil return nil
} }
func (c client) listClusters(runtimeId string) ([]cluster, error) {
limit := 200
offset := 0
clusters := make([]cluster, 0)
for {
req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/v1/clusters?runtime_id=%s&limit=%d&offset=%d", openpitrixAPIServer, runtimeId, limit, offset), nil)
if err != nil {
glog.Error(err)
return nil, err
}
req.Header.Add("Authorization", openpitrixProxyToken)
resp, err := c.client.Do(req)
if err != nil {
glog.Error(err)
return nil, err
}
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
glog.Error(err)
return nil, err
}
resp.Body.Close()
if resp.StatusCode > http.StatusOK {
err = Error{resp.StatusCode, string(data)}
glog.Error(err)
return nil, err
}
listClusterResponse := struct {
TotalCount int `json:"total_count"`
ClusterSet []cluster `json:"cluster_set"`
}{}
err = json.Unmarshal(data, &listClusterResponse)
if err != nil {
glog.Error(err)
return nil, err
}
clusters = append(clusters, listClusterResponse.ClusterSet...)
if listClusterResponse.TotalCount <= limit+offset {
break
}
offset += limit
}
return clusters, nil
}
func (c client) DeleteRuntime(runtimeId string) error {
clusters, err := c.listClusters(runtimeId)
if err != nil {
glog.Error(err)
return err
}
err = c.deleteClusters(clusters)
if err != nil {
glog.Error(err)
return err
}
return nil
}
func IsNotFound(err error) bool {
if e, ok := err.(Error); ok {
if e.status == http.StatusNotFound {
return true
}
if strings.Contains(e.message, "not exist") {
return true
}
if strings.Contains(e.message, "not found") {
return true
}
}
return false
}
func IsDeleted(err error) bool {
if e, ok := err.(Error); ok {
if strings.Contains(e.message, "is [deleted]") {
return true
}
}
return false
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册