[WIP] API refactor (#1737)
* refactor openpitrix API Signed-off-by: hongming <talonwan@yunify.com> * add openpitrix mock client Signed-off-by: hongming <talonwan@yunify.com> * refactor tenant API Signed-off-by: hongming <talonwan@yunify.com> * refactor IAM API Signed-off-by: hongming <talonwan@yunify.com> * refactor IAM API Signed-off-by: hongming <talonwan@yunify.com>
This commit is contained in:
@@ -25,14 +25,16 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/client-go/informers"
|
||||
"k8s.io/klog"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/resources"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam/policy"
|
||||
"kubesphere.io/kubesphere/pkg/models/kubectl"
|
||||
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
|
||||
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2/clusterrole"
|
||||
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2/resource"
|
||||
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2/role"
|
||||
"kubesphere.io/kubesphere/pkg/server/params"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client"
|
||||
"kubesphere.io/kubesphere/pkg/utils/k8sutil"
|
||||
@@ -47,12 +49,30 @@ const (
|
||||
NamespaceViewerRoleBindName = "viewer"
|
||||
)
|
||||
|
||||
func GetDevopsRoleSimpleRules(role string) []models.SimpleRule {
|
||||
var rules []models.SimpleRule
|
||||
type AccessManagementInterface interface {
|
||||
GetDevopsRoleSimpleRules(role string) []SimpleRule
|
||||
ListRoleBindings(namespace string, role string) ([]*rbacv1.RoleBinding, error)
|
||||
CreateClusterRoleBinding(username string, clusterRole string) error
|
||||
}
|
||||
|
||||
type amOperator struct {
|
||||
informers informers.SharedInformerFactory
|
||||
resources resource.ResourceGetter
|
||||
}
|
||||
|
||||
func newAMOperator(informers informers.SharedInformerFactory) AccessManagementInterface {
|
||||
resourceGetter := resource.ResourceGetter{}
|
||||
resourceGetter.Add(v1alpha2.Role, role.NewRoleSearcher(informers))
|
||||
resourceGetter.Add(v1alpha2.ClusterRoles, clusterrole.NewClusterRoleSearcher(informers))
|
||||
return &amOperator{informers: informers, resources: resourceGetter}
|
||||
}
|
||||
|
||||
func (am *amOperator) GetDevopsRoleSimpleRules(role string) []SimpleRule {
|
||||
var rules []SimpleRule
|
||||
|
||||
switch role {
|
||||
case "developer":
|
||||
rules = []models.SimpleRule{
|
||||
rules = []SimpleRule{
|
||||
{Name: "pipelines", Actions: []string{"view", "trigger"}},
|
||||
{Name: "roles", Actions: []string{"view"}},
|
||||
{Name: "members", Actions: []string{"view"}},
|
||||
@@ -60,7 +80,7 @@ func GetDevopsRoleSimpleRules(role string) []models.SimpleRule {
|
||||
}
|
||||
break
|
||||
case "owner":
|
||||
rules = []models.SimpleRule{
|
||||
rules = []SimpleRule{
|
||||
{Name: "pipelines", Actions: []string{"create", "edit", "view", "delete", "trigger"}},
|
||||
{Name: "roles", Actions: []string{"view"}},
|
||||
{Name: "members", Actions: []string{"create", "edit", "view", "delete"}},
|
||||
@@ -69,7 +89,7 @@ func GetDevopsRoleSimpleRules(role string) []models.SimpleRule {
|
||||
}
|
||||
break
|
||||
case "maintainer":
|
||||
rules = []models.SimpleRule{
|
||||
rules = []SimpleRule{
|
||||
{Name: "pipelines", Actions: []string{"create", "edit", "view", "delete", "trigger"}},
|
||||
{Name: "roles", Actions: []string{"view"}},
|
||||
{Name: "members", Actions: []string{"view"}},
|
||||
@@ -80,7 +100,7 @@ func GetDevopsRoleSimpleRules(role string) []models.SimpleRule {
|
||||
case "reporter":
|
||||
fallthrough
|
||||
default:
|
||||
rules = []models.SimpleRule{
|
||||
rules = []SimpleRule{
|
||||
{Name: "pipelines", Actions: []string{"view"}},
|
||||
{Name: "roles", Actions: []string{"view"}},
|
||||
{Name: "members", Actions: []string{"view"}},
|
||||
@@ -92,14 +112,14 @@ func GetDevopsRoleSimpleRules(role string) []models.SimpleRule {
|
||||
}
|
||||
|
||||
// Get user roles in namespace
|
||||
func GetUserRoles(namespace, username string) ([]*rbacv1.Role, error) {
|
||||
clusterRoleLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoles().Lister()
|
||||
roleBindingLister := informers.SharedInformerFactory().Rbac().V1().RoleBindings().Lister()
|
||||
roleLister := informers.SharedInformerFactory().Rbac().V1().Roles().Lister()
|
||||
func (am *amOperator) GetUserRoles(namespace, username string) ([]*rbacv1.Role, error) {
|
||||
clusterRoleLister := am.informers.Rbac().V1().ClusterRoles().Lister()
|
||||
roleBindingLister := am.informers.Rbac().V1().RoleBindings().Lister()
|
||||
roleLister := am.informers.Rbac().V1().Roles().Lister()
|
||||
roleBindings, err := roleBindingLister.RoleBindings(namespace).List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln("get role bindings", namespace, err)
|
||||
klog.Errorln(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -114,7 +134,7 @@ func GetUserRoles(namespace, username string) ([]*rbacv1.Role, error) {
|
||||
klog.Warningf("cluster role %s not found but bind user %s in namespace %s", roleBinding.RoleRef.Name, username, namespace)
|
||||
continue
|
||||
} else {
|
||||
klog.Errorln("get cluster role", roleBinding.RoleRef.Name, err)
|
||||
klog.Errorln(err)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
@@ -132,7 +152,7 @@ func GetUserRoles(namespace, username string) ([]*rbacv1.Role, error) {
|
||||
klog.Warningf("namespace %s role %s not found, but bind user %s", namespace, roleBinding.RoleRef.Name, username)
|
||||
continue
|
||||
} else {
|
||||
klog.Errorln("get role", roleBinding.Namespace, roleBinding.RoleRef.Name, err)
|
||||
klog.Errorln(err)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
@@ -144,13 +164,13 @@ func GetUserRoles(namespace, username string) ([]*rbacv1.Role, error) {
|
||||
return roles, nil
|
||||
}
|
||||
|
||||
func GetUserClusterRoles(username string) (*rbacv1.ClusterRole, []*rbacv1.ClusterRole, error) {
|
||||
clusterRoleLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoles().Lister()
|
||||
clusterRoleBindingLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoleBindings().Lister()
|
||||
func (am *amOperator) GetUserClusterRoles(username string) (*rbacv1.ClusterRole, []*rbacv1.ClusterRole, error) {
|
||||
clusterRoleLister := am.informers.Rbac().V1().ClusterRoles().Lister()
|
||||
clusterRoleBindingLister := am.informers.Rbac().V1().ClusterRoleBindings().Lister()
|
||||
clusterRoleBindings, err := clusterRoleBindingLister.List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln("get cluster role bindings", err)
|
||||
klog.Errorln(err)
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
@@ -164,7 +184,7 @@ func GetUserClusterRoles(username string) (*rbacv1.ClusterRole, []*rbacv1.Cluste
|
||||
klog.Warningf("cluster role %s not found but bind user %s", clusterRoleBinding.RoleRef.Name, username)
|
||||
continue
|
||||
} else {
|
||||
klog.Errorln("get cluster role", clusterRoleBinding.RoleRef.Name, err)
|
||||
klog.Errorln(err)
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
@@ -178,16 +198,16 @@ func GetUserClusterRoles(username string) (*rbacv1.ClusterRole, []*rbacv1.Cluste
|
||||
return userFacingClusterRole, clusterRoles, nil
|
||||
}
|
||||
|
||||
func GetUserClusterRole(username string) (*rbacv1.ClusterRole, error) {
|
||||
userFacingClusterRole, _, err := GetUserClusterRoles(username)
|
||||
func (am *amOperator) GetUserClusterRole(username string) (*rbacv1.ClusterRole, error) {
|
||||
userFacingClusterRole, _, err := am.GetUserClusterRoles(username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return userFacingClusterRole, nil
|
||||
}
|
||||
|
||||
func GetUserClusterRules(username string) ([]rbacv1.PolicyRule, error) {
|
||||
_, clusterRoles, err := GetUserClusterRoles(username)
|
||||
func (am *amOperator) GetUserClusterRules(username string) ([]rbacv1.PolicyRule, error) {
|
||||
_, clusterRoles, err := am.GetUserClusterRoles(username)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -201,8 +221,8 @@ func GetUserClusterRules(username string) ([]rbacv1.PolicyRule, error) {
|
||||
return rules, nil
|
||||
}
|
||||
|
||||
func GetUserRules(namespace, username string) ([]rbacv1.PolicyRule, error) {
|
||||
roles, err := GetUserRoles(namespace, username)
|
||||
func (am *amOperator) GetUserRules(namespace, username string) ([]rbacv1.PolicyRule, error) {
|
||||
roles, err := am.GetUserRoles(namespace, username)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -216,9 +236,9 @@ func GetUserRules(namespace, username string) ([]rbacv1.PolicyRule, error) {
|
||||
return rules, nil
|
||||
}
|
||||
|
||||
func GetWorkspaceRoleBindings(workspace string) ([]*rbacv1.ClusterRoleBinding, error) {
|
||||
func (am *amOperator) GetWorkspaceRoleBindings(workspace string) ([]*rbacv1.ClusterRoleBinding, error) {
|
||||
|
||||
clusterRoleBindings, err := informers.SharedInformerFactory().Rbac().V1().ClusterRoleBindings().Lister().List(labels.Everything())
|
||||
clusterRoleBindings, err := am.informers.Rbac().V1().ClusterRoleBindings().Lister().List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln("get cluster role bindings", err)
|
||||
@@ -236,17 +256,17 @@ func GetWorkspaceRoleBindings(workspace string) ([]*rbacv1.ClusterRoleBinding, e
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func GetWorkspaceRole(workspace, role string) (*rbacv1.ClusterRole, error) {
|
||||
func (am *amOperator) GetWorkspaceRole(workspace, role string) (*rbacv1.ClusterRole, error) {
|
||||
if !sliceutil.HasString(constants.WorkSpaceRoles, role) {
|
||||
return nil, apierrors.NewNotFound(schema.GroupResource{Resource: "workspace role"}, role)
|
||||
}
|
||||
role = fmt.Sprintf("workspace:%s:%s", workspace, strings.TrimPrefix(role, "workspace-"))
|
||||
return informers.SharedInformerFactory().Rbac().V1().ClusterRoles().Lister().Get(role)
|
||||
return am.informers.Rbac().V1().ClusterRoles().Lister().Get(role)
|
||||
}
|
||||
|
||||
func GetUserWorkspaceRoleMap(username string) (map[string]string, error) {
|
||||
func (am *amOperator) GetUserWorkspaceRoleMap(username string) (map[string]string, error) {
|
||||
|
||||
clusterRoleBindings, err := informers.SharedInformerFactory().Rbac().V1().ClusterRoleBindings().Lister().List(labels.Everything())
|
||||
clusterRoleBindings, err := am.informers.Rbac().V1().ClusterRoleBindings().Lister().List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln("get cluster role bindings", err)
|
||||
@@ -265,26 +285,26 @@ func GetUserWorkspaceRoleMap(username string) (map[string]string, error) {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func GetUserWorkspaceRole(workspace, username string) (*rbacv1.ClusterRole, error) {
|
||||
workspaceRoleMap, err := GetUserWorkspaceRoleMap(username)
|
||||
func (am *amOperator) GetUserWorkspaceRole(workspace, username string) (*rbacv1.ClusterRole, error) {
|
||||
workspaceRoleMap, err := am.GetUserWorkspaceRoleMap(username)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if workspaceRole := workspaceRoleMap[workspace]; workspaceRole != "" {
|
||||
return informers.SharedInformerFactory().Rbac().V1().ClusterRoles().Lister().Get(workspaceRole)
|
||||
return am.informers.Rbac().V1().ClusterRoles().Lister().Get(workspaceRole)
|
||||
}
|
||||
|
||||
return nil, apierrors.NewNotFound(schema.GroupResource{Resource: "workspace user"}, username)
|
||||
}
|
||||
|
||||
func GetRoleBindings(namespace string, roleName string) ([]*rbacv1.RoleBinding, error) {
|
||||
roleBindingLister := informers.SharedInformerFactory().Rbac().V1().RoleBindings().Lister()
|
||||
func (am *amOperator) GetRoleBindings(namespace string, roleName string) ([]*rbacv1.RoleBinding, error) {
|
||||
roleBindingLister := am.informers.Rbac().V1().RoleBindings().Lister()
|
||||
roleBindings, err := roleBindingLister.RoleBindings(namespace).List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln("get role bindings", namespace, err)
|
||||
klog.Errorln(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -301,12 +321,12 @@ func GetRoleBindings(namespace string, roleName string) ([]*rbacv1.RoleBinding,
|
||||
return items, nil
|
||||
}
|
||||
|
||||
func GetClusterRoleBindings(clusterRoleName string) ([]*rbacv1.ClusterRoleBinding, error) {
|
||||
clusterRoleBindingLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoleBindings().Lister()
|
||||
func (am *amOperator) GetClusterRoleBindings(clusterRoleName string) ([]*rbacv1.ClusterRoleBinding, error) {
|
||||
clusterRoleBindingLister := am.informers.Rbac().V1().ClusterRoleBindings().Lister()
|
||||
roleBindings, err := clusterRoleBindingLister.List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln("get cluster role bindings", err)
|
||||
klog.Errorln(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -321,14 +341,14 @@ func GetClusterRoleBindings(clusterRoleName string) ([]*rbacv1.ClusterRoleBindin
|
||||
return items, nil
|
||||
}
|
||||
|
||||
func ListClusterRoleUsers(clusterRoleName string, conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
|
||||
func (am *amOperator) ListClusterRoleUsers(clusterRoleName string, conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
|
||||
|
||||
roleBindings, err := GetClusterRoleBindings(clusterRoleName)
|
||||
roleBindings, err := am.GetClusterRoleBindings(clusterRoleName)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
users := make([]*models.User, 0)
|
||||
users := make([]*User, 0)
|
||||
for _, roleBinding := range roleBindings {
|
||||
for _, subject := range roleBinding.Subjects {
|
||||
if subject.Kind == rbacv1.UserKind && !k8sutil.ContainsUser(users, subject.Name) {
|
||||
@@ -337,7 +357,7 @@ func ListClusterRoleUsers(clusterRoleName string, conditions *params.Conditions,
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
klog.Errorln("get user info", subject.Name, err)
|
||||
klog.Errorln(err)
|
||||
return nil, err
|
||||
}
|
||||
users = append(users, user)
|
||||
@@ -348,9 +368,7 @@ func ListClusterRoleUsers(clusterRoleName string, conditions *params.Conditions,
|
||||
// order & reverse
|
||||
sort.Slice(users, func(i, j int) bool {
|
||||
if reverse {
|
||||
tmp := i
|
||||
i = j
|
||||
j = tmp
|
||||
i, j = j, i
|
||||
}
|
||||
switch orderBy {
|
||||
default:
|
||||
@@ -372,43 +390,28 @@ func ListClusterRoleUsers(clusterRoleName string, conditions *params.Conditions,
|
||||
|
||||
}
|
||||
|
||||
func RoleUsers(namespace string, roleName string) ([]*models.User, error) {
|
||||
roleBindings, err := GetRoleBindings(namespace, roleName)
|
||||
func (am *amOperator) ListRoles(namespace string, conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
|
||||
return am.resources.ListResources(namespace, v1alpha2.Roles, conditions, orderBy, reverse, limit, offset)
|
||||
}
|
||||
|
||||
func (am *amOperator) ListRoleBindings(namespace string, role string) ([]*rbacv1.RoleBinding, error) {
|
||||
rbs, err := am.informers.Rbac().V1().RoleBindings().Lister().RoleBindings(namespace).List(labels.Everything())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
users := make([]*models.User, 0)
|
||||
for _, roleBinding := range roleBindings {
|
||||
for _, subject := range roleBinding.Subjects {
|
||||
if subject.Kind == rbacv1.UserKind && !k8sutil.ContainsUser(users, subject.Name) {
|
||||
user, err := GetUserInfo(subject.Name)
|
||||
|
||||
if err != nil {
|
||||
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
|
||||
continue
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
user.Role = roleBinding.RoleRef.Name
|
||||
|
||||
users = append(users, user)
|
||||
}
|
||||
result := make([]*rbacv1.RoleBinding, 0)
|
||||
for _, rb := range rbs {
|
||||
if rb.RoleRef.Name == role {
|
||||
result = append(result, rb.DeepCopy())
|
||||
}
|
||||
}
|
||||
return users, nil
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func ListRoles(namespace string, conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
|
||||
return resources.ListResources(namespace, v1alpha2.Roles, conditions, orderBy, reverse, limit, offset)
|
||||
}
|
||||
|
||||
func ListWorkspaceRoles(workspace string, conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
|
||||
func (am *amOperator) ListWorkspaceRoles(workspace string, conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
|
||||
conditions.Match[v1alpha2.OwnerName] = workspace
|
||||
conditions.Match[v1alpha2.OwnerKind] = "Workspace"
|
||||
result, err := resources.ListResources("", v1alpha2.ClusterRoles, conditions, orderBy, reverse, limit, offset)
|
||||
result, err := am.resources.ListResources("", v1alpha2.ClusterRoles, conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -424,23 +427,23 @@ func ListWorkspaceRoles(workspace string, conditions *params.Conditions, orderBy
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func ListClusterRoles(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
|
||||
return resources.ListResources("", v1alpha2.ClusterRoles, conditions, orderBy, reverse, limit, offset)
|
||||
func (am *amOperator) ListClusterRoles(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
|
||||
return am.resources.ListResources("", v1alpha2.ClusterRoles, conditions, orderBy, reverse, limit, offset)
|
||||
}
|
||||
|
||||
func NamespaceUsers(namespaceName string) ([]*models.User, error) {
|
||||
namespace, err := informers.SharedInformerFactory().Core().V1().Namespaces().Lister().Get(namespaceName)
|
||||
func (am *amOperator) NamespaceUsers(namespaceName string) ([]*User, error) {
|
||||
namespace, err := am.informers.Core().V1().Namespaces().Lister().Get(namespaceName)
|
||||
if err != nil {
|
||||
klog.Errorln("get namespace", namespaceName, err)
|
||||
klog.Errorln(err)
|
||||
return nil, err
|
||||
}
|
||||
roleBindings, err := GetRoleBindings(namespaceName, "")
|
||||
roleBindings, err := am.GetRoleBindings(namespaceName, "")
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
users := make([]*models.User, 0)
|
||||
users := make([]*User, 0)
|
||||
|
||||
for _, roleBinding := range roleBindings {
|
||||
// controlled by ks-controller-manager
|
||||
@@ -475,8 +478,8 @@ func NamespaceUsers(namespaceName string) ([]*models.User, error) {
|
||||
return users, nil
|
||||
}
|
||||
|
||||
func GetUserWorkspaceSimpleRules(workspace, username string) ([]models.SimpleRule, error) {
|
||||
clusterRules, err := GetUserClusterRules(username)
|
||||
func (am *amOperator) GetUserWorkspaceSimpleRules(workspace, username string) ([]SimpleRule, error) {
|
||||
clusterRules, err := am.GetUserClusterRules(username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -487,10 +490,10 @@ func GetUserWorkspaceSimpleRules(workspace, username string) ([]models.SimpleRul
|
||||
APIGroups: []string{"*"},
|
||||
Resources: []string{"*"},
|
||||
}) {
|
||||
return GetWorkspaceRoleSimpleRules(workspace, constants.WorkspaceAdmin), nil
|
||||
return am.GetWorkspaceRoleSimpleRules(workspace, constants.WorkspaceAdmin), nil
|
||||
}
|
||||
|
||||
workspaceRole, err := GetUserWorkspaceRole(workspace, username)
|
||||
workspaceRole, err := am.GetUserWorkspaceRole(workspace, username)
|
||||
|
||||
if err != nil {
|
||||
if apierrors.IsNotFound(err) {
|
||||
@@ -501,26 +504,26 @@ func GetUserWorkspaceSimpleRules(workspace, username string) ([]models.SimpleRul
|
||||
APIGroups: []string{"*"},
|
||||
Resources: []string{"workspaces", "workspaces/*"},
|
||||
}) {
|
||||
return GetWorkspaceRoleSimpleRules(workspace, constants.WorkspacesManager), nil
|
||||
return am.GetWorkspaceRoleSimpleRules(workspace, constants.WorkspacesManager), nil
|
||||
}
|
||||
|
||||
return []models.SimpleRule{}, nil
|
||||
return []SimpleRule{}, nil
|
||||
}
|
||||
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return GetWorkspaceRoleSimpleRules(workspace, workspaceRole.Annotations[constants.DisplayNameAnnotationKey]), nil
|
||||
return am.GetWorkspaceRoleSimpleRules(workspace, workspaceRole.Annotations[constants.DisplayNameAnnotationKey]), nil
|
||||
}
|
||||
|
||||
func GetWorkspaceRoleSimpleRules(workspace, roleName string) []models.SimpleRule {
|
||||
func (am *amOperator) GetWorkspaceRoleSimpleRules(workspace, roleName string) []SimpleRule {
|
||||
|
||||
workspaceRules := make([]models.SimpleRule, 0)
|
||||
workspaceRules := make([]SimpleRule, 0)
|
||||
|
||||
switch roleName {
|
||||
case constants.WorkspaceAdmin:
|
||||
workspaceRules = []models.SimpleRule{
|
||||
workspaceRules = []SimpleRule{
|
||||
{Name: "workspaces", Actions: []string{"edit", "delete", "view"}},
|
||||
{Name: "members", Actions: []string{"edit", "delete", "create", "view"}},
|
||||
{Name: "devops", Actions: []string{"edit", "delete", "create", "view"}},
|
||||
@@ -530,7 +533,7 @@ func GetWorkspaceRoleSimpleRules(workspace, roleName string) []models.SimpleRule
|
||||
{Name: "repos", Actions: []string{"view", "manage"}},
|
||||
}
|
||||
case constants.WorkspaceRegular:
|
||||
workspaceRules = []models.SimpleRule{
|
||||
workspaceRules = []SimpleRule{
|
||||
{Name: "members", Actions: []string{"view"}},
|
||||
{Name: "devops", Actions: []string{"view", "create"}},
|
||||
{Name: "projects", Actions: []string{"view", "create"}},
|
||||
@@ -538,7 +541,7 @@ func GetWorkspaceRoleSimpleRules(workspace, roleName string) []models.SimpleRule
|
||||
{Name: "repos", Actions: []string{"view"}},
|
||||
}
|
||||
case constants.WorkspaceViewer:
|
||||
workspaceRules = []models.SimpleRule{
|
||||
workspaceRules = []SimpleRule{
|
||||
{Name: "workspaces", Actions: []string{"view"}},
|
||||
{Name: "members", Actions: []string{"view"}},
|
||||
{Name: "devops", Actions: []string{"view"}},
|
||||
@@ -548,7 +551,7 @@ func GetWorkspaceRoleSimpleRules(workspace, roleName string) []models.SimpleRule
|
||||
{Name: "repos", Actions: []string{"view"}},
|
||||
}
|
||||
case constants.WorkspacesManager:
|
||||
workspaceRules = []models.SimpleRule{
|
||||
workspaceRules = []SimpleRule{
|
||||
{Name: "workspaces", Actions: []string{"edit", "delete", "view"}},
|
||||
{Name: "members", Actions: []string{"edit", "delete", "create", "view"}},
|
||||
{Name: "roles", Actions: []string{"view"}},
|
||||
@@ -559,33 +562,33 @@ func GetWorkspaceRoleSimpleRules(workspace, roleName string) []models.SimpleRule
|
||||
}
|
||||
|
||||
// Convert cluster role to rules
|
||||
func GetClusterRoleSimpleRules(clusterRoleName string) ([]models.SimpleRule, error) {
|
||||
func (am *amOperator) GetClusterRoleSimpleRules(clusterRoleName string) ([]SimpleRule, error) {
|
||||
|
||||
clusterRoleLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoles().Lister()
|
||||
clusterRoleLister := am.informers.Rbac().V1().ClusterRoles().Lister()
|
||||
clusterRole, err := clusterRoleLister.Get(clusterRoleName)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln("get cluster role", clusterRoleName, clusterRoleName)
|
||||
klog.Errorln(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return getClusterSimpleRule(clusterRole.Rules), nil
|
||||
}
|
||||
|
||||
func GetUserClusterSimpleRules(username string) ([]models.SimpleRule, error) {
|
||||
clusterRules, err := GetUserClusterRules(username)
|
||||
func (am *amOperator) GetUserClusterSimpleRules(username string) ([]SimpleRule, error) {
|
||||
clusterRules, err := am.GetUserClusterRules(username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return getClusterSimpleRule(clusterRules), nil
|
||||
}
|
||||
|
||||
func GetUserNamespaceSimpleRules(namespace, username string) ([]models.SimpleRule, error) {
|
||||
clusterRules, err := GetUserClusterRules(username)
|
||||
func (am *amOperator) GetUserNamespaceSimpleRules(namespace, username string) ([]SimpleRule, error) {
|
||||
clusterRules, err := am.GetUserClusterRules(username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rules, err := GetUserRules(namespace, username)
|
||||
rules, err := am.GetUserRules(namespace, username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -595,21 +598,21 @@ func GetUserNamespaceSimpleRules(namespace, username string) ([]models.SimpleRul
|
||||
}
|
||||
|
||||
// Convert roles to rules
|
||||
func GetRoleSimpleRules(namespace string, roleName string) ([]models.SimpleRule, error) {
|
||||
func (am *amOperator) GetRoleSimpleRules(namespace string, roleName string) ([]SimpleRule, error) {
|
||||
|
||||
roleLister := informers.SharedInformerFactory().Rbac().V1().Roles().Lister()
|
||||
roleLister := am.informers.Rbac().V1().Roles().Lister()
|
||||
role, err := roleLister.Roles(namespace).Get(roleName)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln("get role", namespace, roleName, err)
|
||||
klog.Errorln(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return getSimpleRule(role.Rules), nil
|
||||
}
|
||||
|
||||
func getClusterSimpleRule(policyRules []rbacv1.PolicyRule) []models.SimpleRule {
|
||||
rules := make([]models.SimpleRule, 0)
|
||||
func getClusterSimpleRule(policyRules []rbacv1.PolicyRule) []SimpleRule {
|
||||
rules := make([]SimpleRule, 0)
|
||||
|
||||
for i := 0; i < len(policy.ClusterRoleRuleMapping); i++ {
|
||||
validActions := make([]string, 0)
|
||||
@@ -619,17 +622,17 @@ func getClusterSimpleRule(policyRules []rbacv1.PolicyRule) []models.SimpleRule {
|
||||
}
|
||||
}
|
||||
if len(validActions) > 0 {
|
||||
rules = append(rules, models.SimpleRule{Name: policy.ClusterRoleRuleMapping[i].Name, Actions: validActions})
|
||||
rules = append(rules, SimpleRule{Name: policy.ClusterRoleRuleMapping[i].Name, Actions: validActions})
|
||||
}
|
||||
}
|
||||
|
||||
return rules
|
||||
}
|
||||
|
||||
func getSimpleRule(policyRules []rbacv1.PolicyRule) []models.SimpleRule {
|
||||
simpleRules := make([]models.SimpleRule, 0)
|
||||
func getSimpleRule(policyRules []rbacv1.PolicyRule) []SimpleRule {
|
||||
simpleRules := make([]SimpleRule, 0)
|
||||
for i := 0; i < len(policy.RoleRuleMapping); i++ {
|
||||
rule := models.SimpleRule{Name: policy.RoleRuleMapping[i].Name}
|
||||
rule := SimpleRule{Name: policy.RoleRuleMapping[i].Name}
|
||||
rule.Actions = make([]string, 0)
|
||||
for j := 0; j < len(policy.RoleRuleMapping[i].Actions); j++ {
|
||||
if rulesMatchesAction(policyRules, policy.RoleRuleMapping[i].Actions[j]) {
|
||||
@@ -643,13 +646,13 @@ func getSimpleRule(policyRules []rbacv1.PolicyRule) []models.SimpleRule {
|
||||
return simpleRules
|
||||
}
|
||||
|
||||
func CreateClusterRoleBinding(username string, clusterRoleName string) error {
|
||||
clusterRoleLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoles().Lister()
|
||||
func (am *amOperator) CreateClusterRoleBinding(username string, clusterRoleName string) error {
|
||||
clusterRoleLister := am.informers.Rbac().V1().ClusterRoles().Lister()
|
||||
|
||||
_, err := clusterRoleLister.Get(clusterRoleName)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln("get cluster role", clusterRoleName, err)
|
||||
klog.Errorln(err)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -671,7 +674,7 @@ func CreateClusterRoleBinding(username string, clusterRoleName string) error {
|
||||
clusterRoleBinding.RoleRef = rbacv1.RoleRef{Name: clusterRoleName, Kind: ClusterRoleKind}
|
||||
clusterRoleBinding.Subjects = []rbacv1.Subject{{Kind: rbacv1.UserKind, Name: username}}
|
||||
|
||||
clusterRoleBindingLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoleBindings().Lister()
|
||||
clusterRoleBindingLister := am.informers.Rbac().V1().ClusterRoleBindings().Lister()
|
||||
found, err := clusterRoleBindingLister.Get(username)
|
||||
|
||||
if apierrors.IsNotFound(err) {
|
||||
@@ -714,159 +717,3 @@ func CreateClusterRoleBinding(username string, clusterRoleName string) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func RulesMatchesRequired(rules []rbacv1.PolicyRule, required rbacv1.PolicyRule) bool {
|
||||
for _, rule := range rules {
|
||||
if ruleMatchesRequired(rule, required) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func rulesMatchesAction(rules []rbacv1.PolicyRule, action models.Action) bool {
|
||||
|
||||
for _, required := range action.Rules {
|
||||
if !RulesMatchesRequired(rules, required) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func ruleMatchesRequired(rule rbacv1.PolicyRule, required rbacv1.PolicyRule) bool {
|
||||
|
||||
if len(required.NonResourceURLs) == 0 {
|
||||
for _, apiGroup := range required.APIGroups {
|
||||
for _, resource := range required.Resources {
|
||||
resources := strings.Split(resource, "/")
|
||||
resource = resources[0]
|
||||
var subsource string
|
||||
if len(resources) > 1 {
|
||||
subsource = resources[1]
|
||||
}
|
||||
|
||||
if len(required.ResourceNames) == 0 {
|
||||
for _, verb := range required.Verbs {
|
||||
if !ruleMatchesRequest(rule, apiGroup, "", resource, subsource, "", verb) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for _, resourceName := range required.ResourceNames {
|
||||
for _, verb := range required.Verbs {
|
||||
if !ruleMatchesRequest(rule, apiGroup, "", resource, subsource, resourceName, verb) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for _, apiGroup := range required.APIGroups {
|
||||
for _, nonResourceURL := range required.NonResourceURLs {
|
||||
for _, verb := range required.Verbs {
|
||||
if !ruleMatchesRequest(rule, apiGroup, nonResourceURL, "", "", "", verb) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func ruleMatchesResources(rule rbacv1.PolicyRule, apiGroup string, resource string, subresource string, resourceName string) bool {
|
||||
|
||||
if resource == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
if !hasString(rule.APIGroups, apiGroup) && !hasString(rule.APIGroups, rbacv1.ResourceAll) {
|
||||
return false
|
||||
}
|
||||
|
||||
if len(rule.ResourceNames) > 0 && !hasString(rule.ResourceNames, resourceName) {
|
||||
return false
|
||||
}
|
||||
|
||||
combinedResource := resource
|
||||
|
||||
if subresource != "" {
|
||||
combinedResource = combinedResource + "/" + subresource
|
||||
}
|
||||
|
||||
for _, res := range rule.Resources {
|
||||
|
||||
// match "*"
|
||||
if res == rbacv1.ResourceAll || res == combinedResource {
|
||||
return true
|
||||
}
|
||||
|
||||
// match "*/subresource"
|
||||
if len(subresource) > 0 && strings.HasPrefix(res, "*/") && subresource == strings.TrimLeft(res, "*/") {
|
||||
return true
|
||||
}
|
||||
// match "resource/*"
|
||||
if strings.HasSuffix(res, "/*") && resource == strings.TrimRight(res, "/*") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func ruleMatchesRequest(rule rbacv1.PolicyRule, apiGroup string, nonResourceURL string, resource string, subresource string, resourceName string, verb string) bool {
|
||||
|
||||
if !hasString(rule.Verbs, verb) && !hasString(rule.Verbs, rbacv1.VerbAll) {
|
||||
return false
|
||||
}
|
||||
|
||||
if nonResourceURL == "" {
|
||||
return ruleMatchesResources(rule, apiGroup, resource, subresource, resourceName)
|
||||
} else {
|
||||
return ruleMatchesNonResource(rule, nonResourceURL)
|
||||
}
|
||||
}
|
||||
|
||||
func ruleMatchesNonResource(rule rbacv1.PolicyRule, nonResourceURL string) bool {
|
||||
|
||||
if nonResourceURL == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, spec := range rule.NonResourceURLs {
|
||||
if pathMatches(nonResourceURL, spec) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func pathMatches(path, spec string) bool {
|
||||
// Allow wildcard match
|
||||
if spec == "*" {
|
||||
return true
|
||||
}
|
||||
// Allow exact match
|
||||
if spec == path {
|
||||
return true
|
||||
}
|
||||
// Allow a trailing * subpath match
|
||||
if strings.HasSuffix(spec, "*") && strings.HasPrefix(path, strings.TrimRight(spec, "*")) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func hasString(slice []string, value string) bool {
|
||||
for _, s := range slice {
|
||||
if s == value {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -21,22 +21,21 @@ package policy
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam"
|
||||
|
||||
"k8s.io/api/rbac/v1"
|
||||
)
|
||||
|
||||
const (
|
||||
rulesConfigPath = "/etc/kubesphere/rules/rules.json"
|
||||
clusterRulesConfigPath = "/etc/kubesphere/rules/clusterrules.json"
|
||||
rulesConfigPath = iam.ConfigPath + "/rules.json"
|
||||
clusterRulesConfigPath = iam.ConfigPath + "/clusterrules.json"
|
||||
)
|
||||
|
||||
func init() {
|
||||
rulesConfig, err := ioutil.ReadFile(rulesConfigPath)
|
||||
|
||||
if err == nil {
|
||||
config := &[]models.Rule{}
|
||||
config := &[]iam.Rule{}
|
||||
json.Unmarshal(rulesConfig, config)
|
||||
if len(*config) > 0 {
|
||||
RoleRuleMapping = *config
|
||||
@@ -46,7 +45,7 @@ func init() {
|
||||
clusterRulesConfig, err := ioutil.ReadFile(clusterRulesConfigPath)
|
||||
|
||||
if err == nil {
|
||||
config := &[]models.Rule{}
|
||||
config := &[]iam.Rule{}
|
||||
json.Unmarshal(clusterRulesConfig, config)
|
||||
if len(*config) > 0 {
|
||||
ClusterRoleRuleMapping = *config
|
||||
@@ -55,9 +54,9 @@ func init() {
|
||||
}
|
||||
|
||||
var (
|
||||
ClusterRoleRuleMapping = []models.Rule{
|
||||
ClusterRoleRuleMapping = []iam.Rule{
|
||||
{Name: "workspaces",
|
||||
Actions: []models.Action{
|
||||
Actions: []iam.Action{
|
||||
{
|
||||
Name: "manage",
|
||||
Rules: []v1.PolicyRule{
|
||||
@@ -72,7 +71,7 @@ var (
|
||||
},
|
||||
{
|
||||
Name: "monitoring",
|
||||
Actions: []models.Action{
|
||||
Actions: []iam.Action{
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{{
|
||||
Verbs: []string{"get", "list"},
|
||||
@@ -88,7 +87,7 @@ var (
|
||||
},
|
||||
{
|
||||
Name: "alerting",
|
||||
Actions: []models.Action{
|
||||
Actions: []iam.Action{
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{{
|
||||
Verbs: []string{"get", "list"},
|
||||
@@ -114,7 +113,7 @@ var (
|
||||
},
|
||||
{
|
||||
Name: "logging",
|
||||
Actions: []models.Action{
|
||||
Actions: []iam.Action{
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{{
|
||||
Verbs: []string{"get", "list"},
|
||||
@@ -126,7 +125,7 @@ var (
|
||||
},
|
||||
{
|
||||
Name: "accounts",
|
||||
Actions: []models.Action{
|
||||
Actions: []iam.Action{
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
@@ -193,7 +192,7 @@ var (
|
||||
},
|
||||
}, {
|
||||
Name: "roles",
|
||||
Actions: []models.Action{
|
||||
Actions: []iam.Action{
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
@@ -239,7 +238,7 @@ var (
|
||||
},
|
||||
}, {
|
||||
Name: "storageclasses",
|
||||
Actions: []models.Action{
|
||||
Actions: []iam.Action{
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
@@ -283,7 +282,7 @@ var (
|
||||
},
|
||||
}, {
|
||||
Name: "nodes",
|
||||
Actions: []models.Action{
|
||||
Actions: []iam.Action{
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
@@ -314,7 +313,7 @@ var (
|
||||
},
|
||||
}, {
|
||||
Name: "repos",
|
||||
Actions: []models.Action{
|
||||
Actions: []iam.Action{
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
@@ -354,7 +353,7 @@ var (
|
||||
},
|
||||
}, {
|
||||
Name: "apps",
|
||||
Actions: []models.Action{
|
||||
Actions: []iam.Action{
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
@@ -367,7 +366,7 @@ var (
|
||||
},
|
||||
}, {
|
||||
Name: "components",
|
||||
Actions: []models.Action{
|
||||
Actions: []iam.Action{
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
@@ -380,9 +379,9 @@ var (
|
||||
},
|
||||
}}
|
||||
|
||||
RoleRuleMapping = []models.Rule{{
|
||||
RoleRuleMapping = []iam.Rule{{
|
||||
Name: "projects",
|
||||
Actions: []models.Action{
|
||||
Actions: []iam.Action{
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
@@ -419,7 +418,7 @@ var (
|
||||
},
|
||||
{
|
||||
Name: "monitoring",
|
||||
Actions: []models.Action{
|
||||
Actions: []iam.Action{
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{{
|
||||
Verbs: []string{"get", "list"},
|
||||
@@ -436,7 +435,7 @@ var (
|
||||
|
||||
{
|
||||
Name: "alerting",
|
||||
Actions: []models.Action{
|
||||
Actions: []iam.Action{
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{{
|
||||
Verbs: []string{"get", "list"},
|
||||
@@ -462,7 +461,7 @@ var (
|
||||
},
|
||||
{
|
||||
Name: "members",
|
||||
Actions: []models.Action{
|
||||
Actions: []iam.Action{
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
@@ -508,7 +507,7 @@ var (
|
||||
},
|
||||
{
|
||||
Name: "roles",
|
||||
Actions: []models.Action{
|
||||
Actions: []iam.Action{
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
@@ -549,7 +548,7 @@ var (
|
||||
},
|
||||
{
|
||||
Name: "deployments",
|
||||
Actions: []models.Action{
|
||||
Actions: []iam.Action{
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
@@ -605,7 +604,7 @@ var (
|
||||
},
|
||||
}, {
|
||||
Name: "statefulsets",
|
||||
Actions: []models.Action{
|
||||
Actions: []iam.Action{
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
@@ -659,7 +658,7 @@ var (
|
||||
},
|
||||
}, {
|
||||
Name: "daemonsets",
|
||||
Actions: []models.Action{
|
||||
Actions: []iam.Action{
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
@@ -704,7 +703,7 @@ var (
|
||||
},
|
||||
}, {
|
||||
Name: "pods",
|
||||
Actions: []models.Action{
|
||||
Actions: []iam.Action{
|
||||
{Name: "terminal",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
@@ -736,7 +735,7 @@ var (
|
||||
},
|
||||
{
|
||||
Name: "services",
|
||||
Actions: []models.Action{
|
||||
Actions: []iam.Action{
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
@@ -778,7 +777,7 @@ var (
|
||||
},
|
||||
{
|
||||
Name: "internet",
|
||||
Actions: []models.Action{
|
||||
Actions: []iam.Action{
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
@@ -820,7 +819,7 @@ var (
|
||||
|
||||
{
|
||||
Name: "routes",
|
||||
Actions: []models.Action{
|
||||
Actions: []iam.Action{
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
@@ -860,7 +859,7 @@ var (
|
||||
},
|
||||
}, {
|
||||
Name: "volumes",
|
||||
Actions: []models.Action{
|
||||
Actions: []iam.Action{
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
@@ -900,7 +899,7 @@ var (
|
||||
},
|
||||
}, {
|
||||
Name: "applications",
|
||||
Actions: []models.Action{
|
||||
Actions: []iam.Action{
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
@@ -954,7 +953,7 @@ var (
|
||||
},
|
||||
{
|
||||
Name: "jobs",
|
||||
Actions: []models.Action{
|
||||
Actions: []iam.Action{
|
||||
{Name: "view", Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get", "list"},
|
||||
@@ -987,7 +986,7 @@ var (
|
||||
},
|
||||
{
|
||||
Name: "cronjobs",
|
||||
Actions: []models.Action{
|
||||
Actions: []iam.Action{
|
||||
{Name: "view", Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get", "list"},
|
||||
@@ -1020,7 +1019,7 @@ var (
|
||||
},
|
||||
{
|
||||
Name: "secrets",
|
||||
Actions: []models.Action{
|
||||
Actions: []iam.Action{
|
||||
{Name: "view", Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get", "list"},
|
||||
@@ -1053,7 +1052,7 @@ var (
|
||||
},
|
||||
{
|
||||
Name: "configmaps",
|
||||
Actions: []models.Action{
|
||||
Actions: []iam.Action{
|
||||
{Name: "view", Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get", "list"},
|
||||
|
||||
61
pkg/models/iam/types.go
Normal file
61
pkg/models/iam/types.go
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2020 The KubeSphere 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 iam
|
||||
|
||||
import (
|
||||
"k8s.io/api/rbac/v1"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
ConfigPath = "/etc/kubesphere/iam"
|
||||
KindTokenReview = "TokenReview"
|
||||
)
|
||||
|
||||
type Action struct {
|
||||
Name string `json:"name"`
|
||||
Rules []v1.PolicyRule `json:"rules"`
|
||||
}
|
||||
|
||||
type Rule struct {
|
||||
Name string `json:"name"`
|
||||
Actions []Action `json:"actions"`
|
||||
}
|
||||
|
||||
type SimpleRule struct {
|
||||
Name string `json:"name" description:"rule name"`
|
||||
Actions []string `json:"actions" description:"actions"`
|
||||
}
|
||||
|
||||
type RoleList struct {
|
||||
ClusterRoles []*v1.ClusterRole `json:"clusterRole" description:"cluster role list"`
|
||||
Roles []*v1.Role `json:"roles" description:"role list"`
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
adminEmail string
|
||||
adminPassword string
|
||||
authRateLimit string
|
||||
maxAuthFailed int
|
||||
authTimeInterval time.Duration
|
||||
tokenIdleTimeout time.Duration
|
||||
userInitFile string
|
||||
enableMultiLogin bool
|
||||
generateKubeConfig bool
|
||||
}
|
||||
180
pkg/models/iam/utils.go
Normal file
180
pkg/models/iam/utils.go
Normal file
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2020 The KubeSphere 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 iam
|
||||
|
||||
import (
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func RulesMatchesRequired(rules []rbacv1.PolicyRule, required rbacv1.PolicyRule) bool {
|
||||
for _, rule := range rules {
|
||||
if ruleMatchesRequired(rule, required) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func rulesMatchesAction(rules []rbacv1.PolicyRule, action Action) bool {
|
||||
|
||||
for _, required := range action.Rules {
|
||||
if !RulesMatchesRequired(rules, required) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func ruleMatchesRequired(rule rbacv1.PolicyRule, required rbacv1.PolicyRule) bool {
|
||||
|
||||
if len(required.NonResourceURLs) == 0 {
|
||||
for _, apiGroup := range required.APIGroups {
|
||||
for _, resource := range required.Resources {
|
||||
resources := strings.Split(resource, "/")
|
||||
resource = resources[0]
|
||||
var subsource string
|
||||
if len(resources) > 1 {
|
||||
subsource = resources[1]
|
||||
}
|
||||
|
||||
if len(required.ResourceNames) == 0 {
|
||||
for _, verb := range required.Verbs {
|
||||
if !ruleMatchesRequest(rule, apiGroup, "", resource, subsource, "", verb) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for _, resourceName := range required.ResourceNames {
|
||||
for _, verb := range required.Verbs {
|
||||
if !ruleMatchesRequest(rule, apiGroup, "", resource, subsource, resourceName, verb) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for _, apiGroup := range required.APIGroups {
|
||||
for _, nonResourceURL := range required.NonResourceURLs {
|
||||
for _, verb := range required.Verbs {
|
||||
if !ruleMatchesRequest(rule, apiGroup, nonResourceURL, "", "", "", verb) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func ruleMatchesResources(rule rbacv1.PolicyRule, apiGroup string, resource string, subresource string, resourceName string) bool {
|
||||
|
||||
if resource == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
if !hasString(rule.APIGroups, apiGroup) && !hasString(rule.APIGroups, rbacv1.ResourceAll) {
|
||||
return false
|
||||
}
|
||||
|
||||
if len(rule.ResourceNames) > 0 && !hasString(rule.ResourceNames, resourceName) {
|
||||
return false
|
||||
}
|
||||
|
||||
combinedResource := resource
|
||||
|
||||
if subresource != "" {
|
||||
combinedResource = combinedResource + "/" + subresource
|
||||
}
|
||||
|
||||
for _, res := range rule.Resources {
|
||||
|
||||
// match "*"
|
||||
if res == rbacv1.ResourceAll || res == combinedResource {
|
||||
return true
|
||||
}
|
||||
|
||||
// match "*/subresource"
|
||||
if len(subresource) > 0 && strings.HasPrefix(res, "*/") && subresource == strings.TrimLeft(res, "*/") {
|
||||
return true
|
||||
}
|
||||
// match "resource/*"
|
||||
if strings.HasSuffix(res, "/*") && resource == strings.TrimRight(res, "/*") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func ruleMatchesRequest(rule rbacv1.PolicyRule, apiGroup string, nonResourceURL string, resource string, subresource string, resourceName string, verb string) bool {
|
||||
|
||||
if !hasString(rule.Verbs, verb) && !hasString(rule.Verbs, rbacv1.VerbAll) {
|
||||
return false
|
||||
}
|
||||
|
||||
if nonResourceURL == "" {
|
||||
return ruleMatchesResources(rule, apiGroup, resource, subresource, resourceName)
|
||||
} else {
|
||||
return ruleMatchesNonResource(rule, nonResourceURL)
|
||||
}
|
||||
}
|
||||
|
||||
func ruleMatchesNonResource(rule rbacv1.PolicyRule, nonResourceURL string) bool {
|
||||
|
||||
if nonResourceURL == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, spec := range rule.NonResourceURLs {
|
||||
if pathMatches(nonResourceURL, spec) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func pathMatches(path, spec string) bool {
|
||||
// Allow wildcard match
|
||||
if spec == "*" {
|
||||
return true
|
||||
}
|
||||
// Allow exact match
|
||||
if spec == path {
|
||||
return true
|
||||
}
|
||||
// Allow a trailing * subpath match
|
||||
if strings.HasSuffix(spec, "*") && strings.HasPrefix(path, strings.TrimRight(spec, "*")) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func hasString(slice []string, value string) bool {
|
||||
for _, s := range slice {
|
||||
if s == value {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -1,21 +1,21 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 The KubeSphere 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 application
|
||||
*
|
||||
* Copyright 2020 The KubeSphere 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 openpitrix
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -26,46 +26,39 @@ import (
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/api/extensions/v1beta1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/client-go/informers"
|
||||
"k8s.io/klog"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"kubesphere.io/kubesphere/pkg/models/openpitrix/type"
|
||||
"kubesphere.io/kubesphere/pkg/models/openpitrix/utils"
|
||||
"kubesphere.io/kubesphere/pkg/server/params"
|
||||
cs "kubesphere.io/kubesphere/pkg/simple/client"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/openpitrix"
|
||||
"openpitrix.io/openpitrix/pkg/pb"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Interface interface {
|
||||
List(conditions *params.Conditions, limit, offset int, orderBy string, reverse bool) (*models.PageableResponse, error)
|
||||
Get(namespace, clusterID string) (*Application, error)
|
||||
Create(namespace string, request types.CreateClusterRequest) error
|
||||
Patch(request types.ModifyClusterAttributesRequest) error
|
||||
Delete(id string) error
|
||||
type ApplicationInterface interface {
|
||||
ListApplications(conditions *params.Conditions, limit, offset int, orderBy string, reverse bool) (*models.PageableResponse, error)
|
||||
DescribeApplication(namespace, clusterId string) (*Application, error)
|
||||
CreateApplication(namespace string, request CreateClusterRequest) error
|
||||
ModifyApplication(request ModifyClusterAttributesRequest) error
|
||||
DeleteApplication(id string) error
|
||||
}
|
||||
|
||||
type applicationOperator struct {
|
||||
informers informers.SharedInformerFactory
|
||||
opClient pb.ClusterManagerClient
|
||||
opClient openpitrix.Client
|
||||
}
|
||||
|
||||
func NewApplicaitonOperator(informers informers.SharedInformerFactory, client pb.ClusterManagerClient) Interface {
|
||||
return &applicationOperator{
|
||||
informers: informers,
|
||||
opClient: client,
|
||||
}
|
||||
func newApplicationOperator(informers informers.SharedInformerFactory, opClient openpitrix.Client) ApplicationInterface {
|
||||
return &applicationOperator{informers: informers, opClient: opClient}
|
||||
}
|
||||
|
||||
type Application struct {
|
||||
Name string `json:"name" description:"application name"`
|
||||
Cluster *types.Cluster `json:"cluster,omitempty" description:"application cluster info"`
|
||||
Version *types.AppVersion `json:"version,omitempty" description:"application template version info"`
|
||||
App *types.App `json:"app,omitempty" description:"application template info"`
|
||||
Cluster *Cluster `json:"cluster,omitempty" description:"application cluster info"`
|
||||
Version *AppVersion `json:"version,omitempty" description:"application template version info"`
|
||||
App *App `json:"app,omitempty" description:"application template info"`
|
||||
WorkLoads *workLoads `json:"workloads,omitempty" description:"application workloads"`
|
||||
Services []v1.Service `json:"services,omitempty" description:"application services"`
|
||||
Ingresses []v1beta1.Ingress `json:"ingresses,omitempty" description:"application ingresses"`
|
||||
@@ -77,35 +70,30 @@ type workLoads struct {
|
||||
Daemonsets []appsv1.DaemonSet `json:"daemonsets,omitempty" description:"daemonset list"`
|
||||
}
|
||||
|
||||
func (c *applicationOperator) List(conditions *params.Conditions, limit, offset int, orderBy string, reverse bool) (*models.PageableResponse, error) {
|
||||
client, err := cs.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
func (c *applicationOperator) ListApplications(conditions *params.Conditions, limit, offset int, orderBy string, reverse bool) (*models.PageableResponse, error) {
|
||||
describeClustersRequest := &pb.DescribeClustersRequest{
|
||||
Limit: uint32(limit),
|
||||
Offset: uint32(offset)}
|
||||
if keyword := conditions.Match["keyword"]; keyword != "" {
|
||||
if keyword := conditions.Match[Keyword]; keyword != "" {
|
||||
describeClustersRequest.SearchWord = &wrappers.StringValue{Value: keyword}
|
||||
}
|
||||
if runtimeId := conditions.Match["runtime_id"]; runtimeId != "" {
|
||||
if runtimeId := conditions.Match[RuntimeId]; runtimeId != "" {
|
||||
describeClustersRequest.RuntimeId = []string{runtimeId}
|
||||
}
|
||||
if appId := conditions.Match["app_id"]; appId != "" {
|
||||
if appId := conditions.Match[AppId]; appId != "" {
|
||||
describeClustersRequest.AppId = []string{appId}
|
||||
}
|
||||
if versionId := conditions.Match["version_id"]; versionId != "" {
|
||||
if versionId := conditions.Match[VersionId]; versionId != "" {
|
||||
describeClustersRequest.VersionId = []string{versionId}
|
||||
}
|
||||
if status := conditions.Match["status"]; status != "" {
|
||||
if status := conditions.Match[Status]; status != "" {
|
||||
describeClustersRequest.Status = strings.Split(status, "|")
|
||||
}
|
||||
if orderBy != "" {
|
||||
describeClustersRequest.SortKey = &wrappers.StringValue{Value: orderBy}
|
||||
}
|
||||
describeClustersRequest.Reverse = &wrappers.BoolValue{Value: !reverse}
|
||||
resp, err := client.Cluster().DescribeClusters(openpitrix.SystemContext(), describeClustersRequest)
|
||||
describeClustersRequest.Reverse = &wrappers.BoolValue{Value: reverse}
|
||||
resp, err := c.opClient.DescribeClusters(openpitrix.SystemContext(), describeClustersRequest)
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
return nil, err
|
||||
@@ -125,34 +113,29 @@ func (c *applicationOperator) List(conditions *params.Conditions, limit, offset
|
||||
}
|
||||
|
||||
func (c *applicationOperator) describeApplication(cluster *pb.Cluster) (*Application, error) {
|
||||
op, err := cs.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
var app Application
|
||||
app.Name = cluster.Name.Value
|
||||
app.Cluster = utils.ConvertCluster(cluster)
|
||||
versionInfo, err := op.App().DescribeAppVersions(openpitrix.SystemContext(), &pb.DescribeAppVersionsRequest{VersionId: []string{cluster.GetVersionId().GetValue()}})
|
||||
app.Cluster = convertCluster(cluster)
|
||||
versionInfo, err := c.opClient.DescribeAppVersions(openpitrix.SystemContext(), &pb.DescribeAppVersionsRequest{VersionId: []string{cluster.GetVersionId().GetValue()}})
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
return nil, err
|
||||
}
|
||||
if len(versionInfo.AppVersionSet) > 0 {
|
||||
app.Version = utils.ConvertAppVersion(versionInfo.AppVersionSet[0])
|
||||
app.Version = convertAppVersion(versionInfo.AppVersionSet[0])
|
||||
}
|
||||
appInfo, err := op.App().DescribeApps(openpitrix.SystemContext(), &pb.DescribeAppsRequest{AppId: []string{cluster.GetAppId().GetValue()}, Limit: 1})
|
||||
appInfo, err := c.opClient.DescribeApps(openpitrix.SystemContext(), &pb.DescribeAppsRequest{AppId: []string{cluster.GetAppId().GetValue()}, Limit: 1})
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
return nil, err
|
||||
}
|
||||
if len(appInfo.AppSet) > 0 {
|
||||
app.App = utils.ConvertApp(appInfo.GetAppSet()[0])
|
||||
app.App = convertApp(appInfo.GetAppSet()[0])
|
||||
}
|
||||
return &app, nil
|
||||
}
|
||||
|
||||
func (c *applicationOperator) Get(namespace string, clusterId string) (*Application, error) {
|
||||
func (c *applicationOperator) DescribeApplication(namespace string, clusterId string) (*Application, error) {
|
||||
|
||||
clusters, err := c.opClient.DescribeClusters(openpitrix.SystemContext(), &pb.DescribeClustersRequest{ClusterId: []string{clusterId}, Limit: 1})
|
||||
|
||||
@@ -280,7 +263,7 @@ func (c *applicationOperator) getLabels(namespace string, workloads *workLoads)
|
||||
return &workloadLabels
|
||||
}
|
||||
|
||||
func (c *applicationOperator) isExist(svcs []v1.Service, svc v1.Service) bool {
|
||||
func (c *applicationOperator) isExist(svcs []v1.Service, svc *v1.Service) bool {
|
||||
for _, item := range svcs {
|
||||
if item.Name == svc.Name && item.Namespace == svc.Namespace {
|
||||
return true
|
||||
@@ -293,17 +276,16 @@ func (c *applicationOperator) getSvcs(namespace string, workLoadLabels *[]map[st
|
||||
if len(*workLoadLabels) == 0 {
|
||||
return nil
|
||||
}
|
||||
k8sClient := cs.ClientSets().K8s().Kubernetes()
|
||||
var services []v1.Service
|
||||
for _, label := range *workLoadLabels {
|
||||
labelSelector := labels.Set(label).AsSelector().String()
|
||||
svcs, err := k8sClient.CoreV1().Services(namespace).List(metav1.ListOptions{LabelSelector: labelSelector})
|
||||
labelSelector := labels.Set(label).AsSelector()
|
||||
svcs, err := c.informers.Core().V1().Services().Lister().Services(namespace).List(labelSelector)
|
||||
if err != nil {
|
||||
klog.Errorf("get app's svc failed, reason: %v", err)
|
||||
}
|
||||
for _, item := range svcs.Items {
|
||||
for _, item := range svcs {
|
||||
if !c.isExist(services, item) {
|
||||
services = append(services, item)
|
||||
services = append(services, *item)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -352,7 +334,7 @@ func (c *applicationOperator) getIng(namespace string, services []v1.Service) []
|
||||
return ings
|
||||
}
|
||||
|
||||
func (c *applicationOperator) Create(namespace string, request types.CreateClusterRequest) error {
|
||||
func (c *applicationOperator) CreateApplication(namespace string, request CreateClusterRequest) error {
|
||||
ns, err := c.informers.Core().V1().Namespaces().Lister().Get(namespace)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
@@ -365,14 +347,7 @@ func (c *applicationOperator) Create(namespace string, request types.CreateClust
|
||||
return fmt.Errorf("runtime not init: namespace %s", namespace)
|
||||
}
|
||||
|
||||
client, err := cs.ClientSets().OpenPitrix()
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = client.Cluster().CreateCluster(openpitrix.ContextWithUsername(request.Username), &pb.CreateClusterRequest{
|
||||
_, err = c.opClient.CreateCluster(openpitrix.ContextWithUsername(request.Username), &pb.CreateClusterRequest{
|
||||
AppId: &wrappers.StringValue{Value: request.AppId},
|
||||
VersionId: &wrappers.StringValue{Value: request.VersionId},
|
||||
RuntimeId: &wrappers.StringValue{Value: request.RuntimeId},
|
||||
@@ -387,13 +362,7 @@ func (c *applicationOperator) Create(namespace string, request types.CreateClust
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *applicationOperator) Patch(request types.ModifyClusterAttributesRequest) error {
|
||||
op, err := cs.ClientSets().OpenPitrix()
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
func (c *applicationOperator) ModifyApplication(request ModifyClusterAttributesRequest) error {
|
||||
|
||||
modifyClusterAttributesRequest := &pb.ModifyClusterAttributesRequest{ClusterId: &wrappers.StringValue{Value: request.ClusterID}}
|
||||
if request.Name != nil {
|
||||
@@ -403,16 +372,17 @@ func (c *applicationOperator) Patch(request types.ModifyClusterAttributesRequest
|
||||
modifyClusterAttributesRequest.Description = &wrappers.StringValue{Value: *request.Description}
|
||||
}
|
||||
|
||||
_, err = op.Cluster().ModifyClusterAttributes(openpitrix.SystemContext(), modifyClusterAttributesRequest)
|
||||
_, err := c.opClient.ModifyClusterAttributes(openpitrix.SystemContext(), modifyClusterAttributesRequest)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *applicationOperator) Delete(clusterId string) error {
|
||||
func (c *applicationOperator) DeleteApplication(clusterId string) error {
|
||||
_, err := c.opClient.DeleteClusters(openpitrix.SystemContext(), &pb.DeleteClustersRequest{ClusterId: []string{clusterId}, Force: &wrappers.BoolValue{Value: true}})
|
||||
|
||||
if err != nil {
|
||||
114
pkg/models/openpitrix/applications_test.go
Normal file
114
pkg/models/openpitrix/applications_test.go
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2020 The KubeSphere 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 openpitrix
|
||||
|
||||
import (
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/golang/protobuf/ptypes/wrappers"
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/client-go/informers"
|
||||
"k8s.io/client-go/kubernetes/fake"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/openpitrix"
|
||||
"openpitrix.io/openpitrix/pkg/pb"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func namespacesToRuntimeObjects(namespaces ...*v1.Namespace) []runtime.Object {
|
||||
var objs []runtime.Object
|
||||
for _, deploy := range namespaces {
|
||||
objs = append(objs, deploy)
|
||||
}
|
||||
|
||||
return objs
|
||||
}
|
||||
|
||||
func TestApplicationOperator_CreateApplication(t *testing.T) {
|
||||
tests := []struct {
|
||||
description string
|
||||
existNamespaces []*v1.Namespace
|
||||
targetNamespace string
|
||||
createClusterRequest CreateClusterRequest
|
||||
expected error
|
||||
}{
|
||||
{
|
||||
description: "create application test",
|
||||
existNamespaces: []*v1.Namespace{{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "test", Annotations: map[string]string{openpitrix.RuntimeAnnotationKey: "runtime-ncafface"}},
|
||||
}},
|
||||
targetNamespace: "test",
|
||||
createClusterRequest: CreateClusterRequest{
|
||||
Conf: "app-agwerl",
|
||||
RuntimeId: "runtime-ncafface",
|
||||
VersionId: "version-acklmalkds",
|
||||
Username: "system",
|
||||
},
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
description: "create application test2",
|
||||
existNamespaces: []*v1.Namespace{},
|
||||
targetNamespace: "test2",
|
||||
createClusterRequest: CreateClusterRequest{
|
||||
Conf: "app-agwerl",
|
||||
RuntimeId: "runtime-ncafface",
|
||||
VersionId: "version-acklmalkds",
|
||||
Username: "system",
|
||||
},
|
||||
expected: errors.NewNotFound(schema.GroupResource{Group: "", Resource: "namespace"}, "test2"),
|
||||
},
|
||||
}
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
for _, test := range tests {
|
||||
|
||||
op := openpitrix.NewMockClient(ctrl)
|
||||
objs := namespacesToRuntimeObjects(test.existNamespaces...)
|
||||
k8s := fake.NewSimpleClientset(objs...)
|
||||
informer := informers.NewSharedInformerFactory(k8s, 0)
|
||||
stopChan := make(chan struct{}, 0)
|
||||
informer.Core().V1().Namespaces().Lister()
|
||||
informer.Start(stopChan)
|
||||
informer.WaitForCacheSync(stopChan)
|
||||
|
||||
applicationOperator := newApplicationOperator(informer, op)
|
||||
|
||||
// setup expect response
|
||||
// op.EXPECT().CreateCluster(gomock.Any(), gomock.Any()).Return(&pb.CreateClusterResponse{}, nil).AnyTimes()
|
||||
op.EXPECT().CreateCluster(openpitrix.ContextWithUsername(test.createClusterRequest.Username), &pb.CreateClusterRequest{
|
||||
AppId: &wrappers.StringValue{Value: test.createClusterRequest.AppId},
|
||||
VersionId: &wrappers.StringValue{Value: test.createClusterRequest.VersionId},
|
||||
RuntimeId: &wrappers.StringValue{Value: test.createClusterRequest.RuntimeId},
|
||||
Conf: &wrappers.StringValue{Value: test.createClusterRequest.Conf},
|
||||
}).Return(&pb.CreateClusterResponse{}, nil).AnyTimes()
|
||||
|
||||
t.Run(test.description, func(t *testing.T) {
|
||||
|
||||
err := applicationOperator.CreateApplication(test.targetNamespace, test.createClusterRequest)
|
||||
|
||||
if err != nil && err.Error() != test.expected.Error() {
|
||||
t.Error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2019 The KubeSphere Authors.
|
||||
* Copyright 2020 The KubeSphere Authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,7 +16,7 @@
|
||||
* /
|
||||
*/
|
||||
|
||||
package app
|
||||
package openpitrix
|
||||
|
||||
import (
|
||||
"github.com/go-openapi/strfmt"
|
||||
@@ -25,41 +25,58 @@ import (
|
||||
"google.golang.org/grpc/status"
|
||||
"k8s.io/klog"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"kubesphere.io/kubesphere/pkg/models/openpitrix/type"
|
||||
"kubesphere.io/kubesphere/pkg/models/openpitrix/utils"
|
||||
"kubesphere.io/kubesphere/pkg/server/params"
|
||||
cs "kubesphere.io/kubesphere/pkg/simple/client"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/openpitrix"
|
||||
"openpitrix.io/openpitrix/pkg/pb"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
BuiltinRepoId = "repo-helm"
|
||||
StatusActive = "active"
|
||||
)
|
||||
type AppTemplateInterface interface {
|
||||
ListApps(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error)
|
||||
DescribeApp(id string) (*App, error)
|
||||
DeleteApp(id string) error
|
||||
CreateApp(request *CreateAppRequest) (*CreateAppResponse, error)
|
||||
ModifyApp(appId string, request *ModifyAppRequest) error
|
||||
DeleteAppVersion(id string) error
|
||||
ModifyAppVersion(id string, request *ModifyAppVersionRequest) error
|
||||
DescribeAppVersion(id string) (*AppVersion, error)
|
||||
CreateAppVersion(request *CreateAppVersionRequest) (*CreateAppVersionResponse, error)
|
||||
ValidatePackage(request *ValidatePackageRequest) (*ValidatePackageResponse, error)
|
||||
GetAppVersionPackage(appId, versionId string) (*GetAppVersionPackageResponse, error)
|
||||
DoAppAction(appId string, request *ActionRequest) error
|
||||
DoAppVersionAction(versionId string, request *ActionRequest) error
|
||||
GetAppVersionFiles(versionId string, request *GetAppVersionFilesRequest) (*GetAppVersionPackageFilesResponse, error)
|
||||
ListAppVersionAudits(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error)
|
||||
ListAppVersionReviews(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error)
|
||||
ListAppVersions(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error)
|
||||
}
|
||||
|
||||
func ListApps(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
|
||||
client, err := cs.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
type appTemplateOperator struct {
|
||||
opClient openpitrix.Client
|
||||
}
|
||||
|
||||
func newAppTemplateOperator(opClient openpitrix.Client) AppTemplateInterface {
|
||||
return &appTemplateOperator{
|
||||
opClient: opClient,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *appTemplateOperator) ListApps(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
|
||||
|
||||
describeAppsRequest := &pb.DescribeAppsRequest{}
|
||||
if keyword := conditions.Match["keyword"]; keyword != "" {
|
||||
if keyword := conditions.Match[Keyword]; keyword != "" {
|
||||
describeAppsRequest.SearchWord = &wrappers.StringValue{Value: keyword}
|
||||
}
|
||||
if appId := conditions.Match["app_id"]; appId != "" {
|
||||
if appId := conditions.Match[AppId]; appId != "" {
|
||||
describeAppsRequest.AppId = strings.Split(appId, "|")
|
||||
}
|
||||
if isv := conditions.Match["isv"]; isv != "" {
|
||||
if isv := conditions.Match[ISV]; isv != "" {
|
||||
describeAppsRequest.Isv = strings.Split(isv, "|")
|
||||
}
|
||||
if categoryId := conditions.Match["category_id"]; categoryId != "" {
|
||||
if categoryId := conditions.Match[CategoryId]; categoryId != "" {
|
||||
describeAppsRequest.CategoryId = strings.Split(categoryId, "|")
|
||||
}
|
||||
if repoId := conditions.Match["repo"]; repoId != "" {
|
||||
if repoId := conditions.Match[RepoId]; repoId != "" {
|
||||
// hard code, app template in built-in repo has no repo_id attribute
|
||||
if repoId == BuiltinRepoId {
|
||||
describeAppsRequest.RepoId = []string{"\u0000"}
|
||||
@@ -67,7 +84,7 @@ func ListApps(conditions *params.Conditions, orderBy string, reverse bool, limit
|
||||
describeAppsRequest.RepoId = strings.Split(repoId, "|")
|
||||
}
|
||||
}
|
||||
if status := conditions.Match["status"]; status != "" {
|
||||
if status := conditions.Match[Status]; status != "" {
|
||||
describeAppsRequest.Status = strings.Split(status, "|")
|
||||
}
|
||||
if orderBy != "" {
|
||||
@@ -76,7 +93,7 @@ func ListApps(conditions *params.Conditions, orderBy string, reverse bool, limit
|
||||
describeAppsRequest.Reverse = &wrappers.BoolValue{Value: reverse}
|
||||
describeAppsRequest.Limit = uint32(limit)
|
||||
describeAppsRequest.Offset = uint32(offset)
|
||||
resp, err := client.App().DescribeApps(openpitrix.SystemContext(), describeAppsRequest)
|
||||
resp, err := c.opClient.DescribeApps(openpitrix.SystemContext(), describeAppsRequest)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
@@ -85,19 +102,14 @@ func ListApps(conditions *params.Conditions, orderBy string, reverse bool, limit
|
||||
items := make([]interface{}, 0)
|
||||
|
||||
for _, item := range resp.AppSet {
|
||||
items = append(items, utils.ConvertApp(item))
|
||||
items = append(items, convertApp(item))
|
||||
}
|
||||
|
||||
return &models.PageableResponse{Items: items, TotalCount: int(resp.TotalCount)}, nil
|
||||
}
|
||||
|
||||
func DescribeApp(id string) (*types.App, error) {
|
||||
op, err := cs.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
resp, err := op.App().DescribeApps(openpitrix.SystemContext(), &pb.DescribeAppsRequest{
|
||||
func (c *appTemplateOperator) DescribeApp(id string) (*App, error) {
|
||||
resp, err := c.opClient.DescribeApps(openpitrix.SystemContext(), &pb.DescribeAppsRequest{
|
||||
AppId: []string{id},
|
||||
Limit: 1,
|
||||
})
|
||||
@@ -106,10 +118,10 @@ func DescribeApp(id string) (*types.App, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var app *types.App
|
||||
var app *App
|
||||
|
||||
if len(resp.AppSet) > 0 {
|
||||
app = utils.ConvertApp(resp.AppSet[0])
|
||||
app = convertApp(resp.AppSet[0])
|
||||
return app, nil
|
||||
} else {
|
||||
err := status.New(codes.NotFound, "resource not found").Err()
|
||||
@@ -118,13 +130,8 @@ func DescribeApp(id string) (*types.App, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func DeleteApp(id string) error {
|
||||
op, err := cs.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
_, err = op.App().DeleteApps(openpitrix.SystemContext(), &pb.DeleteAppsRequest{
|
||||
func (c *appTemplateOperator) DeleteApp(id string) error {
|
||||
_, err := c.opClient.DeleteApps(openpitrix.SystemContext(), &pb.DeleteAppsRequest{
|
||||
AppId: []string{id},
|
||||
})
|
||||
if err != nil {
|
||||
@@ -134,12 +141,7 @@ func DeleteApp(id string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func CreateApp(request *types.CreateAppRequest) (*types.CreateAppResponse, error) {
|
||||
op, err := cs.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
func (c *appTemplateOperator) CreateApp(request *CreateAppRequest) (*CreateAppResponse, error) {
|
||||
createAppRequest := &pb.CreateAppRequest{
|
||||
Name: &wrappers.StringValue{Value: request.Name},
|
||||
VersionType: &wrappers.StringValue{Value: request.VersionType},
|
||||
@@ -154,25 +156,18 @@ func CreateApp(request *types.CreateAppRequest) (*types.CreateAppResponse, error
|
||||
if request.Isv != "" {
|
||||
createAppRequest.Isv = &wrappers.StringValue{Value: request.Isv}
|
||||
}
|
||||
resp, err := op.App().CreateApp(openpitrix.ContextWithUsername(request.Username), createAppRequest)
|
||||
resp, err := c.opClient.CreateApp(openpitrix.ContextWithUsername(request.Username), createAppRequest)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
return &types.CreateAppResponse{
|
||||
return &CreateAppResponse{
|
||||
AppID: resp.GetAppId().GetValue(),
|
||||
VersionID: resp.GetVersionId().GetValue(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func PatchApp(appId string, request *types.ModifyAppRequest) error {
|
||||
client, err := cs.ClientSets().OpenPitrix()
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *appTemplateOperator) ModifyApp(appId string, request *ModifyAppRequest) error {
|
||||
// upload app attachment
|
||||
if request.AttachmentContent != nil {
|
||||
uploadAttachmentRequest := &pb.UploadAppAttachmentRequest{
|
||||
@@ -186,7 +181,7 @@ func PatchApp(appId string, request *types.ModifyAppRequest) error {
|
||||
uploadAttachmentRequest.Sequence = &wrappers.UInt32Value{Value: uint32(*request.Sequence)}
|
||||
}
|
||||
|
||||
_, err := client.App().UploadAppAttachment(openpitrix.SystemContext(), uploadAttachmentRequest)
|
||||
_, err := c.opClient.UploadAppAttachment(openpitrix.SystemContext(), uploadAttachmentRequest)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
@@ -229,7 +224,7 @@ func PatchApp(appId string, request *types.ModifyAppRequest) error {
|
||||
patchAppRequest.Tos = &wrappers.StringValue{Value: *request.Tos}
|
||||
}
|
||||
|
||||
_, err = client.App().ModifyApp(openpitrix.SystemContext(), patchAppRequest)
|
||||
_, err := c.opClient.ModifyApp(openpitrix.SystemContext(), patchAppRequest)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
@@ -239,12 +234,7 @@ func PatchApp(appId string, request *types.ModifyAppRequest) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func CreateAppVersion(request *types.CreateAppVersionRequest) (*types.CreateAppVersionResponse, error) {
|
||||
op, err := cs.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
func (c *appTemplateOperator) CreateAppVersion(request *CreateAppVersionRequest) (*CreateAppVersionResponse, error) {
|
||||
createAppVersionRequest := &pb.CreateAppVersionRequest{
|
||||
AppId: &wrappers.StringValue{Value: request.AppId},
|
||||
Name: &wrappers.StringValue{Value: request.Name},
|
||||
@@ -256,24 +246,17 @@ func CreateAppVersion(request *types.CreateAppVersionRequest) (*types.CreateAppV
|
||||
createAppVersionRequest.Package = &wrappers.BytesValue{Value: request.Package}
|
||||
}
|
||||
|
||||
resp, err := op.App().CreateAppVersion(openpitrix.ContextWithUsername(request.Username), createAppVersionRequest)
|
||||
resp, err := c.opClient.CreateAppVersion(openpitrix.ContextWithUsername(request.Username), createAppVersionRequest)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
return &types.CreateAppVersionResponse{
|
||||
return &CreateAppVersionResponse{
|
||||
VersionId: resp.GetVersionId().GetValue(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func ValidatePackage(request *types.ValidatePackageRequest) (*types.ValidatePackageResponse, error) {
|
||||
client, err := cs.ClientSets().OpenPitrix()
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (c *appTemplateOperator) ValidatePackage(request *ValidatePackageRequest) (*ValidatePackageResponse, error) {
|
||||
r := &pb.ValidatePackageRequest{}
|
||||
|
||||
if request.VersionPackage != nil {
|
||||
@@ -283,14 +266,14 @@ func ValidatePackage(request *types.ValidatePackageRequest) (*types.ValidatePack
|
||||
r.VersionType = request.VersionType
|
||||
}
|
||||
|
||||
resp, err := client.App().ValidatePackage(openpitrix.SystemContext(), r)
|
||||
resp, err := c.opClient.ValidatePackage(openpitrix.SystemContext(), r)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := &types.ValidatePackageResponse{}
|
||||
result := &ValidatePackageResponse{}
|
||||
|
||||
if resp.Error != nil {
|
||||
result.Error = resp.Error.Value
|
||||
@@ -316,13 +299,8 @@ func ValidatePackage(request *types.ValidatePackageRequest) (*types.ValidatePack
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func DeleteAppVersion(id string) error {
|
||||
op, err := cs.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
_, err = op.App().DeleteAppVersion(openpitrix.SystemContext(), &pb.DeleteAppVersionRequest{
|
||||
func (c *appTemplateOperator) DeleteAppVersion(id string) error {
|
||||
_, err := c.opClient.DeleteAppVersion(openpitrix.SystemContext(), &pb.DeleteAppVersionRequest{
|
||||
VersionId: &wrappers.StringValue{Value: id},
|
||||
})
|
||||
if err != nil {
|
||||
@@ -332,12 +310,7 @@ func DeleteAppVersion(id string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func PatchAppVersion(id string, request *types.ModifyAppVersionRequest) error {
|
||||
op, err := cs.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
func (c *appTemplateOperator) ModifyAppVersion(id string, request *ModifyAppVersionRequest) error {
|
||||
modifyAppVersionRequest := &pb.ModifyAppVersionRequest{
|
||||
VersionId: &wrappers.StringValue{Value: id},
|
||||
}
|
||||
@@ -355,7 +328,7 @@ func PatchAppVersion(id string, request *types.ModifyAppVersionRequest) error {
|
||||
modifyAppVersionRequest.PackageFiles = request.PackageFiles
|
||||
}
|
||||
|
||||
_, err = op.App().ModifyAppVersion(openpitrix.SystemContext(), modifyAppVersionRequest)
|
||||
_, err := c.opClient.ModifyAppVersion(openpitrix.SystemContext(), modifyAppVersionRequest)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
@@ -363,13 +336,8 @@ func PatchAppVersion(id string, request *types.ModifyAppVersionRequest) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func DescribeAppVersion(id string) (*types.AppVersion, error) {
|
||||
op, err := cs.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
resp, err := op.App().DescribeAppVersions(openpitrix.SystemContext(), &pb.DescribeAppVersionsRequest{
|
||||
func (c *appTemplateOperator) DescribeAppVersion(id string) (*AppVersion, error) {
|
||||
resp, err := c.opClient.DescribeAppVersions(openpitrix.SystemContext(), &pb.DescribeAppVersionsRequest{
|
||||
VersionId: []string{id},
|
||||
Limit: 1,
|
||||
})
|
||||
@@ -378,10 +346,10 @@ func DescribeAppVersion(id string) (*types.AppVersion, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var app *types.AppVersion
|
||||
var app *AppVersion
|
||||
|
||||
if len(resp.AppVersionSet) > 0 {
|
||||
app = utils.ConvertAppVersion(resp.AppVersionSet[0])
|
||||
app = convertAppVersion(resp.AppVersionSet[0])
|
||||
return app, nil
|
||||
} else {
|
||||
err := status.New(codes.NotFound, "resource not found").Err()
|
||||
@@ -390,13 +358,8 @@ func DescribeAppVersion(id string) (*types.AppVersion, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func GetAppVersionPackage(appId, versionId string) (*types.GetAppVersionPackageResponse, error) {
|
||||
op, err := cs.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
resp, err := op.App().GetAppVersionPackage(openpitrix.SystemContext(), &pb.GetAppVersionPackageRequest{
|
||||
func (c *appTemplateOperator) GetAppVersionPackage(appId, versionId string) (*GetAppVersionPackageResponse, error) {
|
||||
resp, err := c.opClient.GetAppVersionPackage(openpitrix.SystemContext(), &pb.GetAppVersionPackageRequest{
|
||||
VersionId: &wrappers.StringValue{Value: versionId},
|
||||
})
|
||||
if err != nil {
|
||||
@@ -404,7 +367,7 @@ func GetAppVersionPackage(appId, versionId string) (*types.GetAppVersionPackageR
|
||||
return nil, err
|
||||
}
|
||||
|
||||
app := &types.GetAppVersionPackageResponse{
|
||||
app := &GetAppVersionPackageResponse{
|
||||
AppId: appId,
|
||||
VersionId: versionId,
|
||||
}
|
||||
@@ -416,21 +379,14 @@ func GetAppVersionPackage(appId, versionId string) (*types.GetAppVersionPackageR
|
||||
return app, nil
|
||||
}
|
||||
|
||||
func DoAppAction(appId string, request *types.ActionRequest) error {
|
||||
op, err := cs.ClientSets().OpenPitrix()
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *appTemplateOperator) DoAppAction(appId string, request *ActionRequest) error {
|
||||
switch request.Action {
|
||||
|
||||
case "recover":
|
||||
case ActionRecover:
|
||||
// TODO openpitrix need to implement app recover interface
|
||||
resp, err := op.App().DescribeAppVersions(openpitrix.SystemContext(), &pb.DescribeAppVersionsRequest{
|
||||
resp, err := c.opClient.DescribeAppVersions(openpitrix.SystemContext(), &pb.DescribeAppVersionsRequest{
|
||||
AppId: []string{appId},
|
||||
Status: []string{"suspended"},
|
||||
Status: []string{StatusSuspended},
|
||||
Limit: 200,
|
||||
Offset: 0,
|
||||
})
|
||||
@@ -440,7 +396,7 @@ func DoAppAction(appId string, request *types.ActionRequest) error {
|
||||
}
|
||||
for _, version := range resp.AppVersionSet {
|
||||
|
||||
_, err = op.App().RecoverAppVersion(openpitrix.SystemContext(), &pb.RecoverAppVersionRequest{
|
||||
_, err = c.opClient.RecoverAppVersion(openpitrix.SystemContext(), &pb.RecoverAppVersionRequest{
|
||||
VersionId: version.VersionId,
|
||||
})
|
||||
if err != nil {
|
||||
@@ -449,11 +405,11 @@ func DoAppAction(appId string, request *types.ActionRequest) error {
|
||||
}
|
||||
}
|
||||
|
||||
case "suspend":
|
||||
case ActionSuspend:
|
||||
// TODO openpitrix need to implement app suspend interface
|
||||
resp, err := op.App().DescribeAppVersions(openpitrix.SystemContext(), &pb.DescribeAppVersionsRequest{
|
||||
resp, err := c.opClient.DescribeAppVersions(openpitrix.SystemContext(), &pb.DescribeAppVersionsRequest{
|
||||
AppId: []string{appId},
|
||||
Status: []string{"active"},
|
||||
Status: []string{StatusActive},
|
||||
Limit: 200,
|
||||
Offset: 0,
|
||||
})
|
||||
@@ -462,7 +418,7 @@ func DoAppAction(appId string, request *types.ActionRequest) error {
|
||||
return err
|
||||
}
|
||||
for _, version := range resp.AppVersionSet {
|
||||
_, err = op.App().SuspendAppVersion(openpitrix.SystemContext(), &pb.SuspendAppVersionRequest{
|
||||
_, err = c.opClient.SuspendAppVersion(openpitrix.SystemContext(), &pb.SuspendAppVersionRequest{
|
||||
VersionId: version.VersionId,
|
||||
})
|
||||
|
||||
@@ -473,7 +429,7 @@ func DoAppAction(appId string, request *types.ActionRequest) error {
|
||||
}
|
||||
|
||||
default:
|
||||
err = status.New(codes.InvalidArgument, "action not support").Err()
|
||||
err := status.New(codes.InvalidArgument, "action not support").Err()
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
@@ -481,42 +437,36 @@ func DoAppAction(appId string, request *types.ActionRequest) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func DoAppVersionAction(versionId string, request *types.ActionRequest) error {
|
||||
op, err := cs.ClientSets().OpenPitrix()
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *appTemplateOperator) DoAppVersionAction(versionId string, request *ActionRequest) error {
|
||||
var err error
|
||||
switch request.Action {
|
||||
case "cancel":
|
||||
_, err = op.App().CancelAppVersion(openpitrix.ContextWithUsername(request.Username), &pb.CancelAppVersionRequest{
|
||||
case ActionCancel:
|
||||
_, err = c.opClient.CancelAppVersion(openpitrix.ContextWithUsername(request.Username), &pb.CancelAppVersionRequest{
|
||||
VersionId: &wrappers.StringValue{Value: versionId},
|
||||
})
|
||||
case "pass":
|
||||
_, err = op.App().AdminPassAppVersion(openpitrix.ContextWithUsername(request.Username), &pb.PassAppVersionRequest{
|
||||
case ActionPass:
|
||||
_, err = c.opClient.AdminPassAppVersion(openpitrix.ContextWithUsername(request.Username), &pb.PassAppVersionRequest{
|
||||
VersionId: &wrappers.StringValue{Value: versionId},
|
||||
})
|
||||
case "recover":
|
||||
_, err = op.App().RecoverAppVersion(openpitrix.ContextWithUsername(request.Username), &pb.RecoverAppVersionRequest{
|
||||
case ActionRecover:
|
||||
_, err = c.opClient.RecoverAppVersion(openpitrix.ContextWithUsername(request.Username), &pb.RecoverAppVersionRequest{
|
||||
VersionId: &wrappers.StringValue{Value: versionId},
|
||||
})
|
||||
case "reject":
|
||||
_, err = op.App().AdminRejectAppVersion(openpitrix.ContextWithUsername(request.Username), &pb.RejectAppVersionRequest{
|
||||
case ActionReject:
|
||||
_, err = c.opClient.AdminRejectAppVersion(openpitrix.ContextWithUsername(request.Username), &pb.RejectAppVersionRequest{
|
||||
VersionId: &wrappers.StringValue{Value: versionId},
|
||||
Message: &wrappers.StringValue{Value: request.Message},
|
||||
})
|
||||
case "submit":
|
||||
_, err = op.App().SubmitAppVersion(openpitrix.ContextWithUsername(request.Username), &pb.SubmitAppVersionRequest{
|
||||
case ActionSubmit:
|
||||
_, err = c.opClient.SubmitAppVersion(openpitrix.ContextWithUsername(request.Username), &pb.SubmitAppVersionRequest{
|
||||
VersionId: &wrappers.StringValue{Value: versionId},
|
||||
})
|
||||
case "suspend":
|
||||
_, err = op.App().SuspendAppVersion(openpitrix.ContextWithUsername(request.Username), &pb.SuspendAppVersionRequest{
|
||||
case ActionSuspend:
|
||||
_, err = c.opClient.SuspendAppVersion(openpitrix.ContextWithUsername(request.Username), &pb.SuspendAppVersionRequest{
|
||||
VersionId: &wrappers.StringValue{Value: versionId},
|
||||
})
|
||||
case "release":
|
||||
_, err = op.App().ReleaseAppVersion(openpitrix.ContextWithUsername(request.Username), &pb.ReleaseAppVersionRequest{
|
||||
case ActionRelease:
|
||||
_, err = c.opClient.ReleaseAppVersion(openpitrix.ContextWithUsername(request.Username), &pb.ReleaseAppVersionRequest{
|
||||
VersionId: &wrappers.StringValue{Value: versionId},
|
||||
})
|
||||
default:
|
||||
@@ -531,12 +481,7 @@ func DoAppVersionAction(versionId string, request *types.ActionRequest) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetAppVersionFiles(versionId string, request *types.GetAppVersionFilesRequest) (*types.GetAppVersionPackageFilesResponse, error) {
|
||||
op, err := cs.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
func (c *appTemplateOperator) GetAppVersionFiles(versionId string, request *GetAppVersionFilesRequest) (*GetAppVersionPackageFilesResponse, error) {
|
||||
getAppVersionPackageFilesRequest := &pb.GetAppVersionPackageFilesRequest{
|
||||
VersionId: &wrappers.StringValue{Value: versionId},
|
||||
}
|
||||
@@ -544,13 +489,13 @@ func GetAppVersionFiles(versionId string, request *types.GetAppVersionFilesReque
|
||||
getAppVersionPackageFilesRequest.Files = request.Files
|
||||
}
|
||||
|
||||
resp, err := op.App().GetAppVersionPackageFiles(openpitrix.SystemContext(), getAppVersionPackageFilesRequest)
|
||||
resp, err := c.opClient.GetAppVersionPackageFiles(openpitrix.SystemContext(), getAppVersionPackageFilesRequest)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
version := &types.GetAppVersionPackageFilesResponse{
|
||||
version := &GetAppVersionPackageFilesResponse{
|
||||
VersionId: versionId,
|
||||
}
|
||||
|
||||
@@ -564,14 +509,7 @@ func GetAppVersionFiles(versionId string, request *types.GetAppVersionFilesReque
|
||||
return version, nil
|
||||
}
|
||||
|
||||
func ListAppVersionAudits(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
|
||||
client, err := cs.ClientSets().OpenPitrix()
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (c *appTemplateOperator) ListAppVersionAudits(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
|
||||
describeAppVersionAudits := &pb.DescribeAppVersionAuditsRequest{}
|
||||
|
||||
if keyword := conditions.Match["keyword"]; keyword != "" {
|
||||
@@ -589,10 +527,10 @@ func ListAppVersionAudits(conditions *params.Conditions, orderBy string, reverse
|
||||
if orderBy != "" {
|
||||
describeAppVersionAudits.SortKey = &wrappers.StringValue{Value: orderBy}
|
||||
}
|
||||
describeAppVersionAudits.Reverse = &wrappers.BoolValue{Value: !reverse}
|
||||
describeAppVersionAudits.Reverse = &wrappers.BoolValue{Value: reverse}
|
||||
describeAppVersionAudits.Limit = uint32(limit)
|
||||
describeAppVersionAudits.Offset = uint32(offset)
|
||||
resp, err := client.App().DescribeAppVersionAudits(openpitrix.SystemContext(), describeAppVersionAudits)
|
||||
resp, err := c.opClient.DescribeAppVersionAudits(openpitrix.SystemContext(), describeAppVersionAudits)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
@@ -602,21 +540,14 @@ func ListAppVersionAudits(conditions *params.Conditions, orderBy string, reverse
|
||||
items := make([]interface{}, 0)
|
||||
|
||||
for _, item := range resp.AppVersionAuditSet {
|
||||
appVersion := utils.ConvertAppVersionAudit(item)
|
||||
appVersion := convertAppVersionAudit(item)
|
||||
items = append(items, appVersion)
|
||||
}
|
||||
|
||||
return &models.PageableResponse{Items: items, TotalCount: int(resp.TotalCount)}, nil
|
||||
}
|
||||
|
||||
func ListAppVersionReviews(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
|
||||
client, err := cs.ClientSets().OpenPitrix()
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (c *appTemplateOperator) ListAppVersionReviews(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
|
||||
describeAppVersionReviews := &pb.DescribeAppVersionReviewsRequest{}
|
||||
|
||||
if keyword := conditions.Match["keyword"]; keyword != "" {
|
||||
@@ -628,11 +559,11 @@ func ListAppVersionReviews(conditions *params.Conditions, orderBy string, revers
|
||||
if orderBy != "" {
|
||||
describeAppVersionReviews.SortKey = &wrappers.StringValue{Value: orderBy}
|
||||
}
|
||||
describeAppVersionReviews.Reverse = &wrappers.BoolValue{Value: !reverse}
|
||||
describeAppVersionReviews.Reverse = &wrappers.BoolValue{Value: reverse}
|
||||
describeAppVersionReviews.Limit = uint32(limit)
|
||||
describeAppVersionReviews.Offset = uint32(offset)
|
||||
// TODO icon is needed
|
||||
resp, err := client.App().DescribeAppVersionReviews(openpitrix.SystemContext(), describeAppVersionReviews)
|
||||
resp, err := c.opClient.DescribeAppVersionReviews(openpitrix.SystemContext(), describeAppVersionReviews)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
@@ -642,21 +573,14 @@ func ListAppVersionReviews(conditions *params.Conditions, orderBy string, revers
|
||||
items := make([]interface{}, 0)
|
||||
|
||||
for _, item := range resp.AppVersionReviewSet {
|
||||
appVersion := utils.ConvertAppVersionReview(item)
|
||||
appVersion := convertAppVersionReview(item)
|
||||
items = append(items, appVersion)
|
||||
}
|
||||
|
||||
return &models.PageableResponse{Items: items, TotalCount: int(resp.TotalCount)}, nil
|
||||
}
|
||||
|
||||
func ListAppVersions(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
|
||||
client, err := cs.ClientSets().OpenPitrix()
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (c *appTemplateOperator) ListAppVersions(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
|
||||
describeAppVersionsRequest := &pb.DescribeAppVersionsRequest{}
|
||||
|
||||
if keyword := conditions.Match["keyword"]; keyword != "" {
|
||||
@@ -671,10 +595,10 @@ func ListAppVersions(conditions *params.Conditions, orderBy string, reverse bool
|
||||
if orderBy != "" {
|
||||
describeAppVersionsRequest.SortKey = &wrappers.StringValue{Value: orderBy}
|
||||
}
|
||||
describeAppVersionsRequest.Reverse = &wrappers.BoolValue{Value: !reverse}
|
||||
describeAppVersionsRequest.Reverse = &wrappers.BoolValue{Value: reverse}
|
||||
describeAppVersionsRequest.Limit = uint32(limit)
|
||||
describeAppVersionsRequest.Offset = uint32(offset)
|
||||
resp, err := client.App().DescribeAppVersions(openpitrix.SystemContext(), describeAppVersionsRequest)
|
||||
resp, err := c.opClient.DescribeAppVersions(openpitrix.SystemContext(), describeAppVersionsRequest)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
@@ -684,7 +608,7 @@ func ListAppVersions(conditions *params.Conditions, orderBy string, reverse bool
|
||||
items := make([]interface{}, 0)
|
||||
|
||||
for _, item := range resp.AppVersionSet {
|
||||
appVersion := utils.ConvertAppVersion(item)
|
||||
appVersion := convertAppVersion(item)
|
||||
items = append(items, appVersion)
|
||||
}
|
||||
|
||||
@@ -16,26 +16,32 @@
|
||||
* /
|
||||
*/
|
||||
|
||||
package attachment
|
||||
package openpitrix
|
||||
|
||||
import (
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"k8s.io/klog"
|
||||
"kubesphere.io/kubesphere/pkg/models/openpitrix/type"
|
||||
"kubesphere.io/kubesphere/pkg/models/openpitrix/utils"
|
||||
cs "kubesphere.io/kubesphere/pkg/simple/client"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/openpitrix"
|
||||
"openpitrix.io/openpitrix/pkg/pb"
|
||||
)
|
||||
|
||||
func DescribeAttachment(id string) (*types.Attachment, error) {
|
||||
op, err := cs.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
type AttachmentInterface interface {
|
||||
DescribeAttachment(id string) (*Attachment, error)
|
||||
}
|
||||
|
||||
type attachmentOperator struct {
|
||||
opClient openpitrix.Client
|
||||
}
|
||||
|
||||
func newAttachmentOperator(opClient openpitrix.Client) AttachmentInterface {
|
||||
return &attachmentOperator{
|
||||
opClient: opClient,
|
||||
}
|
||||
resp, err := op.Attachment().GetAttachments(openpitrix.SystemContext(), &pb.GetAttachmentsRequest{
|
||||
}
|
||||
|
||||
func (c *attachmentOperator) DescribeAttachment(id string) (*Attachment, error) {
|
||||
resp, err := c.opClient.GetAttachments(openpitrix.SystemContext(), &pb.GetAttachmentsRequest{
|
||||
AttachmentId: []string{id},
|
||||
})
|
||||
if err != nil {
|
||||
@@ -43,7 +49,7 @@ func DescribeAttachment(id string) (*types.Attachment, error) {
|
||||
return nil, err
|
||||
}
|
||||
if len(resp.Attachments) > 0 {
|
||||
return utils.ConvertAttachment(resp.Attachments[id]), nil
|
||||
return convertAttachment(resp.Attachments[id]), nil
|
||||
} else {
|
||||
err := status.New(codes.NotFound, "resource not found").Err()
|
||||
klog.Error(err)
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2019 The KubeSphere Authors.
|
||||
* Copyright 2020 The KubeSphere Authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,7 +16,7 @@
|
||||
* /
|
||||
*/
|
||||
|
||||
package category
|
||||
package openpitrix
|
||||
|
||||
import (
|
||||
"github.com/golang/protobuf/ptypes/wrappers"
|
||||
@@ -24,20 +24,30 @@ import (
|
||||
"google.golang.org/grpc/status"
|
||||
"k8s.io/klog"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"kubesphere.io/kubesphere/pkg/models/openpitrix/type"
|
||||
"kubesphere.io/kubesphere/pkg/models/openpitrix/utils"
|
||||
"kubesphere.io/kubesphere/pkg/server/params"
|
||||
cs "kubesphere.io/kubesphere/pkg/simple/client"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/openpitrix"
|
||||
"openpitrix.io/openpitrix/pkg/pb"
|
||||
)
|
||||
|
||||
func CreateCategory(request *types.CreateCategoryRequest) (*types.CreateCategoryResponse, error) {
|
||||
op, err := cs.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
type CategoryInterface interface {
|
||||
CreateCategory(request *CreateCategoryRequest) (*CreateCategoryResponse, error)
|
||||
DeleteCategory(id string) error
|
||||
ModifyCategory(id string, request *ModifyCategoryRequest) error
|
||||
ListCategories(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error)
|
||||
DescribeCategory(id string) (*Category, error)
|
||||
}
|
||||
|
||||
type categoryOperator struct {
|
||||
opClient openpitrix.Client
|
||||
}
|
||||
|
||||
func newCategoryOperator(opClient openpitrix.Client) CategoryInterface {
|
||||
return &categoryOperator{
|
||||
opClient: opClient,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *categoryOperator) CreateCategory(request *CreateCategoryRequest) (*CreateCategoryResponse, error) {
|
||||
r := &pb.CreateCategoryRequest{
|
||||
Name: &wrappers.StringValue{Value: request.Name},
|
||||
Locale: &wrappers.StringValue{Value: request.Locale},
|
||||
@@ -47,23 +57,18 @@ func CreateCategory(request *types.CreateCategoryRequest) (*types.CreateCategory
|
||||
r.Icon = &wrappers.BytesValue{Value: request.Icon}
|
||||
}
|
||||
|
||||
resp, err := op.Category().CreateCategory(openpitrix.SystemContext(), r)
|
||||
resp, err := c.opClient.CreateCategory(openpitrix.SystemContext(), r)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
return &types.CreateCategoryResponse{
|
||||
return &CreateCategoryResponse{
|
||||
CategoryId: resp.GetCategoryId().GetValue(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func DeleteCategory(id string) error {
|
||||
op, err := cs.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
_, err = op.Category().DeleteCategories(openpitrix.SystemContext(), &pb.DeleteCategoriesRequest{
|
||||
func (c *categoryOperator) DeleteCategory(id string) error {
|
||||
_, err := c.opClient.DeleteCategories(openpitrix.SystemContext(), &pb.DeleteCategoriesRequest{
|
||||
CategoryId: []string{id},
|
||||
})
|
||||
if err != nil {
|
||||
@@ -73,12 +78,7 @@ func DeleteCategory(id string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func PatchCategory(id string, request *types.ModifyCategoryRequest) error {
|
||||
op, err := cs.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
func (c *categoryOperator) ModifyCategory(id string, request *ModifyCategoryRequest) error {
|
||||
modifyCategoryRequest := &pb.ModifyCategoryRequest{
|
||||
CategoryId: &wrappers.StringValue{Value: id},
|
||||
}
|
||||
@@ -95,7 +95,7 @@ func PatchCategory(id string, request *types.ModifyCategoryRequest) error {
|
||||
modifyCategoryRequest.Icon = &wrappers.BytesValue{Value: request.Icon}
|
||||
}
|
||||
|
||||
_, err = op.Category().ModifyCategory(openpitrix.SystemContext(), modifyCategoryRequest)
|
||||
_, err := c.opClient.ModifyCategory(openpitrix.SystemContext(), modifyCategoryRequest)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
@@ -103,13 +103,8 @@ func PatchCategory(id string, request *types.ModifyCategoryRequest) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func DescribeCategory(id string) (*types.Category, error) {
|
||||
op, err := cs.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
resp, err := op.Category().DescribeCategories(openpitrix.SystemContext(), &pb.DescribeCategoriesRequest{
|
||||
func (c *categoryOperator) DescribeCategory(id string) (*Category, error) {
|
||||
resp, err := c.opClient.DescribeCategories(openpitrix.SystemContext(), &pb.DescribeCategoriesRequest{
|
||||
CategoryId: []string{id},
|
||||
Limit: 1,
|
||||
})
|
||||
@@ -118,10 +113,10 @@ func DescribeCategory(id string) (*types.Category, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var category *types.Category
|
||||
var category *Category
|
||||
|
||||
if len(resp.CategorySet) > 0 {
|
||||
category = utils.ConvertCategory(resp.CategorySet[0])
|
||||
category = convertCategory(resp.CategorySet[0])
|
||||
return category, nil
|
||||
} else {
|
||||
err := status.New(codes.NotFound, "resource not found").Err()
|
||||
@@ -130,26 +125,19 @@ func DescribeCategory(id string) (*types.Category, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func ListCategories(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
|
||||
client, err := cs.ClientSets().OpenPitrix()
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (c *categoryOperator) ListCategories(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
|
||||
req := &pb.DescribeCategoriesRequest{}
|
||||
|
||||
if keyword := conditions.Match["keyword"]; keyword != "" {
|
||||
if keyword := conditions.Match[Keyword]; keyword != "" {
|
||||
req.SearchWord = &wrappers.StringValue{Value: keyword}
|
||||
}
|
||||
if orderBy != "" {
|
||||
req.SortKey = &wrappers.StringValue{Value: orderBy}
|
||||
}
|
||||
req.Reverse = &wrappers.BoolValue{Value: !reverse}
|
||||
req.Reverse = &wrappers.BoolValue{Value: reverse}
|
||||
req.Limit = uint32(limit)
|
||||
req.Offset = uint32(offset)
|
||||
resp, err := client.Category().DescribeCategories(openpitrix.SystemContext(), req)
|
||||
resp, err := c.opClient.DescribeCategories(openpitrix.SystemContext(), req)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
@@ -158,7 +146,7 @@ func ListCategories(conditions *params.Conditions, orderBy string, reverse bool,
|
||||
items := make([]interface{}, 0)
|
||||
|
||||
for _, item := range resp.CategorySet {
|
||||
items = append(items, utils.ConvertCategory(item))
|
||||
items = append(items, convertCategory(item))
|
||||
}
|
||||
|
||||
return &models.PageableResponse{Items: items, TotalCount: int(resp.TotalCount)}, nil
|
||||
49
pkg/models/openpitrix/interface.go
Normal file
49
pkg/models/openpitrix/interface.go
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2020 The KubeSphere 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 openpitrix
|
||||
|
||||
import (
|
||||
"k8s.io/client-go/informers"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/openpitrix"
|
||||
)
|
||||
|
||||
type Interface interface {
|
||||
ApplicationInterface
|
||||
AppTemplateInterface
|
||||
AttachmentInterface
|
||||
CategoryInterface
|
||||
RepoInterface
|
||||
}
|
||||
type openpitrixOperator struct {
|
||||
ApplicationInterface
|
||||
AppTemplateInterface
|
||||
AttachmentInterface
|
||||
CategoryInterface
|
||||
RepoInterface
|
||||
}
|
||||
|
||||
func NewOpenpitrixOperator(informers informers.SharedInformerFactory, opClient openpitrix.Client) Interface {
|
||||
return &openpitrixOperator{
|
||||
ApplicationInterface: newApplicationOperator(informers, opClient),
|
||||
AppTemplateInterface: newAppTemplateOperator(opClient),
|
||||
AttachmentInterface: newAttachmentOperator(opClient),
|
||||
CategoryInterface: newCategoryOperator(opClient),
|
||||
RepoInterface: newRepoOperator(opClient),
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2019 The KubeSphere Authors.
|
||||
* Copyright 2020 The KubeSphere Authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,7 +16,7 @@
|
||||
* /
|
||||
*/
|
||||
|
||||
package repo
|
||||
package openpitrix
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -25,21 +25,34 @@ import (
|
||||
"google.golang.org/grpc/status"
|
||||
"k8s.io/klog"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"kubesphere.io/kubesphere/pkg/models/openpitrix/type"
|
||||
"kubesphere.io/kubesphere/pkg/models/openpitrix/utils"
|
||||
"kubesphere.io/kubesphere/pkg/server/params"
|
||||
cs "kubesphere.io/kubesphere/pkg/simple/client"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/openpitrix"
|
||||
"openpitrix.io/openpitrix/pkg/pb"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func CreateRepo(request *types.CreateRepoRequest) (*types.CreateRepoResponse, error) {
|
||||
op, err := cs.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
type RepoInterface interface {
|
||||
CreateRepo(request *CreateRepoRequest) (*CreateRepoResponse, error)
|
||||
DeleteRepo(id string) error
|
||||
ModifyRepo(id string, request *ModifyRepoRequest) error
|
||||
DescribeRepo(id string) (*Repo, error)
|
||||
ListRepos(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error)
|
||||
ValidateRepo(request *ValidateRepoRequest) (*ValidateRepoResponse, error)
|
||||
DoRepoAction(repoId string, request *RepoActionRequest) error
|
||||
ListRepoEvents(repoId string, conditions *params.Conditions, limit, offset int) (*models.PageableResponse, error)
|
||||
}
|
||||
|
||||
type repoOperator struct {
|
||||
opClient openpitrix.Client
|
||||
}
|
||||
|
||||
func newRepoOperator(opClient openpitrix.Client) RepoInterface {
|
||||
return &repoOperator{
|
||||
opClient: opClient,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *repoOperator) CreateRepo(request *CreateRepoRequest) (*CreateRepoResponse, error) {
|
||||
createRepoRequest := &pb.CreateRepoRequest{
|
||||
Name: &wrappers.StringValue{Value: request.Name},
|
||||
Description: &wrappers.StringValue{Value: request.Description},
|
||||
@@ -58,23 +71,18 @@ func CreateRepo(request *types.CreateRepoRequest) (*types.CreateRepoResponse, er
|
||||
createRepoRequest.Labels = &wrappers.StringValue{Value: fmt.Sprintf("workspace=%s", *request.Workspace)}
|
||||
}
|
||||
|
||||
resp, err := op.Repo().CreateRepo(openpitrix.SystemContext(), createRepoRequest)
|
||||
resp, err := c.opClient.CreateRepo(openpitrix.SystemContext(), createRepoRequest)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
return &types.CreateRepoResponse{
|
||||
return &CreateRepoResponse{
|
||||
RepoID: resp.GetRepoId().GetValue(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func DeleteRepo(id string) error {
|
||||
op, err := cs.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
_, err = op.Repo().DeleteRepos(openpitrix.SystemContext(), &pb.DeleteReposRequest{
|
||||
func (c *repoOperator) DeleteRepo(id string) error {
|
||||
_, err := c.opClient.DeleteRepos(openpitrix.SystemContext(), &pb.DeleteReposRequest{
|
||||
RepoId: []string{id},
|
||||
})
|
||||
if err != nil {
|
||||
@@ -84,12 +92,7 @@ func DeleteRepo(id string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func PatchRepo(id string, request *types.ModifyRepoRequest) error {
|
||||
op, err := cs.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
func (c *repoOperator) ModifyRepo(id string, request *ModifyRepoRequest) error {
|
||||
modifyRepoRequest := &pb.ModifyRepoRequest{
|
||||
RepoId: &wrappers.StringValue{Value: id},
|
||||
}
|
||||
@@ -126,7 +129,7 @@ func PatchRepo(id string, request *types.ModifyRepoRequest) error {
|
||||
modifyRepoRequest.Labels = &wrappers.StringValue{Value: fmt.Sprintf("workspace=%s", *request.Workspace)}
|
||||
}
|
||||
|
||||
_, err = op.Repo().ModifyRepo(openpitrix.SystemContext(), modifyRepoRequest)
|
||||
_, err := c.opClient.ModifyRepo(openpitrix.SystemContext(), modifyRepoRequest)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
@@ -134,13 +137,8 @@ func PatchRepo(id string, request *types.ModifyRepoRequest) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func DescribeRepo(id string) (*types.Repo, error) {
|
||||
op, err := cs.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
resp, err := op.Repo().DescribeRepos(openpitrix.SystemContext(), &pb.DescribeReposRequest{
|
||||
func (c *repoOperator) DescribeRepo(id string) (*Repo, error) {
|
||||
resp, err := c.opClient.DescribeRepos(openpitrix.SystemContext(), &pb.DescribeReposRequest{
|
||||
RepoId: []string{id},
|
||||
Limit: 1,
|
||||
})
|
||||
@@ -149,10 +147,10 @@ func DescribeRepo(id string) (*types.Repo, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var repo *types.Repo
|
||||
var repo *Repo
|
||||
|
||||
if len(resp.RepoSet) > 0 {
|
||||
repo = utils.ConvertRepo(resp.RepoSet[0])
|
||||
repo = convertRepo(resp.RepoSet[0])
|
||||
return repo, nil
|
||||
} else {
|
||||
err := status.New(codes.NotFound, "resource not found").Err()
|
||||
@@ -161,41 +159,34 @@ func DescribeRepo(id string) (*types.Repo, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func ListRepos(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
|
||||
client, err := cs.ClientSets().OpenPitrix()
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (c *repoOperator) ListRepos(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
|
||||
req := &pb.DescribeReposRequest{}
|
||||
|
||||
if keyword := conditions.Match["keyword"]; keyword != "" {
|
||||
if keyword := conditions.Match[Keyword]; keyword != "" {
|
||||
req.SearchWord = &wrappers.StringValue{Value: keyword}
|
||||
}
|
||||
if status := conditions.Match["status"]; status != "" {
|
||||
if status := conditions.Match[Status]; status != "" {
|
||||
req.Status = strings.Split(status, "|")
|
||||
}
|
||||
if typeStr := conditions.Match["type"]; typeStr != "" {
|
||||
if typeStr := conditions.Match[Type]; typeStr != "" {
|
||||
req.Type = strings.Split(typeStr, "|")
|
||||
}
|
||||
if visibility := conditions.Match["visibility"]; visibility != "" {
|
||||
if visibility := conditions.Match[Visibility]; visibility != "" {
|
||||
req.Visibility = strings.Split(visibility, "|")
|
||||
}
|
||||
if status := conditions.Match["status"]; status != "" {
|
||||
if status := conditions.Match[Status]; status != "" {
|
||||
req.Status = strings.Split(status, "|")
|
||||
}
|
||||
if workspace := conditions.Match["workspace"]; workspace != "" {
|
||||
if workspace := conditions.Match[WorkspaceLabel]; workspace != "" {
|
||||
req.Label = &wrappers.StringValue{Value: fmt.Sprintf("workspace=%s", workspace)}
|
||||
}
|
||||
if orderBy != "" {
|
||||
req.SortKey = &wrappers.StringValue{Value: orderBy}
|
||||
}
|
||||
req.Reverse = &wrappers.BoolValue{Value: !reverse}
|
||||
req.Reverse = &wrappers.BoolValue{Value: reverse}
|
||||
req.Limit = uint32(limit)
|
||||
req.Offset = uint32(offset)
|
||||
resp, err := client.Repo().DescribeRepos(openpitrix.SystemContext(), req)
|
||||
resp, err := c.opClient.DescribeRepos(openpitrix.SystemContext(), req)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
@@ -204,21 +195,14 @@ func ListRepos(conditions *params.Conditions, orderBy string, reverse bool, limi
|
||||
items := make([]interface{}, 0)
|
||||
|
||||
for _, item := range resp.RepoSet {
|
||||
items = append(items, utils.ConvertRepo(item))
|
||||
items = append(items, convertRepo(item))
|
||||
}
|
||||
|
||||
return &models.PageableResponse{Items: items, TotalCount: int(resp.TotalCount)}, nil
|
||||
}
|
||||
|
||||
func ValidateRepo(request *types.ValidateRepoRequest) (*types.ValidateRepoResponse, error) {
|
||||
client, err := cs.ClientSets().OpenPitrix()
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, err := client.Repo().ValidateRepo(openpitrix.SystemContext(), &pb.ValidateRepoRequest{
|
||||
func (c *repoOperator) ValidateRepo(request *ValidateRepoRequest) (*ValidateRepoResponse, error) {
|
||||
resp, err := c.opClient.ValidateRepo(openpitrix.SystemContext(), &pb.ValidateRepoRequest{
|
||||
Type: &wrappers.StringValue{Value: request.Type},
|
||||
Credential: &wrappers.StringValue{Value: request.Credential},
|
||||
Url: &wrappers.StringValue{Value: request.Url},
|
||||
@@ -229,25 +213,20 @@ func ValidateRepo(request *types.ValidateRepoRequest) (*types.ValidateRepoRespon
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &types.ValidateRepoResponse{
|
||||
return &ValidateRepoResponse{
|
||||
ErrorCode: int64(resp.ErrorCode),
|
||||
Ok: resp.Ok.Value,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func DoRepoAction(repoId string, request *types.RepoActionRequest) error {
|
||||
op, err := cs.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *repoOperator) DoRepoAction(repoId string, request *RepoActionRequest) error {
|
||||
var err error
|
||||
switch request.Action {
|
||||
case "index":
|
||||
case ActionIndex:
|
||||
indexRepoRequest := &pb.IndexRepoRequest{
|
||||
RepoId: &wrappers.StringValue{Value: repoId},
|
||||
}
|
||||
_, err := op.RepoIndexer().IndexRepo(openpitrix.SystemContext(), indexRepoRequest)
|
||||
_, err := c.opClient.IndexRepo(openpitrix.SystemContext(), indexRepoRequest)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
@@ -262,13 +241,7 @@ func DoRepoAction(repoId string, request *types.RepoActionRequest) error {
|
||||
}
|
||||
}
|
||||
|
||||
func ListRepoEvents(repoId string, conditions *params.Conditions, limit, offset int) (*models.PageableResponse, error) {
|
||||
op, err := cs.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (c *repoOperator) ListRepoEvents(repoId string, conditions *params.Conditions, limit, offset int) (*models.PageableResponse, error) {
|
||||
describeRepoEventsRequest := &pb.DescribeRepoEventsRequest{
|
||||
RepoId: []string{repoId},
|
||||
}
|
||||
@@ -281,7 +254,7 @@ func ListRepoEvents(repoId string, conditions *params.Conditions, limit, offset
|
||||
describeRepoEventsRequest.Limit = uint32(limit)
|
||||
describeRepoEventsRequest.Offset = uint32(offset)
|
||||
|
||||
resp, err := op.RepoIndexer().DescribeRepoEvents(openpitrix.SystemContext(), describeRepoEventsRequest)
|
||||
resp, err := c.opClient.DescribeRepoEvents(openpitrix.SystemContext(), describeRepoEventsRequest)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
@@ -291,7 +264,7 @@ func ListRepoEvents(repoId string, conditions *params.Conditions, limit, offset
|
||||
items := make([]interface{}, 0)
|
||||
|
||||
for _, item := range resp.RepoEventSet {
|
||||
items = append(items, utils.ConvertRepoEvent(item))
|
||||
items = append(items, convertRepoEvent(item))
|
||||
}
|
||||
|
||||
return &models.PageableResponse{Items: items, TotalCount: int(resp.TotalCount)}, nil
|
||||
@@ -1,4 +1,4 @@
|
||||
package types
|
||||
package openpitrix
|
||||
|
||||
import (
|
||||
"github.com/go-openapi/strfmt"
|
||||
@@ -835,3 +835,30 @@ type ModifyClusterAttributesRequest struct {
|
||||
// cluster name
|
||||
Name *string `json:"name,omitempty"`
|
||||
}
|
||||
|
||||
const (
|
||||
CreateTime = "create_time"
|
||||
StatusTime = "status_time"
|
||||
RuntimeId = "runtime_id"
|
||||
VersionId = "version_id"
|
||||
RepoId = "repo_id"
|
||||
CategoryId = "category_id"
|
||||
Status = "status"
|
||||
Type = "type"
|
||||
Visibility = "visibility"
|
||||
AppId = "app_id"
|
||||
Keyword = "keyword"
|
||||
ISV = "isv"
|
||||
WorkspaceLabel = "workspace"
|
||||
BuiltinRepoId = "repo-helm"
|
||||
StatusActive = "active"
|
||||
StatusSuspended = "suspended"
|
||||
ActionRecover = "recover"
|
||||
ActionSuspend = "suspend"
|
||||
ActionCancel = "cancel"
|
||||
ActionPass = "pass"
|
||||
ActionReject = "reject"
|
||||
ActionSubmit = "submit"
|
||||
ActionRelease = "release"
|
||||
ActionIndex = "index"
|
||||
)
|
||||
@@ -16,29 +16,28 @@
|
||||
* /
|
||||
*/
|
||||
|
||||
package utils
|
||||
package openpitrix
|
||||
|
||||
import (
|
||||
"github.com/go-openapi/strfmt"
|
||||
"kubesphere.io/kubesphere/pkg/models/openpitrix/type"
|
||||
"openpitrix.io/openpitrix/pkg/pb"
|
||||
"time"
|
||||
)
|
||||
|
||||
func ConvertApp(in *pb.App) *types.App {
|
||||
func convertApp(in *pb.App) *App {
|
||||
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
categorySet := make(types.AppCategorySet, 0)
|
||||
categorySet := make(AppCategorySet, 0)
|
||||
|
||||
for _, item := range in.CategorySet {
|
||||
category := ConvertResourceCategory(item)
|
||||
category := convertResourceCategory(item)
|
||||
categorySet = append(categorySet, category)
|
||||
}
|
||||
|
||||
out := types.App{
|
||||
out := App{
|
||||
CategorySet: categorySet,
|
||||
}
|
||||
|
||||
@@ -93,7 +92,7 @@ func ConvertApp(in *pb.App) *types.App {
|
||||
out.Keywords = in.Keywords.Value
|
||||
}
|
||||
if in.LatestAppVersion != nil {
|
||||
out.LatestAppVersion = ConvertAppVersion(in.LatestAppVersion)
|
||||
out.LatestAppVersion = convertAppVersion(in.LatestAppVersion)
|
||||
}
|
||||
if in.Name != nil {
|
||||
out.Name = in.Name.Value
|
||||
@@ -131,11 +130,11 @@ func ConvertApp(in *pb.App) *types.App {
|
||||
return &out
|
||||
}
|
||||
|
||||
func ConvertAppVersion(in *pb.AppVersion) *types.AppVersion {
|
||||
func convertAppVersion(in *pb.AppVersion) *AppVersion {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := types.AppVersion{}
|
||||
out := AppVersion{}
|
||||
if in.AppId != nil {
|
||||
out.AppId = in.AppId.Value
|
||||
}
|
||||
@@ -210,11 +209,11 @@ func ConvertAppVersion(in *pb.AppVersion) *types.AppVersion {
|
||||
|
||||
}
|
||||
|
||||
func ConvertResourceCategory(in *pb.ResourceCategory) *types.ResourceCategory {
|
||||
func convertResourceCategory(in *pb.ResourceCategory) *ResourceCategory {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := types.ResourceCategory{}
|
||||
out := ResourceCategory{}
|
||||
|
||||
if in.CategoryId != nil {
|
||||
out.CategoryId = in.CategoryId.Value
|
||||
@@ -240,11 +239,11 @@ func ConvertResourceCategory(in *pb.ResourceCategory) *types.ResourceCategory {
|
||||
return &out
|
||||
}
|
||||
|
||||
func ConvertCategory(in *pb.Category) *types.Category {
|
||||
func convertCategory(in *pb.Category) *Category {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := types.Category{}
|
||||
out := Category{}
|
||||
|
||||
if in.CategoryId != nil {
|
||||
out.CategoryID = in.CategoryId.Value
|
||||
@@ -276,11 +275,11 @@ func ConvertCategory(in *pb.Category) *types.Category {
|
||||
return &out
|
||||
}
|
||||
|
||||
func ConvertAttachment(in *pb.Attachment) *types.Attachment {
|
||||
func convertAttachment(in *pb.Attachment) *Attachment {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := types.Attachment{}
|
||||
out := Attachment{}
|
||||
|
||||
out.AttachmentID = in.AttachmentId
|
||||
|
||||
@@ -298,11 +297,11 @@ func ConvertAttachment(in *pb.Attachment) *types.Attachment {
|
||||
return &out
|
||||
}
|
||||
|
||||
func ConvertRepo(in *pb.Repo) *types.Repo {
|
||||
func convertRepo(in *pb.Repo) *Repo {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := types.Repo{}
|
||||
out := Repo{}
|
||||
|
||||
if in.RepoId != nil {
|
||||
out.RepoId = in.RepoId.Value
|
||||
@@ -317,10 +316,10 @@ func ConvertRepo(in *pb.Repo) *types.Repo {
|
||||
out.Credential = in.Credential.Value
|
||||
}
|
||||
|
||||
categorySet := make(types.RepoCategorySet, 0)
|
||||
categorySet := make(RepoCategorySet, 0)
|
||||
|
||||
for _, item := range in.CategorySet {
|
||||
category := ConvertResourceCategory(item)
|
||||
category := convertResourceCategory(item)
|
||||
categorySet = append(categorySet, category)
|
||||
}
|
||||
|
||||
@@ -339,10 +338,10 @@ func ConvertRepo(in *pb.Repo) *types.Repo {
|
||||
out.Description = in.Description.Value
|
||||
}
|
||||
|
||||
labelSet := make(types.RepoLabels, 0)
|
||||
labelSet := make(RepoLabels, 0)
|
||||
|
||||
for _, item := range in.Labels {
|
||||
label := ConvertRepoLabel(item)
|
||||
label := convertRepoLabel(item)
|
||||
labelSet = append(labelSet, label)
|
||||
}
|
||||
|
||||
@@ -358,10 +357,10 @@ func ConvertRepo(in *pb.Repo) *types.Repo {
|
||||
out.RepoId = in.RepoId.Value
|
||||
}
|
||||
|
||||
selectorSet := make(types.RepoSelectors, 0)
|
||||
selectorSet := make(RepoSelectors, 0)
|
||||
|
||||
for _, item := range in.Selectors {
|
||||
selector := ConvertRepoSelector(item)
|
||||
selector := convertRepoSelector(item)
|
||||
selectorSet = append(selectorSet, selector)
|
||||
}
|
||||
|
||||
@@ -385,11 +384,11 @@ func ConvertRepo(in *pb.Repo) *types.Repo {
|
||||
return &out
|
||||
}
|
||||
|
||||
func ConvertRepoLabel(in *pb.RepoLabel) *types.RepoLabel {
|
||||
func convertRepoLabel(in *pb.RepoLabel) *RepoLabel {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := types.RepoLabel{}
|
||||
out := RepoLabel{}
|
||||
if in.CreateTime != nil {
|
||||
date := strfmt.DateTime(time.Unix(in.CreateTime.Seconds, 0))
|
||||
out.CreateTime = &date
|
||||
@@ -403,11 +402,11 @@ func ConvertRepoLabel(in *pb.RepoLabel) *types.RepoLabel {
|
||||
return &out
|
||||
}
|
||||
|
||||
func ConvertRepoSelector(in *pb.RepoSelector) *types.RepoSelector {
|
||||
func convertRepoSelector(in *pb.RepoSelector) *RepoSelector {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := types.RepoSelector{}
|
||||
out := RepoSelector{}
|
||||
if in.CreateTime != nil {
|
||||
date := strfmt.DateTime(time.Unix(in.CreateTime.Seconds, 0))
|
||||
out.CreateTime = &date
|
||||
@@ -421,11 +420,11 @@ func ConvertRepoSelector(in *pb.RepoSelector) *types.RepoSelector {
|
||||
return &out
|
||||
}
|
||||
|
||||
func ConvertAppVersionAudit(in *pb.AppVersionAudit) *types.AppVersionAudit {
|
||||
func convertAppVersionAudit(in *pb.AppVersionAudit) *AppVersionAudit {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := types.AppVersionAudit{}
|
||||
out := AppVersionAudit{}
|
||||
if in.AppId != nil {
|
||||
out.AppId = in.AppId.Value
|
||||
}
|
||||
@@ -463,11 +462,11 @@ func ConvertAppVersionAudit(in *pb.AppVersionAudit) *types.AppVersionAudit {
|
||||
return &out
|
||||
}
|
||||
|
||||
func ConvertAppVersionReview(in *pb.AppVersionReview) *types.AppVersionReview {
|
||||
func convertAppVersionReview(in *pb.AppVersionReview) *AppVersionReview {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := types.AppVersionReview{}
|
||||
out := AppVersionReview{}
|
||||
if in.AppId != nil {
|
||||
out.AppId = in.AppId.Value
|
||||
}
|
||||
@@ -475,9 +474,9 @@ func ConvertAppVersionReview(in *pb.AppVersionReview) *types.AppVersionReview {
|
||||
out.AppName = in.AppName.Value
|
||||
}
|
||||
if in.Phase != nil {
|
||||
out.Phase = make(types.AppVersionReviewPhaseOAIGen)
|
||||
out.Phase = make(AppVersionReviewPhaseOAIGen)
|
||||
for k, v := range in.Phase {
|
||||
out.Phase[k] = *ConvertAppVersionReviewPhase(v)
|
||||
out.Phase[k] = *convertAppVersionReviewPhase(v)
|
||||
}
|
||||
}
|
||||
if in.ReviewId != nil {
|
||||
@@ -504,11 +503,11 @@ func ConvertAppVersionReview(in *pb.AppVersionReview) *types.AppVersionReview {
|
||||
return &out
|
||||
}
|
||||
|
||||
func ConvertAppVersionReviewPhase(in *pb.AppVersionReviewPhase) *types.AppVersionReviewPhase {
|
||||
func convertAppVersionReviewPhase(in *pb.AppVersionReviewPhase) *AppVersionReviewPhase {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := types.AppVersionReviewPhase{}
|
||||
out := AppVersionReviewPhase{}
|
||||
if in.Message != nil {
|
||||
out.Message = in.Message.Value
|
||||
}
|
||||
@@ -532,11 +531,11 @@ func ConvertAppVersionReviewPhase(in *pb.AppVersionReviewPhase) *types.AppVersio
|
||||
return &out
|
||||
}
|
||||
|
||||
func ConvertRepoEvent(in *pb.RepoEvent) *types.RepoEvent {
|
||||
func convertRepoEvent(in *pb.RepoEvent) *RepoEvent {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := types.RepoEvent{}
|
||||
out := RepoEvent{}
|
||||
if in.CreateTime != nil {
|
||||
date := strfmt.DateTime(time.Unix(in.CreateTime.Seconds, 0))
|
||||
out.CreateTime = &date
|
||||
@@ -564,11 +563,11 @@ func ConvertRepoEvent(in *pb.RepoEvent) *types.RepoEvent {
|
||||
return &out
|
||||
}
|
||||
|
||||
func ConvertCluster(in *pb.Cluster) *types.Cluster {
|
||||
func convertCluster(in *pb.Cluster) *Cluster {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := types.Cluster{}
|
||||
out := Cluster{}
|
||||
if in.AdditionalInfo != nil {
|
||||
out.AdditionalInfo = in.AdditionalInfo.Value
|
||||
}
|
||||
@@ -52,6 +52,10 @@ type ResourceGetter struct {
|
||||
resourcesGetters map[string]v1alpha2.Interface
|
||||
}
|
||||
|
||||
func (r ResourceGetter) Add(resource string, getter v1alpha2.Interface) {
|
||||
r.resourcesGetters[resource] = getter
|
||||
}
|
||||
|
||||
func NewResourceGetter(factory informers.InformerFactory) *ResourceGetter {
|
||||
resourceGetters := make(map[string]v1alpha2.Interface)
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ import (
|
||||
"kubesphere.io/kubesphere/pkg/gojenkins/utils"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"kubesphere.io/kubesphere/pkg/models/devops"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam"
|
||||
"kubesphere.io/kubesphere/pkg/server/params"
|
||||
cs "kubesphere.io/kubesphere/pkg/simple/client"
|
||||
"net/http"
|
||||
@@ -317,7 +318,7 @@ func CreateDevopsProject(username string, workspace string, req *v1alpha2.DevOps
|
||||
return project, nil
|
||||
}
|
||||
|
||||
func GetUserDevopsSimpleRules(username, projectId string) ([]models.SimpleRule, error) {
|
||||
func GetUserDevopsSimpleRules(username, projectId string) ([]iam.SimpleRule, error) {
|
||||
role, err := devops.GetProjectUserRole(username, projectId)
|
||||
if err != nil {
|
||||
klog.Errorf("%+v", err)
|
||||
@@ -326,12 +327,12 @@ func GetUserDevopsSimpleRules(username, projectId string) ([]models.SimpleRule,
|
||||
return GetDevopsRoleSimpleRules(role), nil
|
||||
}
|
||||
|
||||
func GetDevopsRoleSimpleRules(role string) []models.SimpleRule {
|
||||
var rules []models.SimpleRule
|
||||
func GetDevopsRoleSimpleRules(role string) []iam.SimpleRule {
|
||||
var rules []iam.SimpleRule
|
||||
|
||||
switch role {
|
||||
case "developer":
|
||||
rules = []models.SimpleRule{
|
||||
rules = []iam.SimpleRule{
|
||||
{Name: "pipelines", Actions: []string{"view", "trigger"}},
|
||||
{Name: "roles", Actions: []string{"view"}},
|
||||
{Name: "members", Actions: []string{"view"}},
|
||||
@@ -339,7 +340,7 @@ func GetDevopsRoleSimpleRules(role string) []models.SimpleRule {
|
||||
}
|
||||
break
|
||||
case "owner":
|
||||
rules = []models.SimpleRule{
|
||||
rules = []iam.SimpleRule{
|
||||
{Name: "pipelines", Actions: []string{"create", "edit", "view", "delete", "trigger"}},
|
||||
{Name: "roles", Actions: []string{"view"}},
|
||||
{Name: "members", Actions: []string{"create", "edit", "view", "delete"}},
|
||||
@@ -348,7 +349,7 @@ func GetDevopsRoleSimpleRules(role string) []models.SimpleRule {
|
||||
}
|
||||
break
|
||||
case "maintainer":
|
||||
rules = []models.SimpleRule{
|
||||
rules = []iam.SimpleRule{
|
||||
{Name: "pipelines", Actions: []string{"create", "edit", "view", "delete", "trigger"}},
|
||||
{Name: "roles", Actions: []string{"view"}},
|
||||
{Name: "members", Actions: []string{"view"}},
|
||||
@@ -359,7 +360,7 @@ func GetDevopsRoleSimpleRules(role string) []models.SimpleRule {
|
||||
case "reporter":
|
||||
fallthrough
|
||||
default:
|
||||
rules = []models.SimpleRule{
|
||||
rules = []iam.SimpleRule{
|
||||
{Name: "pipelines", Actions: []string{"view"}},
|
||||
{Name: "roles", Actions: []string{"view"}},
|
||||
{Name: "members", Actions: []string{"view"}},
|
||||
|
||||
@@ -21,9 +21,10 @@ import (
|
||||
"k8s.io/api/core/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
k8sinformers "k8s.io/client-go/informers"
|
||||
kubernetes "k8s.io/client-go/kubernetes"
|
||||
"k8s.io/klog"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam"
|
||||
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
|
||||
"kubesphere.io/kubesphere/pkg/server/params"
|
||||
@@ -32,11 +33,34 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
type namespaceSearcher struct {
|
||||
type NamespaceInterface interface {
|
||||
Search(username string, conditions *params.Conditions, orderBy string, reverse bool) ([]*v1.Namespace, error)
|
||||
CreateNamespace(workspace string, namespace *v1.Namespace, username string) (*v1.Namespace, error)
|
||||
}
|
||||
|
||||
// Exactly Match
|
||||
func (*namespaceSearcher) match(match map[string]string, item *v1.Namespace) bool {
|
||||
type namespaceSearcher struct {
|
||||
k8s kubernetes.Interface
|
||||
informers k8sinformers.SharedInformerFactory
|
||||
}
|
||||
|
||||
func (s *namespaceSearcher) CreateNamespace(workspace string, namespace *v1.Namespace, username string) (*v1.Namespace, error) {
|
||||
if namespace.Labels == nil {
|
||||
namespace.Labels = make(map[string]string, 0)
|
||||
}
|
||||
if username != "" {
|
||||
namespace.Annotations[constants.CreatorAnnotationKey] = username
|
||||
}
|
||||
|
||||
namespace.Labels[constants.WorkspaceLabelKey] = workspace
|
||||
|
||||
return s.k8s.CoreV1().Namespaces().Create(namespace)
|
||||
}
|
||||
|
||||
func newNamespaceOperator(k8s kubernetes.Interface, informers k8sinformers.SharedInformerFactory) NamespaceInterface {
|
||||
return &namespaceSearcher{k8s: k8s, informers: informers}
|
||||
}
|
||||
|
||||
func (s *namespaceSearcher) match(match map[string]string, item *v1.Namespace) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
case v1alpha2.Name:
|
||||
@@ -58,7 +82,7 @@ func (*namespaceSearcher) match(match map[string]string, item *v1.Namespace) boo
|
||||
return true
|
||||
}
|
||||
|
||||
func (*namespaceSearcher) fuzzy(fuzzy map[string]string, item *v1.Namespace) bool {
|
||||
func (s *namespaceSearcher) fuzzy(fuzzy map[string]string, item *v1.Namespace) bool {
|
||||
|
||||
for k, v := range fuzzy {
|
||||
switch k {
|
||||
@@ -74,7 +98,7 @@ func (*namespaceSearcher) fuzzy(fuzzy map[string]string, item *v1.Namespace) boo
|
||||
return true
|
||||
}
|
||||
|
||||
func (*namespaceSearcher) compare(a, b *v1.Namespace, orderBy string) bool {
|
||||
func (s *namespaceSearcher) compare(a, b *v1.Namespace, orderBy string) bool {
|
||||
switch orderBy {
|
||||
case "createTime":
|
||||
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
|
||||
@@ -85,7 +109,7 @@ func (*namespaceSearcher) compare(a, b *v1.Namespace, orderBy string) bool {
|
||||
}
|
||||
}
|
||||
|
||||
func (*namespaceSearcher) GetNamespaces(username string) ([]*v1.Namespace, error) {
|
||||
func (s *namespaceSearcher) GetNamespaces(username string) ([]*v1.Namespace, error) {
|
||||
|
||||
roles, err := iam.GetUserRoles("", username)
|
||||
|
||||
@@ -93,7 +117,7 @@ func (*namespaceSearcher) GetNamespaces(username string) ([]*v1.Namespace, error
|
||||
return nil, err
|
||||
}
|
||||
namespaces := make([]*v1.Namespace, 0)
|
||||
namespaceLister := informers.SharedInformerFactory().Core().V1().Namespaces().Lister()
|
||||
namespaceLister := s.informers.Core().V1().Namespaces().Lister()
|
||||
for _, role := range roles {
|
||||
namespace, err := namespaceLister.Get(role.Namespace)
|
||||
if err != nil {
|
||||
@@ -117,7 +141,7 @@ func containsNamespace(namespaces []*v1.Namespace, namespace *v1.Namespace) bool
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *namespaceSearcher) search(username string, conditions *params.Conditions, orderBy string, reverse bool) ([]*v1.Namespace, error) {
|
||||
func (s *namespaceSearcher) Search(username string, conditions *params.Conditions, orderBy string, reverse bool) ([]*v1.Namespace, error) {
|
||||
|
||||
rules, err := iam.GetUserClusterRules(username)
|
||||
|
||||
@@ -128,7 +152,7 @@ func (s *namespaceSearcher) search(username string, conditions *params.Condition
|
||||
namespaces := make([]*v1.Namespace, 0)
|
||||
|
||||
if iam.RulesMatchesRequired(rules, rbacv1.PolicyRule{Verbs: []string{"list"}, APIGroups: []string{"tenant.kubesphere.io"}, Resources: []string{"namespaces"}}) {
|
||||
namespaces, err = informers.SharedInformerFactory().Core().V1().Namespaces().Lister().List(labels.Everything())
|
||||
namespaces, err = s.informers.Core().V1().Namespaces().Lister().List(labels.Everything())
|
||||
} else {
|
||||
namespaces, err = s.GetNamespaces(username)
|
||||
}
|
||||
@@ -148,12 +172,14 @@ func (s *namespaceSearcher) search(username string, conditions *params.Condition
|
||||
// order & reverse
|
||||
sort.Slice(result, func(i, j int) bool {
|
||||
if reverse {
|
||||
tmp := i
|
||||
i = j
|
||||
j = tmp
|
||||
i, j = j, i
|
||||
}
|
||||
return s.compare(result[i], result[j], orderBy)
|
||||
})
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func CreateNamespace() {
|
||||
|
||||
}
|
||||
|
||||
@@ -19,49 +19,62 @@ package tenant
|
||||
|
||||
import (
|
||||
"k8s.io/api/core/v1"
|
||||
k8sinformers "k8s.io/client-go/informers"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha1"
|
||||
ksinformers "kubesphere.io/kubesphere/pkg/client/informers/externalversions"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
ws "kubesphere.io/kubesphere/pkg/models/workspaces"
|
||||
"kubesphere.io/kubesphere/pkg/server/params"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/mysql"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
var (
|
||||
workspaces = workspaceSearcher{}
|
||||
namespaces = namespaceSearcher{}
|
||||
)
|
||||
|
||||
func CreateNamespace(workspaceName string, namespace *v1.Namespace, username string) (*v1.Namespace, error) {
|
||||
if namespace.Labels == nil {
|
||||
namespace.Labels = make(map[string]string, 0)
|
||||
}
|
||||
if username != "" {
|
||||
namespace.Annotations[constants.CreatorAnnotationKey] = username
|
||||
}
|
||||
|
||||
namespace.Labels[constants.WorkspaceLabelKey] = workspaceName
|
||||
|
||||
return client.ClientSets().K8s().Kubernetes().CoreV1().Namespaces().Create(namespace)
|
||||
type Interface interface {
|
||||
CreateNamespace(workspace string, namespace *v1.Namespace, username string) (*v1.Namespace, error)
|
||||
DeleteNamespace(workspace, namespace string) error
|
||||
DescribeWorkspace(username, workspace string) (*v1alpha1.Workspace, error)
|
||||
ListWorkspaces(username string, conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error)
|
||||
ListNamespaces(username string, conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error)
|
||||
}
|
||||
|
||||
func DescribeWorkspace(username, workspaceName string) (*v1alpha1.Workspace, error) {
|
||||
workspace, err := informers.KsSharedInformerFactory().Tenant().V1alpha1().Workspaces().Lister().Get(workspaceName)
|
||||
type tenantOperator struct {
|
||||
workspaces WorkspaceInterface
|
||||
namespaces NamespaceInterface
|
||||
}
|
||||
|
||||
func (t *tenantOperator) DeleteNamespace(workspace, namespace string) error {
|
||||
return t.workspaces.DeleteNamespace(workspace, namespace)
|
||||
}
|
||||
|
||||
func New(client kubernetes.Interface, informers k8sinformers.SharedInformerFactory, ksinformers ksinformers.SharedInformerFactory, db *mysql.Database) Interface {
|
||||
return &tenantOperator{
|
||||
workspaces: newWorkspaceOperator(client, informers, ksinformers, db),
|
||||
namespaces: newNamespaceOperator(client, informers),
|
||||
}
|
||||
}
|
||||
|
||||
func (t *tenantOperator) CreateNamespace(workspaceName string, namespace *v1.Namespace, username string) (*v1.Namespace, error) {
|
||||
return t.namespaces.CreateNamespace(workspaceName, namespace, username)
|
||||
}
|
||||
|
||||
func (t *tenantOperator) DescribeWorkspace(username, workspaceName string) (*v1alpha1.Workspace, error) {
|
||||
workspace, err := t.workspaces.GetWorkspace(workspaceName)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
workspace = appendAnnotations(username, workspace)
|
||||
if username != "" {
|
||||
workspace = t.appendAnnotations(username, workspace)
|
||||
}
|
||||
|
||||
return workspace, nil
|
||||
}
|
||||
|
||||
func ListWorkspaces(username string, conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
|
||||
func (t *tenantOperator) ListWorkspaces(username string, conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
|
||||
|
||||
workspaces, err := workspaces.search(username, conditions, orderBy, reverse)
|
||||
workspaces, err := t.workspaces.SearchWorkspace(username, conditions, orderBy, reverse)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -71,7 +84,7 @@ func ListWorkspaces(username string, conditions *params.Conditions, orderBy stri
|
||||
result := make([]interface{}, 0)
|
||||
for i, workspace := range workspaces {
|
||||
if len(result) < limit && i >= offset {
|
||||
workspace := appendAnnotations(username, workspace)
|
||||
workspace := t.appendAnnotations(username, workspace)
|
||||
result = append(result, workspace)
|
||||
}
|
||||
}
|
||||
@@ -79,12 +92,12 @@ func ListWorkspaces(username string, conditions *params.Conditions, orderBy stri
|
||||
return &models.PageableResponse{Items: result, TotalCount: len(workspaces)}, nil
|
||||
}
|
||||
|
||||
func appendAnnotations(username string, workspace *v1alpha1.Workspace) *v1alpha1.Workspace {
|
||||
func (t *tenantOperator) appendAnnotations(username string, workspace *v1alpha1.Workspace) *v1alpha1.Workspace {
|
||||
workspace = workspace.DeepCopy()
|
||||
if workspace.Annotations == nil {
|
||||
workspace.Annotations = make(map[string]string)
|
||||
}
|
||||
ns, err := ListNamespaces(username, ¶ms.Conditions{Match: map[string]string{constants.WorkspaceLabelKey: workspace.Name}}, "", false, 1, 0)
|
||||
ns, err := t.ListNamespaces(username, ¶ms.Conditions{Match: map[string]string{constants.WorkspaceLabelKey: workspace.Name}}, "", false, 1, 0)
|
||||
if err == nil {
|
||||
workspace.Annotations["kubesphere.io/namespace-count"] = strconv.Itoa(ns.TotalCount)
|
||||
}
|
||||
@@ -92,16 +105,18 @@ func appendAnnotations(username string, workspace *v1alpha1.Workspace) *v1alpha1
|
||||
if err == nil {
|
||||
workspace.Annotations["kubesphere.io/devops-count"] = strconv.Itoa(devops.TotalCount)
|
||||
}
|
||||
userCount, err := ws.WorkspaceUserCount(workspace.Name)
|
||||
|
||||
userCount, err := t.workspaces.CountUsersInWorkspace(workspace.Name)
|
||||
|
||||
if err == nil {
|
||||
workspace.Annotations["kubesphere.io/member-count"] = strconv.Itoa(userCount)
|
||||
}
|
||||
return workspace
|
||||
}
|
||||
|
||||
func ListNamespaces(username string, conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
|
||||
func (t *tenantOperator) ListNamespaces(username string, conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
|
||||
|
||||
namespaces, err := namespaces.search(username, conditions, orderBy, reverse)
|
||||
namespaces, err := t.namespaces.Search(username, conditions, orderBy, reverse)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -1,41 +1,241 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 The KubeSphere 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.
|
||||
|
||||
*/
|
||||
*
|
||||
* Copyright 2020 The KubeSphere 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 tenant
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
core "k8s.io/api/core/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/client-go/informers"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/klog"
|
||||
"kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha1"
|
||||
"kubesphere.io/kubesphere/pkg/client/informers/externalversions"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/db"
|
||||
"kubesphere.io/kubesphere/pkg/models/devops"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam"
|
||||
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
|
||||
"kubesphere.io/kubesphere/pkg/server/params"
|
||||
clientset "kubesphere.io/kubesphere/pkg/simple/client"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/mysql"
|
||||
"kubesphere.io/kubesphere/pkg/utils/k8sutil"
|
||||
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"k8s.io/api/rbac/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
type workspaceSearcher struct {
|
||||
type WorkspaceInterface interface {
|
||||
GetWorkspace(workspace string) (*v1alpha1.Workspace, error)
|
||||
SearchWorkspace(username string, conditions *params.Conditions, orderBy string, reverse bool) ([]*v1alpha1.Workspace, error)
|
||||
ListNamespaces(workspace string) ([]*core.Namespace, error)
|
||||
DeleteNamespace(workspace, namespace string) error
|
||||
RemoveUser(user, workspace string) error
|
||||
AddUser(workspace string, user *iam.User) error
|
||||
CountDevopsProjectsInWorkspace(workspace string) (int, error)
|
||||
CountUsersInWorkspace(workspace string) (int, error)
|
||||
CountOrgRoles() (int, error)
|
||||
CountWorkspaces() (int, error)
|
||||
CountNamespacesInWorkspace(workspace string) (int, error)
|
||||
}
|
||||
|
||||
// Exactly Match
|
||||
func (*workspaceSearcher) match(match map[string]string, item *v1alpha1.Workspace) bool {
|
||||
type workspaceOperator struct {
|
||||
client kubernetes.Interface
|
||||
informers informers.SharedInformerFactory
|
||||
ksInformers externalversions.SharedInformerFactory
|
||||
|
||||
// TODO: use db interface instead of mysql client
|
||||
// we can refactor this after rewrite devops using crd
|
||||
db *mysql.Database
|
||||
}
|
||||
|
||||
func newWorkspaceOperator(client kubernetes.Interface, informers informers.SharedInformerFactory, ksinformers externalversions.SharedInformerFactory, db *mysql.Database) WorkspaceInterface {
|
||||
return &workspaceOperator{
|
||||
client: client,
|
||||
informers: informers,
|
||||
ksInformers: ksinformers,
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
func (w *workspaceOperator) ListNamespaces(workspace string) ([]*core.Namespace, error) {
|
||||
namespaces, err := w.informers.Core().V1().Namespaces().Lister().List(labels.SelectorFromSet(labels.Set{constants.WorkspaceLabelKey: workspace}))
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return namespaces, nil
|
||||
}
|
||||
|
||||
func (w *workspaceOperator) DeleteNamespace(workspace string, namespace string) error {
|
||||
ns, err := w.informers.Core().V1().Namespaces().Lister().Get(namespace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ns.Labels[constants.WorkspaceLabelKey] == workspace {
|
||||
deletePolicy := metav1.DeletePropagationBackground
|
||||
return w.client.CoreV1().Namespaces().Delete(namespace, &metav1.DeleteOptions{PropagationPolicy: &deletePolicy})
|
||||
} else {
|
||||
return apierrors.NewNotFound(schema.GroupResource{Group: "", Resource: "workspace"}, workspace)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *workspaceOperator) RemoveUser(workspace string, username string) error {
|
||||
workspaceRole, err := iam.GetUserWorkspaceRole(workspace, username)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = w.deleteWorkspaceRoleBinding(workspace, username, workspaceRole.Annotations[constants.DisplayNameAnnotationKey])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *workspaceOperator) AddUser(workspaceName string, user *iam.User) error {
|
||||
|
||||
workspaceRole, err := iam.GetUserWorkspaceRole(workspaceName, user.Username)
|
||||
|
||||
if err != nil && !apierrors.IsNotFound(err) {
|
||||
klog.Errorf("get workspace role failed: %+v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
workspaceRoleName := fmt.Sprintf("workspace:%s:%s", workspaceName, strings.TrimPrefix(user.WorkspaceRole, "workspace-"))
|
||||
var currentWorkspaceRoleName string
|
||||
if workspaceRole != nil {
|
||||
currentWorkspaceRoleName = workspaceRole.Name
|
||||
}
|
||||
|
||||
if currentWorkspaceRoleName != workspaceRoleName && currentWorkspaceRoleName != "" {
|
||||
err := w.deleteWorkspaceRoleBinding(workspaceName, user.Username, workspaceRole.Annotations[constants.DisplayNameAnnotationKey])
|
||||
if err != nil {
|
||||
klog.Errorf("delete workspace role binding failed: %+v", err)
|
||||
return err
|
||||
}
|
||||
} else if currentWorkspaceRoleName != "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
return w.createWorkspaceRoleBinding(workspaceName, user.Username, user.WorkspaceRole)
|
||||
}
|
||||
|
||||
func (w *workspaceOperator) createWorkspaceRoleBinding(workspace, username string, role string) error {
|
||||
|
||||
if !sliceutil.HasString(constants.WorkSpaceRoles, role) {
|
||||
return apierrors.NewNotFound(schema.GroupResource{Resource: "workspace role"}, role)
|
||||
}
|
||||
|
||||
roleBindingName := fmt.Sprintf("workspace:%s:%s", workspace, strings.TrimPrefix(role, "workspace-"))
|
||||
workspaceRoleBinding, err := w.informers.Rbac().V1().ClusterRoleBindings().Lister().Get(roleBindingName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !k8sutil.ContainsUser(workspaceRoleBinding.Subjects, username) {
|
||||
workspaceRoleBinding = workspaceRoleBinding.DeepCopy()
|
||||
workspaceRoleBinding.Subjects = append(workspaceRoleBinding.Subjects, v1.Subject{APIGroup: "rbac.authorization.k8s.io", Kind: "User", Name: username})
|
||||
_, err = w.client.RbacV1().ClusterRoleBindings().Update(workspaceRoleBinding)
|
||||
if err != nil {
|
||||
klog.Errorf("update workspace role binding failed: %+v", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *workspaceOperator) deleteWorkspaceRoleBinding(workspace, username string, role string) error {
|
||||
|
||||
if !sliceutil.HasString(constants.WorkSpaceRoles, role) {
|
||||
return apierrors.NewNotFound(schema.GroupResource{Resource: "workspace role"}, role)
|
||||
}
|
||||
|
||||
roleBindingName := fmt.Sprintf("workspace:%s:%s", workspace, strings.TrimPrefix(role, "workspace-"))
|
||||
|
||||
workspaceRoleBinding, err := w.informers.Rbac().V1().ClusterRoleBindings().Lister().Get(roleBindingName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
workspaceRoleBinding = workspaceRoleBinding.DeepCopy()
|
||||
|
||||
for i, v := range workspaceRoleBinding.Subjects {
|
||||
if v.Kind == v1.UserKind && v.Name == username {
|
||||
workspaceRoleBinding.Subjects = append(workspaceRoleBinding.Subjects[:i], workspaceRoleBinding.Subjects[i+1:]...)
|
||||
i--
|
||||
}
|
||||
}
|
||||
|
||||
workspaceRoleBinding, err = w.client.RbacV1().ClusterRoleBindings().Update(workspaceRoleBinding)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (w *workspaceOperator) CountDevopsProjectsInWorkspace(workspaceName string) (int, error) {
|
||||
if w.db == nil {
|
||||
return 0, clientset.ErrClientSetNotEnabled
|
||||
}
|
||||
|
||||
query := w.db.Select(devops.DevOpsProjectIdColumn).
|
||||
From(devops.DevOpsProjectTableName).
|
||||
Where(db.And(db.Eq(devops.DevOpsProjectWorkSpaceColumn, workspaceName),
|
||||
db.Eq(devops.StatusColumn, devops.StatusActive)))
|
||||
|
||||
devOpsProjects := make([]string, 0)
|
||||
|
||||
if _, err := query.Load(&devOpsProjects); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return len(devOpsProjects), nil
|
||||
}
|
||||
|
||||
func (w *workspaceOperator) CountUsersInWorkspace(workspace string) (int, error) {
|
||||
count, err := iam.WorkspaceUsersTotalCount(workspace)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
func (w *workspaceOperator) CountOrgRoles() (int, error) {
|
||||
return len(constants.WorkSpaceRoles), nil
|
||||
}
|
||||
|
||||
func (w *workspaceOperator) CountNamespacesInWorkspace(workspace string) (int, error) {
|
||||
ns, err := w.ListNamespaces(workspace)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return len(ns), nil
|
||||
}
|
||||
|
||||
func (*workspaceOperator) match(match map[string]string, item *v1alpha1.Workspace) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
case v1alpha2.Name:
|
||||
@@ -57,7 +257,7 @@ func (*workspaceSearcher) match(match map[string]string, item *v1alpha1.Workspac
|
||||
return true
|
||||
}
|
||||
|
||||
func (*workspaceSearcher) fuzzy(fuzzy map[string]string, item *v1alpha1.Workspace) bool {
|
||||
func (*workspaceOperator) fuzzy(fuzzy map[string]string, item *v1alpha1.Workspace) bool {
|
||||
|
||||
for k, v := range fuzzy {
|
||||
switch k {
|
||||
@@ -73,7 +273,7 @@ func (*workspaceSearcher) fuzzy(fuzzy map[string]string, item *v1alpha1.Workspac
|
||||
return true
|
||||
}
|
||||
|
||||
func (*workspaceSearcher) compare(a, b *v1alpha1.Workspace, orderBy string) bool {
|
||||
func (*workspaceOperator) compare(a, b *v1alpha1.Workspace, orderBy string) bool {
|
||||
switch orderBy {
|
||||
case v1alpha2.CreateTime:
|
||||
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
|
||||
@@ -84,7 +284,7 @@ func (*workspaceSearcher) compare(a, b *v1alpha1.Workspace, orderBy string) bool
|
||||
}
|
||||
}
|
||||
|
||||
func (s *workspaceSearcher) search(username string, conditions *params.Conditions, orderBy string, reverse bool) ([]*v1alpha1.Workspace, error) {
|
||||
func (w *workspaceOperator) SearchWorkspace(username string, conditions *params.Conditions, orderBy string, reverse bool) ([]*v1alpha1.Workspace, error) {
|
||||
rules, err := iam.GetUserClusterRules(username)
|
||||
|
||||
if err != nil {
|
||||
@@ -94,7 +294,7 @@ func (s *workspaceSearcher) search(username string, conditions *params.Condition
|
||||
workspaces := make([]*v1alpha1.Workspace, 0)
|
||||
|
||||
if iam.RulesMatchesRequired(rules, rbacv1.PolicyRule{Verbs: []string{"list"}, APIGroups: []string{"tenant.kubesphere.io"}, Resources: []string{"workspaces"}}) {
|
||||
workspaces, err = informers.KsSharedInformerFactory().Tenant().V1alpha1().Workspaces().Lister().List(labels.Everything())
|
||||
workspaces, err = w.ksInformers.Tenant().V1alpha1().Workspaces().Lister().List(labels.Everything())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -104,7 +304,7 @@ func (s *workspaceSearcher) search(username string, conditions *params.Condition
|
||||
return nil, err
|
||||
}
|
||||
for k := range workspaceRoles {
|
||||
workspace, err := informers.KsSharedInformerFactory().Tenant().V1alpha1().Workspaces().Lister().Get(k)
|
||||
workspace, err := w.ksInformers.Tenant().V1alpha1().Workspaces().Lister().Get(k)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -115,7 +315,7 @@ func (s *workspaceSearcher) search(username string, conditions *params.Condition
|
||||
result := make([]*v1alpha1.Workspace, 0)
|
||||
|
||||
for _, workspace := range workspaces {
|
||||
if s.match(conditions.Match, workspace) && s.fuzzy(conditions.Fuzzy, workspace) {
|
||||
if w.match(conditions.Match, workspace) && w.fuzzy(conditions.Fuzzy, workspace) {
|
||||
result = append(result, workspace)
|
||||
}
|
||||
}
|
||||
@@ -123,18 +323,16 @@ func (s *workspaceSearcher) search(username string, conditions *params.Condition
|
||||
// order & reverse
|
||||
sort.Slice(result, func(i, j int) bool {
|
||||
if reverse {
|
||||
tmp := i
|
||||
i = j
|
||||
j = tmp
|
||||
i, j = j, i
|
||||
}
|
||||
return s.compare(result[i], result[j], orderBy)
|
||||
return w.compare(result[i], result[j], orderBy)
|
||||
})
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func GetWorkspace(workspaceName string) (*v1alpha1.Workspace, error) {
|
||||
return informers.KsSharedInformerFactory().Tenant().V1alpha1().Workspaces().Lister().Get(workspaceName)
|
||||
func (w *workspaceOperator) GetWorkspace(workspaceName string) (*v1alpha1.Workspace, error) {
|
||||
return w.ksInformers.Tenant().V1alpha1().Workspaces().Lister().Get(workspaceName)
|
||||
}
|
||||
|
||||
func contains(m map[string]string, key, value string) bool {
|
||||
@@ -149,3 +347,47 @@ func contains(m map[string]string, key, value string) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/*
|
||||
// TODO: move to metrics package
|
||||
func GetAllProjectNums() (int, error) {
|
||||
namespaceLister := informers.SharedInformerFactory().Core().V1().Namespaces().Lister()
|
||||
list, err := namespaceLister.List(labels.Everything())
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return len(list), nil
|
||||
}
|
||||
|
||||
func GetAllDevOpsProjectsNums() (int, error) {
|
||||
_, err := clientset.ClientSets().Devops()
|
||||
if _, notEnabled := err.(clientset.ClientSetNotEnabledError); notEnabled {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
dbconn, err := clientset.ClientSets().MySQL()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
query := dbconn.Select(devops.DevOpsProjectIdColumn).
|
||||
From(devops.DevOpsProjectTableName).
|
||||
Where(db.Eq(devops.StatusColumn, devops.StatusActive))
|
||||
|
||||
devOpsProjects := make([]string, 0)
|
||||
|
||||
if _, err := query.Load(&devOpsProjects); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return len(devOpsProjects), nil
|
||||
}
|
||||
*/
|
||||
|
||||
func (w *workspaceOperator) CountWorkspaces() (int, error) {
|
||||
ws, err := w.ksInformers.Tenant().V1alpha1().Workspaces().Lister().List(labels.Everything())
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return len(ws), nil
|
||||
}
|
||||
|
||||
@@ -17,12 +17,6 @@
|
||||
*/
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"k8s.io/api/rbac/v1"
|
||||
)
|
||||
|
||||
type PageableResponse struct {
|
||||
Items []interface{} `json:"items" description:"paging data"`
|
||||
TotalCount int `json:"total_count" description:"total count"`
|
||||
@@ -35,41 +29,6 @@ type Workspace struct {
|
||||
DevopsProjects []string `json:"devops_projects"`
|
||||
}
|
||||
|
||||
type Action struct {
|
||||
Name string `json:"name"`
|
||||
Rules []v1.PolicyRule `json:"rules"`
|
||||
}
|
||||
|
||||
type Rule struct {
|
||||
Name string `json:"name"`
|
||||
Actions []Action `json:"actions"`
|
||||
}
|
||||
|
||||
type SimpleRule struct {
|
||||
Name string `json:"name" description:"rule name"`
|
||||
Actions []string `json:"actions" description:"actions"`
|
||||
}
|
||||
|
||||
type User struct {
|
||||
Username string `json:"username"`
|
||||
Email string `json:"email"`
|
||||
Lang string `json:"lang,omitempty"`
|
||||
Description string `json:"description"`
|
||||
CreateTime time.Time `json:"create_time"`
|
||||
Groups []string `json:"groups,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
CurrentPassword string `json:"current_password,omitempty"`
|
||||
AvatarUrl string `json:"avatar_url"`
|
||||
LastLoginTime string `json:"last_login_time"`
|
||||
Status int `json:"status"`
|
||||
ClusterRole string `json:"cluster_role"`
|
||||
Roles map[string]string `json:"roles,omitempty"`
|
||||
Role string `json:"role,omitempty"`
|
||||
RoleBinding string `json:"role_binding,omitempty"`
|
||||
RoleBindTime *time.Time `json:"role_bind_time,omitempty"`
|
||||
WorkspaceRole string `json:"workspace_role,omitempty"`
|
||||
}
|
||||
|
||||
type Group struct {
|
||||
Path string `json:"path"`
|
||||
Name string `json:"name"`
|
||||
|
||||
@@ -1,276 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 The KubeSphere 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 workspaces
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/client-go/informers"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/klog"
|
||||
"kubesphere.io/kubesphere/pkg/client/informers/externalversions"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/db"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"kubesphere.io/kubesphere/pkg/models/devops"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam"
|
||||
clientset "kubesphere.io/kubesphere/pkg/simple/client"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/mysql"
|
||||
"kubesphere.io/kubesphere/pkg/utils/k8sutil"
|
||||
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
|
||||
"strings"
|
||||
|
||||
core "k8s.io/api/core/v1"
|
||||
|
||||
"errors"
|
||||
"k8s.io/api/rbac/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
type Interface interface {
|
||||
ListNamespaces(workspace string) ([]*core.Namespace, error)
|
||||
DeleteNamespace(workspace, namespace string) error
|
||||
RemoveUser(user, workspace string) error
|
||||
AddUser(workspace string, user *models.User) error
|
||||
CountDevopsProjectsInWorkspace(workspace string) (int, error)
|
||||
CountUsersInWorkspace(workspace string) (int, error)
|
||||
CountOrgRoles() (int, error)
|
||||
CountWorkspaces() (int, error)
|
||||
CountNamespacesInWorkspace(workspace string) (int, error)
|
||||
}
|
||||
|
||||
type workspaceOperator struct {
|
||||
client kubernetes.Interface
|
||||
informers informers.SharedInformerFactory
|
||||
ksInformers externalversions.SharedInformerFactory
|
||||
|
||||
// TODO: use db interface instead of mysql client
|
||||
// we can refactor this after rewrite devops using crd
|
||||
db *mysql.Database
|
||||
}
|
||||
|
||||
func NewWorkspaceOperator(client kubernetes.Interface, informers informers.SharedInformerFactory, ksinformers externalversions.SharedInformerFactory, db *mysql.Database) Interface {
|
||||
return &workspaceOperator{
|
||||
client: client,
|
||||
informers: informers,
|
||||
ksInformers: ksinformers,
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *workspaceOperator) ListNamespaces(workspace string) ([]*core.Namespace, error) {
|
||||
namespaces, err := c.informers.Core().V1().Namespaces().Lister().List(labels.SelectorFromSet(labels.Set{constants.WorkspaceLabelKey: workspace}))
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return namespaces, nil
|
||||
}
|
||||
|
||||
func (c *workspaceOperator) DeleteNamespace(workspace string, namespace string) error {
|
||||
ns, err := c.informers.Core().V1().Namespaces().Lister().Get(namespace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ns.Labels[constants.WorkspaceLabelKey] == workspace {
|
||||
deletePolicy := metav1.DeletePropagationBackground
|
||||
return c.client.CoreV1().Namespaces().Delete(namespace, &metav1.DeleteOptions{PropagationPolicy: &deletePolicy})
|
||||
} else {
|
||||
return errors.New("resource not found")
|
||||
}
|
||||
}
|
||||
|
||||
func (c *workspaceOperator) RemoveUser(workspace string, username string) error {
|
||||
workspaceRole, err := iam.GetUserWorkspaceRole(workspace, username)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = c.deleteWorkspaceRoleBinding(workspace, username, workspaceRole.Annotations[constants.DisplayNameAnnotationKey])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *workspaceOperator) AddUser(workspaceName string, user *models.User) error {
|
||||
|
||||
workspaceRole, err := iam.GetUserWorkspaceRole(workspaceName, user.Username)
|
||||
|
||||
if err != nil && !apierrors.IsNotFound(err) {
|
||||
klog.Errorf("get workspace role failed: %+v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
workspaceRoleName := fmt.Sprintf("workspace:%s:%s", workspaceName, strings.TrimPrefix(user.WorkspaceRole, "workspace-"))
|
||||
var currentWorkspaceRoleName string
|
||||
if workspaceRole != nil {
|
||||
currentWorkspaceRoleName = workspaceRole.Name
|
||||
}
|
||||
|
||||
if currentWorkspaceRoleName != workspaceRoleName && currentWorkspaceRoleName != "" {
|
||||
err := c.deleteWorkspaceRoleBinding(workspaceName, user.Username, workspaceRole.Annotations[constants.DisplayNameAnnotationKey])
|
||||
if err != nil {
|
||||
klog.Errorf("delete workspace role binding failed: %+v", err)
|
||||
return err
|
||||
}
|
||||
} else if currentWorkspaceRoleName != "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
return c.createWorkspaceRoleBinding(workspaceName, user.Username, user.WorkspaceRole)
|
||||
}
|
||||
|
||||
func (c *workspaceOperator) createWorkspaceRoleBinding(workspace, username string, role string) error {
|
||||
|
||||
if !sliceutil.HasString(constants.WorkSpaceRoles, role) {
|
||||
return apierrors.NewNotFound(schema.GroupResource{Resource: "workspace role"}, role)
|
||||
}
|
||||
|
||||
roleBindingName := fmt.Sprintf("workspace:%s:%s", workspace, strings.TrimPrefix(role, "workspace-"))
|
||||
workspaceRoleBinding, err := c.informers.Rbac().V1().ClusterRoleBindings().Lister().Get(roleBindingName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !k8sutil.ContainsUser(workspaceRoleBinding.Subjects, username) {
|
||||
workspaceRoleBinding = workspaceRoleBinding.DeepCopy()
|
||||
workspaceRoleBinding.Subjects = append(workspaceRoleBinding.Subjects, v1.Subject{APIGroup: "rbac.authorization.k8s.io", Kind: "User", Name: username})
|
||||
_, err = c.client.RbacV1().ClusterRoleBindings().Update(workspaceRoleBinding)
|
||||
if err != nil {
|
||||
klog.Errorf("update workspace role binding failed: %+v", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *workspaceOperator) deleteWorkspaceRoleBinding(workspace, username string, role string) error {
|
||||
|
||||
if !sliceutil.HasString(constants.WorkSpaceRoles, role) {
|
||||
return apierrors.NewNotFound(schema.GroupResource{Resource: "workspace role"}, role)
|
||||
}
|
||||
|
||||
roleBindingName := fmt.Sprintf("workspace:%s:%s", workspace, strings.TrimPrefix(role, "workspace-"))
|
||||
|
||||
workspaceRoleBinding, err := c.informers.Rbac().V1().ClusterRoleBindings().Lister().Get(roleBindingName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
workspaceRoleBinding = workspaceRoleBinding.DeepCopy()
|
||||
|
||||
for i, v := range workspaceRoleBinding.Subjects {
|
||||
if v.Kind == v1.UserKind && v.Name == username {
|
||||
workspaceRoleBinding.Subjects = append(workspaceRoleBinding.Subjects[:i], workspaceRoleBinding.Subjects[i+1:]...)
|
||||
i--
|
||||
}
|
||||
}
|
||||
|
||||
workspaceRoleBinding, err = c.client.RbacV1().ClusterRoleBindings().Update(workspaceRoleBinding)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *workspaceOperator) CountDevopsProjectsInWorkspace(workspaceName string) (int, error) {
|
||||
if c.db == nil {
|
||||
return 0, clientset.ErrClientSetNotEnabled
|
||||
}
|
||||
|
||||
query := c.db.Select(devops.DevOpsProjectIdColumn).
|
||||
From(devops.DevOpsProjectTableName).
|
||||
Where(db.And(db.Eq(devops.DevOpsProjectWorkSpaceColumn, workspaceName),
|
||||
db.Eq(devops.StatusColumn, devops.StatusActive)))
|
||||
|
||||
devOpsProjects := make([]string, 0)
|
||||
|
||||
if _, err := query.Load(&devOpsProjects); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return len(devOpsProjects), nil
|
||||
}
|
||||
|
||||
func (c *workspaceOperator) CountUsersInWorkspace(workspace string) (int, error) {
|
||||
count, err := iam.WorkspaceUsersTotalCount(workspace)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
func (c *workspaceOperator) CountOrgRoles() (int, error) {
|
||||
return len(constants.WorkSpaceRoles), nil
|
||||
}
|
||||
|
||||
func (c *workspaceOperator) CountNamespacesInWorkspace(workspace string) (int, error) {
|
||||
ns, err := c.ListNamespaces(workspace)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return len(ns), nil
|
||||
}
|
||||
|
||||
/*
|
||||
// TODO: move to metrics package
|
||||
func GetAllProjectNums() (int, error) {
|
||||
namespaceLister := informers.SharedInformerFactory().Core().V1().Namespaces().Lister()
|
||||
list, err := namespaceLister.List(labels.Everything())
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return len(list), nil
|
||||
}
|
||||
|
||||
func GetAllDevOpsProjectsNums() (int, error) {
|
||||
_, err := clientset.ClientSets().Devops()
|
||||
if _, notEnabled := err.(clientset.ClientSetNotEnabledError); notEnabled {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
dbconn, err := clientset.ClientSets().MySQL()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
query := dbconn.Select(devops.DevOpsProjectIdColumn).
|
||||
From(devops.DevOpsProjectTableName).
|
||||
Where(db.Eq(devops.StatusColumn, devops.StatusActive))
|
||||
|
||||
devOpsProjects := make([]string, 0)
|
||||
|
||||
if _, err := query.Load(&devOpsProjects); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return len(devOpsProjects), nil
|
||||
}
|
||||
*/
|
||||
|
||||
func (c *workspaceOperator) CountWorkspaces() (int, error) {
|
||||
ws, err := c.ksInformers.Tenant().V1alpha1().Workspaces().Lister().List(labels.Everything())
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return len(ws), nil
|
||||
}
|
||||
Reference in New Issue
Block a user