[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:
2
go.mod
2
go.mod
@@ -39,6 +39,7 @@ require (
|
||||
github.com/go-sql-driver/mysql v1.4.1
|
||||
github.com/gocraft/dbr v0.0.0-20180507214907-a0fd650918f6
|
||||
github.com/golang/example v0.0.0-20170904185048-46695d81d1fa
|
||||
github.com/golang/mock v1.2.0
|
||||
github.com/golang/protobuf v1.3.2
|
||||
github.com/google/go-cmp v0.3.0
|
||||
github.com/google/go-querystring v1.0.0 // indirect
|
||||
@@ -79,6 +80,7 @@ require (
|
||||
github.com/stretchr/testify v1.4.0
|
||||
github.com/xanzy/ssh-agent v0.2.1 // indirect
|
||||
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
|
||||
google.golang.org/grpc v1.23.1
|
||||
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d // indirect
|
||||
gopkg.in/go-playground/validator.v9 v9.29.1 // indirect
|
||||
|
||||
70
pkg/api/iam/v1alpha2/types.go
Normal file
70
pkg/api/iam/v1alpha2/types.go
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
*
|
||||
* 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 v1alpha2
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam"
|
||||
"net/mail"
|
||||
)
|
||||
|
||||
const minPasswordLength = 6
|
||||
|
||||
type Spec struct {
|
||||
Token string `json:"token" description:"access token"`
|
||||
}
|
||||
|
||||
type Status struct {
|
||||
Authenticated bool `json:"authenticated" description:"is authenticated"`
|
||||
User map[string]interface{} `json:"user,omitempty" description:"user info"`
|
||||
}
|
||||
|
||||
type TokenReview struct {
|
||||
APIVersion string `json:"apiVersion" description:"Kubernetes API version"`
|
||||
Kind string `json:"kind" description:"kind of the API object"`
|
||||
Spec *Spec `json:"spec,omitempty"`
|
||||
Status *Status `json:"status,omitempty" description:"token review status"`
|
||||
}
|
||||
|
||||
type LoginRequest struct {
|
||||
Username string `json:"username" description:"username"`
|
||||
Password string `json:"password" description:"password"`
|
||||
}
|
||||
|
||||
type UserCreateRequest struct {
|
||||
*iam.User
|
||||
ClusterRole string `json:"cluster_role"`
|
||||
}
|
||||
|
||||
func (request *UserCreateRequest) Validate() error {
|
||||
if request.Username == "" {
|
||||
return fmt.Errorf("username must not be empty")
|
||||
}
|
||||
|
||||
// Parses a single RFC 5322 address, e.g. "Barry Gibbs <bg@example.com>"
|
||||
if _, err := mail.ParseAddress(request.Email); err != nil {
|
||||
return fmt.Errorf("invalid email: %s", request.Email)
|
||||
}
|
||||
|
||||
if len(request.Password) < minPasswordLength {
|
||||
return fmt.Errorf("password must be at least %d characters long", minPasswordLength)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,16 +1,24 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"net/http"
|
||||
"github.com/emicklei/go-restful"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func HandleInternalError(response *restful.Response, err error) {
|
||||
statusCode := http.StatusInternalServerError
|
||||
statusCode := http.StatusInternalServerError
|
||||
|
||||
response.WriteError(statusCode, err)
|
||||
response.WriteError(statusCode, err)
|
||||
}
|
||||
|
||||
func HandleBadRequest(response *restful.Response, err error) {
|
||||
|
||||
}
|
||||
|
||||
func HandleNotFound(response *restful.Response, err error) {
|
||||
|
||||
}
|
||||
|
||||
func HandleForbidden(response *restful.Response, err error) {
|
||||
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ type Dependencies struct {
|
||||
// Injected Dependencies
|
||||
KubeClient k8s.Client
|
||||
S3 s3.Interface
|
||||
OpenPitrix openpitrix.Interface
|
||||
OpenPitrix openpitrix.Client
|
||||
Monitoring monitoring.Interface
|
||||
Logging logging.Interface
|
||||
Devops devops.Interface
|
||||
|
||||
@@ -16,185 +16,3 @@
|
||||
|
||||
*/
|
||||
package iam
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"k8s.io/api/rbac/v1"
|
||||
k8serr "k8s.io/apimachinery/pkg/api/errors"
|
||||
"kubesphere.io/kubesphere/pkg/server/params"
|
||||
"net/http"
|
||||
"sort"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/models/iam"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam/policy"
|
||||
"kubesphere.io/kubesphere/pkg/server/errors"
|
||||
)
|
||||
|
||||
type RoleList struct {
|
||||
ClusterRoles []*v1.ClusterRole `json:"clusterRole" description:"cluster role list"`
|
||||
Roles []*v1.Role `json:"roles" description:"role list"`
|
||||
}
|
||||
|
||||
func ListRoleUsers(req *restful.Request, resp *restful.Response) {
|
||||
roleName := req.PathParameter("role")
|
||||
namespace := req.PathParameter("namespace")
|
||||
|
||||
users, err := iam.RoleUsers(namespace, roleName)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(users)
|
||||
}
|
||||
|
||||
func ListClusterRoles(req *restful.Request, resp *restful.Response) {
|
||||
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
|
||||
orderBy := req.QueryParameter(params.OrderByParam)
|
||||
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
|
||||
reverse := params.ParseReverse(req)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
result, err := iam.ListClusterRoles(conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(result)
|
||||
|
||||
}
|
||||
|
||||
func ListRoles(req *restful.Request, resp *restful.Response) {
|
||||
namespace := req.PathParameter("namespace")
|
||||
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
|
||||
orderBy := req.QueryParameter(params.OrderByParam)
|
||||
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
|
||||
reverse := params.ParseReverse(req)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
result, err := iam.ListRoles(namespace, conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(result)
|
||||
|
||||
}
|
||||
|
||||
// List users by namespace
|
||||
func ListNamespaceUsers(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
namespace := req.PathParameter("namespace")
|
||||
|
||||
users, err := iam.NamespaceUsers(namespace)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
// sort by time by default
|
||||
sort.Slice(users, func(i, j int) bool {
|
||||
return users[i].RoleBindTime.After(*users[j].RoleBindTime)
|
||||
})
|
||||
|
||||
resp.WriteAsJson(users)
|
||||
}
|
||||
|
||||
func ListUserRoles(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
username := req.PathParameter("user")
|
||||
|
||||
roles, err := iam.GetUserRoles("", username)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
_, clusterRoles, err := iam.GetUserClusterRoles(username)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
roleList := RoleList{}
|
||||
roleList.Roles = roles
|
||||
roleList.ClusterRoles = clusterRoles
|
||||
|
||||
resp.WriteAsJson(roleList)
|
||||
}
|
||||
|
||||
func RulesMapping(req *restful.Request, resp *restful.Response) {
|
||||
rules := policy.RoleRuleMapping
|
||||
resp.WriteAsJson(rules)
|
||||
}
|
||||
|
||||
func ClusterRulesMapping(req *restful.Request, resp *restful.Response) {
|
||||
rules := policy.ClusterRoleRuleMapping
|
||||
resp.WriteAsJson(rules)
|
||||
}
|
||||
|
||||
func ListClusterRoleRules(req *restful.Request, resp *restful.Response) {
|
||||
clusterRoleName := req.PathParameter("clusterrole")
|
||||
rules, err := iam.GetClusterRoleSimpleRules(clusterRoleName)
|
||||
if err != nil {
|
||||
resp.WriteError(http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
resp.WriteAsJson(rules)
|
||||
}
|
||||
|
||||
func ListClusterRoleUsers(req *restful.Request, resp *restful.Response) {
|
||||
clusterRoleName := req.PathParameter("clusterrole")
|
||||
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
|
||||
orderBy := req.QueryParameter(params.OrderByParam)
|
||||
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
|
||||
reverse := params.ParseReverse(req)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
result, err := iam.ListClusterRoleUsers(clusterRoleName, conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
if k8serr.IsNotFound(err) {
|
||||
resp.WriteError(http.StatusNotFound, err)
|
||||
} else {
|
||||
resp.WriteError(http.StatusInternalServerError, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(result)
|
||||
}
|
||||
|
||||
func ListRoleRules(req *restful.Request, resp *restful.Response) {
|
||||
namespaceName := req.PathParameter("namespace")
|
||||
roleName := req.PathParameter("role")
|
||||
|
||||
rules, err := iam.GetRoleSimpleRules(namespaceName, roleName)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(rules)
|
||||
}
|
||||
|
||||
@@ -19,38 +19,15 @@ package iam
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"github.com/emicklei/go-restful"
|
||||
"k8s.io/klog"
|
||||
iamv1alpha2 "kubesphere.io/kubesphere/pkg/api/iam/v1alpha2"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam"
|
||||
"kubesphere.io/kubesphere/pkg/server/errors"
|
||||
"kubesphere.io/kubesphere/pkg/utils/iputil"
|
||||
"kubesphere.io/kubesphere/pkg/utils/jwtutil"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type Spec struct {
|
||||
Token string `json:"token" description:"access token"`
|
||||
}
|
||||
|
||||
type Status struct {
|
||||
Authenticated bool `json:"authenticated" description:"is authenticated"`
|
||||
User map[string]interface{} `json:"user,omitempty" description:"user info"`
|
||||
}
|
||||
|
||||
type TokenReview struct {
|
||||
APIVersion string `json:"apiVersion" description:"Kubernetes API version"`
|
||||
Kind string `json:"kind" description:"kind of the API object"`
|
||||
Spec *Spec `json:"spec,omitempty"`
|
||||
Status *Status `json:"status,omitempty" description:"token review status"`
|
||||
}
|
||||
|
||||
type LoginRequest struct {
|
||||
Username string `json:"username" description:"username"`
|
||||
Password string `json:"password" description:"password"`
|
||||
}
|
||||
|
||||
type OAuthRequest struct {
|
||||
GrantType string `json:"grant_type"`
|
||||
Username string `json:"username,omitempty" description:"username"`
|
||||
@@ -58,36 +35,6 @@ type OAuthRequest struct {
|
||||
RefreshToken string `json:"refresh_token,omitempty"`
|
||||
}
|
||||
|
||||
const (
|
||||
KindTokenReview = "TokenReview"
|
||||
)
|
||||
|
||||
func Login(req *restful.Request, resp *restful.Response) {
|
||||
var loginRequest LoginRequest
|
||||
|
||||
err := req.ReadEntity(&loginRequest)
|
||||
|
||||
if err != nil || loginRequest.Username == "" || loginRequest.Password == "" {
|
||||
resp.WriteHeaderAndEntity(http.StatusUnauthorized, errors.New("incorrect username or password"))
|
||||
return
|
||||
}
|
||||
|
||||
ip := iputil.RemoteIp(req.Request)
|
||||
|
||||
token, err := iam.Login(loginRequest.Username, loginRequest.Password, ip)
|
||||
|
||||
if err != nil {
|
||||
if serviceError, ok := err.(restful.ServiceError); ok {
|
||||
resp.WriteHeaderAndEntity(serviceError.Code, errors.New(serviceError.Message))
|
||||
return
|
||||
}
|
||||
resp.WriteHeaderAndEntity(http.StatusUnauthorized, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(token)
|
||||
}
|
||||
|
||||
func OAuth(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
authRequest := &OAuthRequest{}
|
||||
@@ -120,72 +67,3 @@ func OAuth(req *restful.Request, resp *restful.Response) {
|
||||
resp.WriteEntity(result)
|
||||
|
||||
}
|
||||
|
||||
// k8s token review
|
||||
func TokenReviewHandler(req *restful.Request, resp *restful.Response) {
|
||||
var tokenReview TokenReview
|
||||
|
||||
err := req.ReadEntity(&tokenReview)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if tokenReview.Spec == nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.New("token must not be null"))
|
||||
return
|
||||
}
|
||||
|
||||
uToken := tokenReview.Spec.Token
|
||||
|
||||
token, err := jwtutil.ValidateToken(uToken)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln("token review failed", uToken, err)
|
||||
failed := TokenReview{APIVersion: tokenReview.APIVersion,
|
||||
Kind: KindTokenReview,
|
||||
Status: &Status{
|
||||
Authenticated: false,
|
||||
},
|
||||
}
|
||||
resp.WriteAsJson(failed)
|
||||
return
|
||||
}
|
||||
|
||||
claims := token.Claims.(jwt.MapClaims)
|
||||
|
||||
username, ok := claims["username"].(string)
|
||||
|
||||
if !ok {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.New("username not found"))
|
||||
return
|
||||
}
|
||||
|
||||
user, err := iam.GetUserInfo(username)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
groups, err := iam.GetUserGroups(username)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
user.Groups = groups
|
||||
|
||||
success := TokenReview{APIVersion: tokenReview.APIVersion,
|
||||
Kind: KindTokenReview,
|
||||
Status: &Status{
|
||||
Authenticated: true,
|
||||
User: map[string]interface{}{"username": user.Username, "uid": user.Username, "groups": user.Groups},
|
||||
},
|
||||
}
|
||||
|
||||
resp.WriteAsJson(success)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ func ListGroupUsers(req *restful.Request, resp *restful.Response) {
|
||||
return
|
||||
}
|
||||
|
||||
users := make([]*models.User, 0)
|
||||
users := make([]*iam.User, 0)
|
||||
|
||||
modify := false
|
||||
|
||||
|
||||
@@ -29,60 +29,10 @@ import (
|
||||
"github.com/go-ldap/ldap"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam"
|
||||
"kubesphere.io/kubesphere/pkg/server/errors"
|
||||
)
|
||||
|
||||
func CreateUser(req *restful.Request, resp *restful.Response) {
|
||||
var user models.User
|
||||
|
||||
err := req.ReadEntity(&user)
|
||||
|
||||
if err != nil {
|
||||
klog.Info(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if user.Username == "" {
|
||||
err = fmt.Errorf("invalid username: %s", user.Username)
|
||||
klog.Info(err, user.Username)
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
// Parses a single RFC 5322 address, e.g. "Barry Gibbs <bg@example.com>"
|
||||
if _, err = mail.ParseAddress(user.Email); err != nil {
|
||||
err = fmt.Errorf("invalid email: %s", user.Email)
|
||||
klog.Info(err, user.Email)
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if len(user.Password) < 6 {
|
||||
err = fmt.Errorf("invalid password")
|
||||
klog.Info(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
created, err := iam.CreateUser(&user)
|
||||
|
||||
if err != nil {
|
||||
if ldap.IsErrorWithCode(err, ldap.LDAPResultEntryAlreadyExists) {
|
||||
klog.Info(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusConflict, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
klog.Info(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(created)
|
||||
}
|
||||
|
||||
func DeleteUser(req *restful.Request, resp *restful.Response) {
|
||||
username := req.PathParameter("user")
|
||||
|
||||
@@ -110,7 +60,7 @@ func UpdateUser(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
usernameInPath := req.PathParameter("user")
|
||||
usernameInHeader := req.HeaderParameter(constants.UserNameHeader)
|
||||
var user models.User
|
||||
var user iam.User
|
||||
|
||||
err := req.ReadEntity(&user)
|
||||
|
||||
@@ -254,8 +204,8 @@ func DescribeUser(req *restful.Request, resp *restful.Response) {
|
||||
}
|
||||
|
||||
result := struct {
|
||||
*models.User
|
||||
ClusterRules []models.SimpleRule `json:"cluster_rules"`
|
||||
*iam.User
|
||||
ClusterRules []iam.SimpleRule `json:"cluster_rules"`
|
||||
}{
|
||||
User: user,
|
||||
ClusterRules: clusterRules,
|
||||
|
||||
@@ -21,7 +21,6 @@ import (
|
||||
"github.com/emicklei/go-restful"
|
||||
k8serr "k8s.io/apimachinery/pkg/api/errors"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam"
|
||||
"kubesphere.io/kubesphere/pkg/models/workspaces"
|
||||
"kubesphere.io/kubesphere/pkg/server/errors"
|
||||
@@ -113,7 +112,7 @@ func ListDevopsRoleRules(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
func InviteUser(req *restful.Request, resp *restful.Response) {
|
||||
workspace := req.PathParameter("workspace")
|
||||
var user models.User
|
||||
var user iam.User
|
||||
err := req.ReadEntity(&user)
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
|
||||
@@ -1,280 +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 openpitrix
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/emicklei/go-restful"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"k8s.io/api/core/v1"
|
||||
"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/resources/v1alpha2"
|
||||
"kubesphere.io/kubesphere/pkg/server/errors"
|
||||
"kubesphere.io/kubesphere/pkg/server/params"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func ListApplications(req *restful.Request, resp *restful.Response) {
|
||||
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
|
||||
namespaceName := req.PathParameter("namespace")
|
||||
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
|
||||
orderBy := req.QueryParameter(params.OrderByParam)
|
||||
reverse := params.ParseReverse(req)
|
||||
|
||||
if orderBy == "" {
|
||||
orderBy = "create_time"
|
||||
reverse = true
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if namespaceName != "" {
|
||||
namespace, err := v1alpha2.GetResource("", v1alpha2.Namespaces, namespaceName)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
var runtimeId string
|
||||
|
||||
if ns, ok := namespace.(*v1.Namespace); ok {
|
||||
runtimeId = ns.Annotations[constants.OpenPitrixRuntimeAnnotationKey]
|
||||
}
|
||||
|
||||
if runtimeId == "" {
|
||||
resp.WriteAsJson(models.PageableResponse{Items: []interface{}{}, TotalCount: 0})
|
||||
return
|
||||
} else {
|
||||
conditions.Match["runtime_id"] = runtimeId
|
||||
}
|
||||
}
|
||||
|
||||
result, err := openpitrix.ListApplications(conditions, limit, offset, orderBy, reverse)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(result)
|
||||
}
|
||||
|
||||
func DescribeApplication(req *restful.Request, resp *restful.Response) {
|
||||
clusterId := req.PathParameter("application")
|
||||
namespaceName := req.PathParameter("namespace")
|
||||
app, err := openpitrix.DescribeApplication(namespaceName, clusterId)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
if status.Code(err) == codes.NotFound {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
namespace, err := resources.GetResource("", v1alpha2.Namespaces, namespaceName)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
var runtimeId string
|
||||
|
||||
if ns, ok := namespace.(*v1.Namespace); ok {
|
||||
runtimeId = ns.Annotations[constants.OpenPitrixRuntimeAnnotationKey]
|
||||
}
|
||||
|
||||
if runtimeId != app.Cluster.RuntimeId {
|
||||
err = fmt.Errorf("rumtime not match %s,%s", app.Cluster.RuntimeId, runtimeId)
|
||||
klog.V(4).Info(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusForbidden, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(app)
|
||||
return
|
||||
}
|
||||
|
||||
func CreateApplication(req *restful.Request, resp *restful.Response) {
|
||||
namespace := req.PathParameter("namespace")
|
||||
var createClusterRequest types.CreateClusterRequest
|
||||
err := req.ReadEntity(&createClusterRequest)
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
createClusterRequest.Username = req.HeaderParameter(constants.UserNameHeader)
|
||||
|
||||
err = openpitrix.CreateApplication(namespace, createClusterRequest)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
resp.WriteEntity(errors.None)
|
||||
}
|
||||
|
||||
func ModifyApplication(req *restful.Request, resp *restful.Response) {
|
||||
var modifyClusterAttributesRequest types.ModifyClusterAttributesRequest
|
||||
clusterId := req.PathParameter("application")
|
||||
namespaceName := req.PathParameter("namespace")
|
||||
err := req.ReadEntity(&modifyClusterAttributesRequest)
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
app, err := openpitrix.DescribeApplication(namespaceName, clusterId)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if status.Code(err) == codes.NotFound {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
namespace, err := resources.GetResource("", v1alpha2.Namespaces, namespaceName)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
var runtimeId string
|
||||
|
||||
if ns, ok := namespace.(*v1.Namespace); ok {
|
||||
runtimeId = ns.Annotations[constants.OpenPitrixRuntimeAnnotationKey]
|
||||
}
|
||||
|
||||
if runtimeId != app.Cluster.RuntimeId {
|
||||
err = fmt.Errorf("rumtime not match %s,%s", app.Cluster.RuntimeId, runtimeId)
|
||||
klog.V(4).Info(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusForbidden, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
err = openpitrix.PatchApplication(&modifyClusterAttributesRequest)
|
||||
|
||||
if status.Code(err) == codes.NotFound {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(errors.None)
|
||||
}
|
||||
|
||||
func DeleteApplication(req *restful.Request, resp *restful.Response) {
|
||||
clusterId := req.PathParameter("application")
|
||||
namespaceName := req.PathParameter("namespace")
|
||||
app, err := openpitrix.DescribeApplication(namespaceName, clusterId)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if status.Code(err) == codes.NotFound {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
namespace, err := resources.GetResource("", v1alpha2.Namespaces, namespaceName)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
var runtimeId string
|
||||
|
||||
if ns, ok := namespace.(*v1.Namespace); ok {
|
||||
runtimeId = ns.Annotations[constants.OpenPitrixRuntimeAnnotationKey]
|
||||
}
|
||||
|
||||
if runtimeId != app.Cluster.RuntimeId {
|
||||
err = fmt.Errorf("rumtime not match %s,%s", app.Cluster.RuntimeId, runtimeId)
|
||||
klog.V(4).Info(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusForbidden, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
err = openpitrix.DeleteApplication(clusterId)
|
||||
|
||||
if status.Code(err) == codes.NotFound {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(errors.None)
|
||||
}
|
||||
@@ -1,548 +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 openpitrix
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"k8s.io/klog"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/models/openpitrix/app"
|
||||
"kubesphere.io/kubesphere/pkg/models/openpitrix/type"
|
||||
"kubesphere.io/kubesphere/pkg/server/errors"
|
||||
"kubesphere.io/kubesphere/pkg/server/params"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func GetAppVersionPackage(req *restful.Request, resp *restful.Response) {
|
||||
appId := req.PathParameter("app")
|
||||
versionId := req.PathParameter("version")
|
||||
|
||||
result, err := app.GetAppVersionPackage(appId, versionId)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func DoAppAction(req *restful.Request, resp *restful.Response) {
|
||||
var doActionRequest types.ActionRequest
|
||||
err := req.ReadEntity(&doActionRequest)
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
appId := req.PathParameter("app")
|
||||
|
||||
err = app.DoAppAction(appId, &doActionRequest)
|
||||
if status.Code(err) == codes.NotFound {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if status.Code(err) == codes.InvalidArgument {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(errors.None)
|
||||
}
|
||||
|
||||
func DoAppVersionAction(req *restful.Request, resp *restful.Response) {
|
||||
var doActionRequest types.ActionRequest
|
||||
err := req.ReadEntity(&doActionRequest)
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
doActionRequest.Username = req.HeaderParameter(constants.UserNameHeader)
|
||||
|
||||
versionId := req.PathParameter("version")
|
||||
|
||||
err = app.DoAppVersionAction(versionId, &doActionRequest)
|
||||
if status.Code(err) == codes.NotFound {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if status.Code(err) == codes.InvalidArgument {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(errors.None)
|
||||
}
|
||||
|
||||
func GetAppVersionFiles(req *restful.Request, resp *restful.Response) {
|
||||
versionId := req.PathParameter("version")
|
||||
getAppVersionFilesRequest := &types.GetAppVersionFilesRequest{}
|
||||
if f := req.QueryParameter("files"); f != "" {
|
||||
getAppVersionFilesRequest.Files = strings.Split(f, ",")
|
||||
}
|
||||
|
||||
result, err := app.GetAppVersionFiles(versionId, getAppVersionFilesRequest)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if status.Code(err) == codes.NotFound {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func ListAppVersionAudits(req *restful.Request, resp *restful.Response) {
|
||||
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
|
||||
orderBy := req.QueryParameter(params.OrderByParam)
|
||||
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
|
||||
reverse := params.ParseReverse(req)
|
||||
appId := req.PathParameter("app")
|
||||
versionId := req.PathParameter("version")
|
||||
if orderBy == "" {
|
||||
orderBy = "status_time"
|
||||
reverse = true
|
||||
}
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
conditions.Match["app"] = appId
|
||||
if versionId != "" {
|
||||
conditions.Match["version"] = versionId
|
||||
}
|
||||
|
||||
result, err := app.ListAppVersionAudits(conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func ListReviews(req *restful.Request, resp *restful.Response) {
|
||||
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
|
||||
orderBy := req.QueryParameter(params.OrderByParam)
|
||||
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
|
||||
reverse := params.ParseReverse(req)
|
||||
if orderBy == "" {
|
||||
orderBy = "status_time"
|
||||
reverse = true
|
||||
}
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
result, err := app.ListAppVersionReviews(conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func ListAppVersions(req *restful.Request, resp *restful.Response) {
|
||||
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
|
||||
orderBy := req.QueryParameter(params.OrderByParam)
|
||||
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
|
||||
reverse := params.ParseReverse(req)
|
||||
appId := req.PathParameter("app")
|
||||
statistics, _ := strconv.ParseBool(req.QueryParameter("statistics"))
|
||||
if orderBy == "" {
|
||||
orderBy = "create_time"
|
||||
reverse = true
|
||||
}
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
conditions.Match["app"] = appId
|
||||
|
||||
result, err := app.ListAppVersions(conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if statistics {
|
||||
for _, item := range result.Items {
|
||||
if version, ok := item.(*types.AppVersion); ok {
|
||||
statisticsResult, err := openpitrix.ListApplications(¶ms.Conditions{Match: map[string]string{"app_id": version.AppId, "version_id": version.VersionId}}, 0, 0, "", false)
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
version.ClusterTotal = &statisticsResult.TotalCount
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func ListApps(req *restful.Request, resp *restful.Response) {
|
||||
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
|
||||
orderBy := req.QueryParameter(params.OrderByParam)
|
||||
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
|
||||
reverse := params.ParseReverse(req)
|
||||
statistics, _ := strconv.ParseBool(req.QueryParameter("statistics"))
|
||||
if orderBy == "" {
|
||||
orderBy = "create_time"
|
||||
reverse = true
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
result, err := app.ListApps(conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if statistics {
|
||||
for _, item := range result.Items {
|
||||
if app, ok := item.(*types.App); ok {
|
||||
status := "active|used|enabled|stopped|pending|creating|upgrading|updating|rollbacking|stopping|starting|recovering|resizing|scaling|deleting"
|
||||
statisticsResult, err := openpitrix.ListApplications(¶ms.Conditions{Match: map[string]string{"app_id": app.AppId, "status": status}}, 0, 0, "", false)
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
app.ClusterTotal = &statisticsResult.TotalCount
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func ModifyApp(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
var patchAppRequest types.ModifyAppRequest
|
||||
err := req.ReadEntity(&patchAppRequest)
|
||||
appId := req.PathParameter("app")
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
err = app.PatchApp(appId, &patchAppRequest)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if status.Code(err) == codes.NotFound {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if status.Code(err) == codes.InvalidArgument {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(errors.None)
|
||||
}
|
||||
|
||||
func DescribeApp(req *restful.Request, resp *restful.Response) {
|
||||
appId := req.PathParameter("app")
|
||||
|
||||
result, err := app.DescribeApp(appId)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if status.Code(err) == codes.NotFound {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func DeleteApp(req *restful.Request, resp *restful.Response) {
|
||||
appId := req.PathParameter("app")
|
||||
|
||||
err := app.DeleteApp(appId)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if status.Code(err) == codes.NotFound {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(errors.None)
|
||||
}
|
||||
|
||||
func CreateApp(req *restful.Request, resp *restful.Response) {
|
||||
createAppRequest := &types.CreateAppRequest{}
|
||||
err := req.ReadEntity(createAppRequest)
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
createAppRequest.Username = req.HeaderParameter(constants.UserNameHeader)
|
||||
|
||||
validate, _ := strconv.ParseBool(req.QueryParameter("validate"))
|
||||
|
||||
var result interface{}
|
||||
|
||||
if validate {
|
||||
validatePackageRequest := &types.ValidatePackageRequest{
|
||||
VersionPackage: createAppRequest.VersionPackage,
|
||||
VersionType: createAppRequest.VersionType,
|
||||
}
|
||||
result, err = app.ValidatePackage(validatePackageRequest)
|
||||
} else {
|
||||
result, err = app.CreateApp(createAppRequest)
|
||||
}
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if status.Code(err) == codes.InvalidArgument {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func CreateAppVersion(req *restful.Request, resp *restful.Response) {
|
||||
var createAppVersionRequest types.CreateAppVersionRequest
|
||||
err := req.ReadEntity(&createAppVersionRequest)
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
// override app id
|
||||
createAppVersionRequest.AppId = req.PathParameter("app")
|
||||
createAppVersionRequest.Username = req.HeaderParameter(constants.UserNameHeader)
|
||||
|
||||
validate, _ := strconv.ParseBool(req.QueryParameter("validate"))
|
||||
|
||||
var result interface{}
|
||||
|
||||
if validate {
|
||||
validatePackageRequest := &types.ValidatePackageRequest{
|
||||
VersionPackage: createAppVersionRequest.Package,
|
||||
VersionType: createAppVersionRequest.Type,
|
||||
}
|
||||
result, err = app.ValidatePackage(validatePackageRequest)
|
||||
} else {
|
||||
result, err = app.CreateAppVersion(&createAppVersionRequest)
|
||||
}
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if status.Code(err) == codes.InvalidArgument {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func ModifyAppVersion(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
var patchAppVersionRequest types.ModifyAppVersionRequest
|
||||
err := req.ReadEntity(&patchAppVersionRequest)
|
||||
versionId := req.PathParameter("version")
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
err = app.PatchAppVersion(versionId, &patchAppVersionRequest)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if status.Code(err) == codes.InvalidArgument {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(errors.None)
|
||||
}
|
||||
|
||||
func DeleteAppVersion(req *restful.Request, resp *restful.Response) {
|
||||
versionId := req.PathParameter("version")
|
||||
|
||||
err := app.DeleteAppVersion(versionId)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if status.Code(err) == codes.NotFound {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(errors.None)
|
||||
}
|
||||
|
||||
func DescribeAppVersion(req *restful.Request, resp *restful.Response) {
|
||||
versionId := req.PathParameter("version")
|
||||
|
||||
result, err := app.DescribeAppVersion(versionId)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if status.Code(err) == codes.NotFound {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
@@ -1,54 +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 openpitrix
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"kubesphere.io/kubesphere/pkg/models/openpitrix/attachment"
|
||||
"kubesphere.io/kubesphere/pkg/server/errors"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func DescribeAttachment(req *restful.Request, resp *restful.Response) {
|
||||
attachmentId := req.PathParameter("attachment")
|
||||
fileName := req.QueryParameter("filename")
|
||||
result, err := attachment.DescribeAttachment(attachmentId)
|
||||
// file raw
|
||||
if fileName != "" {
|
||||
data := result.AttachmentContent[fileName]
|
||||
resp.Write(data)
|
||||
resp.Header().Set("Content-Type", "text/plain")
|
||||
return
|
||||
}
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if status.Code(err) == codes.NotFound {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
@@ -1,173 +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 openpitrix
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"k8s.io/klog"
|
||||
"kubesphere.io/kubesphere/pkg/models/openpitrix/app"
|
||||
"kubesphere.io/kubesphere/pkg/models/openpitrix/category"
|
||||
"kubesphere.io/kubesphere/pkg/models/openpitrix/type"
|
||||
"kubesphere.io/kubesphere/pkg/server/errors"
|
||||
"kubesphere.io/kubesphere/pkg/server/params"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func CreateCategory(req *restful.Request, resp *restful.Response) {
|
||||
createCategoryRequest := &types.CreateCategoryRequest{}
|
||||
err := req.ReadEntity(createCategoryRequest)
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
result, err := category.CreateCategory(createCategoryRequest)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
if status.Code(err) == codes.InvalidArgument {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
func DeleteCategory(req *restful.Request, resp *restful.Response) {
|
||||
categoryId := req.PathParameter("category")
|
||||
|
||||
err := category.DeleteCategory(categoryId)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
if status.Code(err) == codes.NotFound {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(errors.None)
|
||||
}
|
||||
func ModifyCategory(req *restful.Request, resp *restful.Response) {
|
||||
var modifyCategoryRequest types.ModifyCategoryRequest
|
||||
categoryId := req.PathParameter("category")
|
||||
err := req.ReadEntity(&modifyCategoryRequest)
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
err = category.PatchCategory(categoryId, &modifyCategoryRequest)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
if status.Code(err) == codes.InvalidArgument {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(errors.None)
|
||||
}
|
||||
func DescribeCategory(req *restful.Request, resp *restful.Response) {
|
||||
categoryId := req.PathParameter("category")
|
||||
|
||||
result, err := category.DescribeCategory(categoryId)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if status.Code(err) == codes.NotFound {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
func ListCategories(req *restful.Request, resp *restful.Response) {
|
||||
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
|
||||
orderBy := req.QueryParameter(params.OrderByParam)
|
||||
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
|
||||
reverse := params.ParseReverse(req)
|
||||
if orderBy == "" {
|
||||
orderBy = "create_time"
|
||||
reverse = true
|
||||
}
|
||||
statistics, _ := strconv.ParseBool(req.QueryParameter("statistics"))
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
result, err := category.ListCategories(conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if statistics {
|
||||
for _, item := range result.Items {
|
||||
if category, ok := item.(*types.Category); ok {
|
||||
statisticsResult, err := app.ListApps(¶ms.Conditions{Match: map[string]string{"category_id": category.CategoryID, "status": app.StatusActive, "repo": app.BuiltinRepoId}}, "", false, 0, 0)
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
category.AppTotal = &statisticsResult.TotalCount
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
@@ -1,223 +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 openpitrix
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"k8s.io/klog"
|
||||
"kubesphere.io/kubesphere/pkg/models/openpitrix/repo"
|
||||
"kubesphere.io/kubesphere/pkg/models/openpitrix/type"
|
||||
"kubesphere.io/kubesphere/pkg/server/errors"
|
||||
"kubesphere.io/kubesphere/pkg/server/params"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func CreateRepo(req *restful.Request, resp *restful.Response) {
|
||||
createRepoRequest := &types.CreateRepoRequest{}
|
||||
err := req.ReadEntity(createRepoRequest)
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
validate, _ := strconv.ParseBool(req.QueryParameter("validate"))
|
||||
|
||||
var result interface{}
|
||||
|
||||
if validate {
|
||||
validateRepoRequest := &types.ValidateRepoRequest{
|
||||
Type: createRepoRequest.Type,
|
||||
Url: createRepoRequest.URL,
|
||||
Credential: createRepoRequest.Credential,
|
||||
}
|
||||
result, err = repo.ValidateRepo(validateRepoRequest)
|
||||
} else {
|
||||
result, err = repo.CreateRepo(createRepoRequest)
|
||||
}
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
if status.Code(err) == codes.InvalidArgument {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func DoRepoAction(req *restful.Request, resp *restful.Response) {
|
||||
repoActionRequest := &types.RepoActionRequest{}
|
||||
repoId := req.PathParameter("repo")
|
||||
err := req.ReadEntity(repoActionRequest)
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
err = repo.DoRepoAction(repoId, repoActionRequest)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
if status.Code(err) == codes.InvalidArgument {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(errors.None)
|
||||
}
|
||||
|
||||
func DeleteRepo(req *restful.Request, resp *restful.Response) {
|
||||
repoId := req.PathParameter("repo")
|
||||
|
||||
err := repo.DeleteRepo(repoId)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
if status.Code(err) == codes.NotFound {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(errors.None)
|
||||
}
|
||||
|
||||
func ModifyRepo(req *restful.Request, resp *restful.Response) {
|
||||
var updateRepoRequest types.ModifyRepoRequest
|
||||
repoId := req.PathParameter("repo")
|
||||
err := req.ReadEntity(&updateRepoRequest)
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
err = repo.PatchRepo(repoId, &updateRepoRequest)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
if status.Code(err) == codes.InvalidArgument {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(errors.None)
|
||||
}
|
||||
|
||||
func DescribeRepo(req *restful.Request, resp *restful.Response) {
|
||||
repoId := req.PathParameter("repo")
|
||||
|
||||
result, err := repo.DescribeRepo(repoId)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
if status.Code(err) == codes.NotFound {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
func ListRepos(req *restful.Request, resp *restful.Response) {
|
||||
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
|
||||
orderBy := req.QueryParameter(params.OrderByParam)
|
||||
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
|
||||
reverse := params.ParseReverse(req)
|
||||
if orderBy == "" {
|
||||
orderBy = "create_time"
|
||||
reverse = true
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
result, err := repo.ListRepos(conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func ListRepoEvents(req *restful.Request, resp *restful.Response) {
|
||||
repoId := req.PathParameter("repo")
|
||||
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
|
||||
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
result, err := repo.ListRepoEvents(repoId, conditions, limit, offset)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
@@ -1,440 +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 tenant
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"k8s.io/api/core/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
k8serr "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/util/net"
|
||||
"k8s.io/klog"
|
||||
devopsv1alpha2 "kubesphere.io/kubesphere/pkg/api/devops/v1alpha2"
|
||||
loggingv1alpha2 "kubesphere.io/kubesphere/pkg/api/logging/v1alpha2"
|
||||
"kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha1"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/logging"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam"
|
||||
"kubesphere.io/kubesphere/pkg/models/metrics"
|
||||
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
|
||||
"kubesphere.io/kubesphere/pkg/models/tenant"
|
||||
"kubesphere.io/kubesphere/pkg/models/workspaces"
|
||||
"kubesphere.io/kubesphere/pkg/server/errors"
|
||||
"kubesphere.io/kubesphere/pkg/server/params"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func ListWorkspaceRules(req *restful.Request, resp *restful.Response) {
|
||||
workspace := req.PathParameter("workspace")
|
||||
username := req.HeaderParameter(constants.UserNameHeader)
|
||||
|
||||
rules, err := iam.GetUserWorkspaceSimpleRules(workspace, username)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(rules)
|
||||
}
|
||||
|
||||
func ListWorkspaces(req *restful.Request, resp *restful.Response) {
|
||||
username := req.HeaderParameter(constants.UserNameHeader)
|
||||
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
|
||||
orderBy := req.QueryParameter(params.OrderByParam)
|
||||
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
|
||||
reverse := params.ParseReverse(req)
|
||||
|
||||
if orderBy == "" {
|
||||
orderBy = v1alpha2.CreateTime
|
||||
reverse = true
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
result, err := tenant.ListWorkspaces(username, conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(result)
|
||||
}
|
||||
|
||||
func DescribeWorkspace(req *restful.Request, resp *restful.Response) {
|
||||
username := req.HeaderParameter(constants.UserNameHeader)
|
||||
workspaceName := req.PathParameter("workspace")
|
||||
|
||||
result, err := tenant.DescribeWorkspace(username, workspaceName)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorf("describe workspace failed: %+v", err)
|
||||
if k8serr.IsNotFound(err) {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
|
||||
} else {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(result)
|
||||
}
|
||||
func ListNamespacesByUsername(req *restful.Request, resp *restful.Response) {
|
||||
ListNamespaces(req, resp)
|
||||
}
|
||||
|
||||
func ListNamespaces(req *restful.Request, resp *restful.Response) {
|
||||
workspace := req.PathParameter("workspace")
|
||||
username := req.PathParameter("member")
|
||||
// /workspaces/{workspace}/members/{username}/namespaces
|
||||
if username == "" {
|
||||
// /workspaces/{workspace}/namespaces
|
||||
username = req.HeaderParameter(constants.UserNameHeader)
|
||||
}
|
||||
|
||||
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
|
||||
orderBy := req.QueryParameter(params.OrderByParam)
|
||||
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
|
||||
reverse := params.ParseReverse(req)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
conditions.Match[constants.WorkspaceLabelKey] = workspace
|
||||
|
||||
result, err := tenant.ListNamespaces(username, conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
namespaces := make([]*v1.Namespace, 0)
|
||||
|
||||
for _, item := range result.Items {
|
||||
namespaces = append(namespaces, item.(*v1.Namespace).DeepCopy())
|
||||
}
|
||||
|
||||
namespaces = metrics.GetNamespacesWithMetrics(namespaces)
|
||||
|
||||
items := make([]interface{}, 0)
|
||||
|
||||
for _, item := range namespaces {
|
||||
items = append(items, item)
|
||||
}
|
||||
|
||||
result.Items = items
|
||||
|
||||
resp.WriteAsJson(result)
|
||||
}
|
||||
|
||||
func CreateNamespace(req *restful.Request, resp *restful.Response) {
|
||||
workspaceName := req.PathParameter("workspace")
|
||||
username := req.HeaderParameter(constants.UserNameHeader)
|
||||
var namespace v1.Namespace
|
||||
err := req.ReadEntity(&namespace)
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
workspace, err := tenant.GetWorkspace(workspaceName)
|
||||
|
||||
err = checkResourceQuotas(workspace)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusForbidden, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if k8serr.IsNotFound(err) {
|
||||
resp.WriteHeaderAndEntity(http.StatusForbidden, errors.Wrap(err))
|
||||
} else {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
created, err := tenant.CreateNamespace(workspaceName, &namespace, username)
|
||||
|
||||
if err != nil {
|
||||
if k8serr.IsAlreadyExists(err) {
|
||||
resp.WriteHeaderAndEntity(http.StatusConflict, err)
|
||||
} else {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
resp.WriteAsJson(created)
|
||||
}
|
||||
|
||||
func DeleteNamespace(req *restful.Request, resp *restful.Response) {
|
||||
workspaceName := req.PathParameter("workspace")
|
||||
namespaceName := req.PathParameter("namespace")
|
||||
|
||||
err := workspaces.DeleteNamespace(workspaceName, namespaceName)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(errors.None)
|
||||
}
|
||||
|
||||
func checkResourceQuotas(wokrspace *v1alpha1.Workspace) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func ListDevopsProjectsByUsername(req *restful.Request, resp *restful.Response) {
|
||||
ListDevopsProjects(req, resp)
|
||||
}
|
||||
|
||||
func ListDevopsProjects(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
workspace := req.PathParameter("workspace")
|
||||
username := req.PathParameter("member")
|
||||
if username == "" {
|
||||
username = req.HeaderParameter(constants.UserNameHeader)
|
||||
}
|
||||
orderBy := req.QueryParameter(params.OrderByParam)
|
||||
reverse := params.ParseReverse(req)
|
||||
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
|
||||
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
|
||||
|
||||
if err != nil {
|
||||
klog.Errorf("%+v", err)
|
||||
errors.ParseSvcErr(restful.NewError(http.StatusBadRequest, err.Error()), resp)
|
||||
return
|
||||
}
|
||||
|
||||
result, err := tenant.ListDevopsProjects(workspace, username, conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorf("%+v", err)
|
||||
errors.ParseSvcErr(err, resp)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(result)
|
||||
}
|
||||
|
||||
func GetDevOpsProjectsCount(req *restful.Request, resp *restful.Response) {
|
||||
username := req.HeaderParameter(constants.UserNameHeader)
|
||||
|
||||
result, err := tenant.GetDevOpsProjectsCount(username)
|
||||
if err != nil {
|
||||
klog.Errorf("%+v", err)
|
||||
errors.ParseSvcErr(err, resp)
|
||||
return
|
||||
}
|
||||
resp.WriteAsJson(struct {
|
||||
Count uint32 `json:"count"`
|
||||
}{Count: result})
|
||||
}
|
||||
func DeleteDevopsProject(req *restful.Request, resp *restful.Response) {
|
||||
projectId := req.PathParameter("devops")
|
||||
workspaceName := req.PathParameter("workspace")
|
||||
username := req.HeaderParameter(constants.UserNameHeader)
|
||||
|
||||
_, err := tenant.GetWorkspace(workspaceName)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorf("%+v", err)
|
||||
errors.ParseSvcErr(restful.NewError(http.StatusBadRequest, err.Error()), resp)
|
||||
return
|
||||
}
|
||||
|
||||
err = tenant.DeleteDevOpsProject(projectId, username)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorf("%+v", err)
|
||||
errors.ParseSvcErr(err, resp)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(errors.None)
|
||||
}
|
||||
|
||||
func CreateDevopsProject(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
workspaceName := req.PathParameter("workspace")
|
||||
username := req.HeaderParameter(constants.UserNameHeader)
|
||||
|
||||
var devops devopsv1alpha2.DevOpsProject
|
||||
|
||||
err := req.ReadEntity(&devops)
|
||||
|
||||
if err != nil {
|
||||
klog.Infof("%+v", err)
|
||||
errors.ParseSvcErr(restful.NewError(http.StatusBadRequest, err.Error()), resp)
|
||||
return
|
||||
}
|
||||
|
||||
klog.Infoln("create workspace", username, workspaceName, devops)
|
||||
project, err := tenant.CreateDevopsProject(username, workspaceName, &devops)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorf("%+v", err)
|
||||
errors.ParseSvcErr(err, resp)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(project)
|
||||
}
|
||||
|
||||
func ListNamespaceRules(req *restful.Request, resp *restful.Response) {
|
||||
namespace := req.PathParameter("namespace")
|
||||
username := req.HeaderParameter(constants.UserNameHeader)
|
||||
|
||||
rules, err := iam.GetUserNamespaceSimpleRules(namespace, username)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteError(http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(rules)
|
||||
}
|
||||
|
||||
func ListDevopsRules(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
devops := req.PathParameter("devops")
|
||||
username := req.HeaderParameter(constants.UserNameHeader)
|
||||
|
||||
rules, err := tenant.GetUserDevopsSimpleRules(username, devops)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorf("%+v", err)
|
||||
errors.ParseSvcErr(err, resp)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(rules)
|
||||
}
|
||||
|
||||
func LogQuery(req *restful.Request, resp *restful.Response) {
|
||||
operation := req.QueryParameter("operation")
|
||||
req, err := regenerateLoggingRequest(req)
|
||||
switch {
|
||||
case err != nil:
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
case req != nil:
|
||||
logging.LoggingQueryCluster(req, resp)
|
||||
default:
|
||||
if operation == "export" {
|
||||
resp.Header().Set(restful.HEADER_ContentType, "text/plain")
|
||||
resp.Header().Set("Content-Disposition", "attachment")
|
||||
resp.Write(nil)
|
||||
} else {
|
||||
resp.WriteAsJson(loggingv1alpha2.QueryResult{Read: new(loggingv1alpha2.ReadResult)})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// override namespace query conditions
|
||||
func regenerateLoggingRequest(req *restful.Request) (*restful.Request, error) {
|
||||
|
||||
username := req.HeaderParameter(constants.UserNameHeader)
|
||||
|
||||
// regenerate the request for log query
|
||||
newUrl := net.FormatURL("http", "127.0.0.1", 80, "/kapis/logging.kubesphere.io/v1alpha2/cluster")
|
||||
values := req.Request.URL.Query()
|
||||
|
||||
clusterRules, err := iam.GetUserClusterRules(username)
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hasClusterLogAccess := iam.RulesMatchesRequired(clusterRules, rbacv1.PolicyRule{Verbs: []string{"get"}, Resources: []string{"*"}, APIGroups: []string{"logging.kubesphere.io"}})
|
||||
// if the user is not a cluster admin
|
||||
if !hasClusterLogAccess {
|
||||
queryNamespaces := strings.Split(req.QueryParameter("namespaces"), ",")
|
||||
// then the user can only view logs of namespaces he belongs to
|
||||
namespaces := make([]string, 0)
|
||||
roles, err := iam.GetUserRoles("", username)
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
return nil, err
|
||||
}
|
||||
for _, role := range roles {
|
||||
if !sliceutil.HasString(namespaces, role.Namespace) && iam.RulesMatchesRequired(role.Rules, rbacv1.PolicyRule{Verbs: []string{"get"}, Resources: []string{"*"}, APIGroups: []string{"logging.kubesphere.io"}}) {
|
||||
namespaces = append(namespaces, role.Namespace)
|
||||
}
|
||||
}
|
||||
|
||||
// if the user belongs to no namespace
|
||||
// then no log visible
|
||||
if len(namespaces) == 0 {
|
||||
return nil, nil
|
||||
} else if len(queryNamespaces) == 1 && queryNamespaces[0] == "" {
|
||||
values.Set("namespaces", strings.Join(namespaces, ","))
|
||||
} else {
|
||||
inter := intersection(queryNamespaces, namespaces)
|
||||
if len(inter) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
values.Set("namespaces", strings.Join(inter, ","))
|
||||
}
|
||||
}
|
||||
|
||||
newUrl.RawQuery = values.Encode()
|
||||
|
||||
// forward the request to logging model
|
||||
newHttpRequest, _ := http.NewRequest(http.MethodGet, newUrl.String(), nil)
|
||||
return restful.NewRequest(newHttpRequest), nil
|
||||
}
|
||||
|
||||
func intersection(s1, s2 []string) (inter []string) {
|
||||
hash := make(map[string]bool)
|
||||
for _, e := range s1 {
|
||||
hash[e] = true
|
||||
}
|
||||
for _, e := range s2 {
|
||||
// If elements present in the hashmap then append intersection list.
|
||||
if hash[e] {
|
||||
inter = append(inter, e)
|
||||
}
|
||||
}
|
||||
//Remove dups from slice.
|
||||
inter = removeDups(inter)
|
||||
return
|
||||
}
|
||||
|
||||
//Remove dups from slice.
|
||||
func removeDups(elements []string) (nodups []string) {
|
||||
encountered := make(map[string]bool)
|
||||
for _, element := range elements {
|
||||
if !encountered[element] {
|
||||
nodups = append(nodups, element)
|
||||
encountered[element] = true
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -77,6 +77,7 @@ const (
|
||||
ComponentMetricsTag = "Component Metrics"
|
||||
LogQueryTag = "Log Query"
|
||||
FluentBitSetting = "Fluent Bit Setting"
|
||||
TerminalTag = "Terminal"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -100,7 +100,7 @@ var _ reconcile.Reconciler = &ReconcileNamespace{}
|
||||
// ReconcileNamespace reconciles a Namespace object
|
||||
type ReconcileNamespace struct {
|
||||
client.Client
|
||||
openpitrixClient *openpitrix.Client
|
||||
openpitrixClient openpitrix.Client
|
||||
scheme *runtime.Scheme
|
||||
}
|
||||
|
||||
@@ -361,7 +361,7 @@ func (r *ReconcileNamespace) checkAndCreateRuntime(namespace *corev1.Namespace)
|
||||
|
||||
adminKubeConfigName := fmt.Sprintf("kubeconfig-%s", constants.AdminUserName)
|
||||
|
||||
runtimeCredentials, err := r.openpitrixClient.Runtime().DescribeRuntimeCredentials(openpitrix.SystemContext(), &pb.DescribeRuntimeCredentialsRequest{SearchWord: &wrappers.StringValue{Value: adminKubeConfigName}, Limit: 1})
|
||||
runtimeCredentials, err := r.openpitrixClient.DescribeRuntimeCredentials(openpitrix.SystemContext(), &pb.DescribeRuntimeCredentialsRequest{SearchWord: &wrappers.StringValue{Value: adminKubeConfigName}, Limit: 1})
|
||||
|
||||
if err != nil {
|
||||
klog.Error(fmt.Sprintf("create runtime, namespace: %s, error: %s", namespace.Name, err))
|
||||
@@ -382,7 +382,7 @@ func (r *ReconcileNamespace) checkAndCreateRuntime(namespace *corev1.Namespace)
|
||||
return err
|
||||
}
|
||||
|
||||
resp, err := r.openpitrixClient.Runtime().CreateRuntimeCredential(openpitrix.SystemContext(), &pb.CreateRuntimeCredentialRequest{
|
||||
resp, err := r.openpitrixClient.CreateRuntimeCredential(openpitrix.SystemContext(), &pb.CreateRuntimeCredentialRequest{
|
||||
Name: &wrappers.StringValue{Value: adminKubeConfigName},
|
||||
Provider: &wrappers.StringValue{Value: "kubernetes"},
|
||||
Description: &wrappers.StringValue{Value: "kubeconfig"},
|
||||
@@ -399,7 +399,7 @@ func (r *ReconcileNamespace) checkAndCreateRuntime(namespace *corev1.Namespace)
|
||||
}
|
||||
|
||||
// TODO runtime id is invalid when recreate runtime
|
||||
runtimeId, err := r.openpitrixClient.Runtime().CreateRuntime(openpitrix.SystemContext(), &pb.CreateRuntimeRequest{
|
||||
runtimeId, err := r.openpitrixClient.CreateRuntime(openpitrix.SystemContext(), &pb.CreateRuntimeRequest{
|
||||
Name: &wrappers.StringValue{Value: namespace.Name},
|
||||
RuntimeCredentialId: &wrappers.StringValue{Value: kubesphereRuntimeCredentialId},
|
||||
Provider: &wrappers.StringValue{Value: openpitrix.KubernetesProvider},
|
||||
@@ -420,7 +420,7 @@ func (r *ReconcileNamespace) checkAndCreateRuntime(namespace *corev1.Namespace)
|
||||
func (r *ReconcileNamespace) deleteRuntime(namespace *corev1.Namespace) error {
|
||||
|
||||
if runtimeId := namespace.Annotations[constants.OpenPitrixRuntimeAnnotationKey]; runtimeId != "" {
|
||||
_, err := r.openpitrixClient.Runtime().DeleteRuntimes(openpitrix.SystemContext(), &pb.DeleteRuntimesRequest{RuntimeId: []string{runtimeId}, Force: &wrappers.BoolValue{Value: true}})
|
||||
_, err := r.openpitrixClient.DeleteRuntimes(openpitrix.SystemContext(), &pb.DeleteRuntimesRequest{RuntimeId: []string{runtimeId}, Force: &wrappers.BoolValue{Value: true}})
|
||||
|
||||
if err == nil || openpitrix.IsNotFound(err) || openpitrix.IsDeleted(err) {
|
||||
return nil
|
||||
|
||||
@@ -1,18 +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 iam contains iam API versions
|
||||
package iam
|
||||
@@ -1,33 +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 install
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
urlruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
||||
"kubesphere.io/kubesphere/pkg/kapis/iam/v1alpha2"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Install(runtime.Container)
|
||||
}
|
||||
|
||||
func Install(container *restful.Container) {
|
||||
urlruntime.Must(v1alpha2.AddToContainer(container))
|
||||
}
|
||||
@@ -1 +1,327 @@
|
||||
package v1alpha2
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"github.com/emicklei/go-restful"
|
||||
"github.com/go-ldap/ldap"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
k8serr "k8s.io/apimachinery/pkg/api/errors"
|
||||
"kubesphere.io/kubesphere/pkg/api"
|
||||
iamv1alpha2 "kubesphere.io/kubesphere/pkg/api/iam/v1alpha2"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam/policy"
|
||||
kserr "kubesphere.io/kubesphere/pkg/server/errors"
|
||||
"kubesphere.io/kubesphere/pkg/server/params"
|
||||
"kubesphere.io/kubesphere/pkg/utils/iputil"
|
||||
"kubesphere.io/kubesphere/pkg/utils/jwtutil"
|
||||
"net/http"
|
||||
"sort"
|
||||
)
|
||||
|
||||
type iamHandler struct {
|
||||
amOperator iam.AccessManagementInterface
|
||||
imOperator iam.IdentityManagementInterface
|
||||
}
|
||||
|
||||
func newIAMHandler() *iamHandler {
|
||||
return &iamHandler{}
|
||||
}
|
||||
|
||||
// k8s token review
|
||||
func (h *iamHandler) TokenReviewHandler(req *restful.Request, resp *restful.Response) {
|
||||
var tokenReview iamv1alpha2.TokenReview
|
||||
|
||||
err := req.ReadEntity(&tokenReview)
|
||||
|
||||
if err != nil {
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
if tokenReview.Spec == nil {
|
||||
api.HandleBadRequest(resp, errors.New("token must not be null"))
|
||||
return
|
||||
}
|
||||
|
||||
uToken := tokenReview.Spec.Token
|
||||
|
||||
token, err := jwtutil.ValidateToken(uToken)
|
||||
|
||||
if err != nil {
|
||||
failed := iamv1alpha2.TokenReview{APIVersion: tokenReview.APIVersion,
|
||||
Kind: iam.KindTokenReview,
|
||||
Status: &iamv1alpha2.Status{
|
||||
Authenticated: false,
|
||||
},
|
||||
}
|
||||
resp.WriteEntity(failed)
|
||||
return
|
||||
}
|
||||
|
||||
claims := token.Claims.(jwt.MapClaims)
|
||||
|
||||
username, ok := claims["username"].(string)
|
||||
|
||||
if !ok {
|
||||
api.HandleBadRequest(resp, errors.New("username not found"))
|
||||
return
|
||||
}
|
||||
|
||||
user, err := h.imOperator.DescribeUser(username)
|
||||
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
success := iamv1alpha2.TokenReview{APIVersion: tokenReview.APIVersion,
|
||||
Kind: iam.KindTokenReview,
|
||||
Status: &iamv1alpha2.Status{
|
||||
Authenticated: true,
|
||||
User: map[string]interface{}{"username": user.Username, "uid": user.Username, "groups": user.Groups},
|
||||
},
|
||||
}
|
||||
|
||||
resp.WriteEntity(success)
|
||||
}
|
||||
|
||||
func (h *iamHandler) Login(req *restful.Request, resp *restful.Response) {
|
||||
var loginRequest iamv1alpha2.LoginRequest
|
||||
|
||||
err := req.ReadEntity(&loginRequest)
|
||||
|
||||
if err != nil || loginRequest.Username == "" || loginRequest.Password == "" {
|
||||
resp.WriteHeaderAndEntity(http.StatusUnauthorized, errors.New("incorrect username or password"))
|
||||
return
|
||||
}
|
||||
|
||||
ip := iputil.RemoteIp(req.Request)
|
||||
|
||||
token, err := h.imOperator.Login(loginRequest.Username, loginRequest.Password, ip)
|
||||
|
||||
if err != nil {
|
||||
if serviceError, ok := err.(restful.ServiceError); ok {
|
||||
resp.WriteHeaderAndEntity(serviceError.Code, errors.New(serviceError.Message))
|
||||
return
|
||||
}
|
||||
resp.WriteHeaderAndEntity(http.StatusUnauthorized, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(token)
|
||||
}
|
||||
|
||||
func (h *iamHandler) CreateUser(req *restful.Request, resp *restful.Response) {
|
||||
var createRequest iamv1alpha2.UserCreateRequest
|
||||
err := req.ReadEntity(&createRequest)
|
||||
if err != nil {
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := createRequest.Validate(); err != nil {
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
created, err := h.imOperator.CreateUser(createRequest.User)
|
||||
|
||||
if err != nil {
|
||||
if ldap.IsErrorWithCode(err, ldap.LDAPResultEntryAlreadyExists) {
|
||||
resp.WriteHeaderAndEntity(http.StatusConflict, kserr.Wrap(err))
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
err := h.amOperator.CreateClusterRoleBinding(created.Username, createRequest.ClusterRole)
|
||||
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
resp.WriteEntity(created)
|
||||
}
|
||||
|
||||
func (h *iamHandler) ListRoleUsers(req *restful.Request, resp *restful.Response) {
|
||||
role := req.PathParameter("role")
|
||||
namespace := req.PathParameter("namespace")
|
||||
|
||||
roleBindings, err := h.amOperator.ListRoleBindings(namespace, role)
|
||||
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
result := make([]*iam.User, 0)
|
||||
for _, roleBinding := range roleBindings {
|
||||
for _, subject := range roleBinding.Subjects {
|
||||
if subject.Kind == rbacv1.UserKind {
|
||||
user, err := h.imOperator.GetUserInfo(subject.Name)
|
||||
// skip if user not exist
|
||||
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
result = append(result, user)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func (h *iamHandler) ListClusterRoles(req *restful.Request, resp *restful.Response) {
|
||||
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
|
||||
orderBy := req.QueryParameter(params.OrderByParam)
|
||||
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
|
||||
reverse := params.ParseReverse(req)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
result, err := iam.ListClusterRoles(conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(result)
|
||||
|
||||
}
|
||||
|
||||
func (h *iamHandler) ListRoles(req *restful.Request, resp *restful.Response) {
|
||||
namespace := req.PathParameter("namespace")
|
||||
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
|
||||
orderBy := req.QueryParameter(params.OrderByParam)
|
||||
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
|
||||
reverse := params.ParseReverse(req)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
result, err := iam.ListRoles(namespace, conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(result)
|
||||
|
||||
}
|
||||
|
||||
// List users by namespace
|
||||
func (h *iamHandler) ListNamespaceUsers(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
namespace := req.PathParameter("namespace")
|
||||
|
||||
users, err := iam.NamespaceUsers(namespace)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
// sort by time by default
|
||||
sort.Slice(users, func(i, j int) bool {
|
||||
return users[i].RoleBindTime.After(*users[j].RoleBindTime)
|
||||
})
|
||||
|
||||
resp.WriteAsJson(users)
|
||||
}
|
||||
|
||||
func (h *iamHandler) ListUserRoles(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
username := req.PathParameter("user")
|
||||
|
||||
roles, err := iam.GetUserRoles("", username)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
_, clusterRoles, err := iam.GetUserClusterRoles(username)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
roleList := RoleList{}
|
||||
roleList.Roles = roles
|
||||
roleList.ClusterRoles = clusterRoles
|
||||
|
||||
resp.WriteAsJson(roleList)
|
||||
}
|
||||
|
||||
func (h *iamHandler) RulesMapping(req *restful.Request, resp *restful.Response) {
|
||||
rules := policy.RoleRuleMapping
|
||||
resp.WriteAsJson(rules)
|
||||
}
|
||||
|
||||
func (h *iamHandler) ClusterRulesMapping(req *restful.Request, resp *restful.Response) {
|
||||
rules := policy.ClusterRoleRuleMapping
|
||||
resp.WriteAsJson(rules)
|
||||
}
|
||||
|
||||
func (h *iamHandler) ListClusterRoleRules(req *restful.Request, resp *restful.Response) {
|
||||
clusterRoleName := req.PathParameter("clusterrole")
|
||||
rules, err := iam.GetClusterRoleSimpleRules(clusterRoleName)
|
||||
if err != nil {
|
||||
resp.WriteError(http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
resp.WriteAsJson(rules)
|
||||
}
|
||||
|
||||
func (h *iamHandler) ListClusterRoleUsers(req *restful.Request, resp *restful.Response) {
|
||||
clusterRoleName := req.PathParameter("clusterrole")
|
||||
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
|
||||
orderBy := req.QueryParameter(params.OrderByParam)
|
||||
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
|
||||
reverse := params.ParseReverse(req)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
result, err := iam.ListClusterRoleUsers(clusterRoleName, conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
if k8serr.IsNotFound(err) {
|
||||
resp.WriteError(http.StatusNotFound, err)
|
||||
} else {
|
||||
resp.WriteError(http.StatusInternalServerError, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(result)
|
||||
}
|
||||
|
||||
func (h *iamHandler) ListRoleRules(req *restful.Request, resp *restful.Response) {
|
||||
namespaceName := req.PathParameter("namespace")
|
||||
roleName := req.PathParameter("role")
|
||||
|
||||
rules, err := iam.GetRoleSimpleRules(namespaceName, roleName)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(rules)
|
||||
}
|
||||
|
||||
@@ -22,10 +22,13 @@ import (
|
||||
"github.com/emicklei/go-restful-openapi"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"kubesphere.io/kubesphere/pkg/api"
|
||||
iamv1alpha2 "kubesphere.io/kubesphere/pkg/api/iam/v1alpha2"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/iam"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
iam2 "kubesphere.io/kubesphere/pkg/models/iam"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam/policy"
|
||||
"kubesphere.io/kubesphere/pkg/server/errors"
|
||||
"net/http"
|
||||
@@ -118,174 +121,169 @@ type DescribeWorkspaceUserResponse struct {
|
||||
func addWebService(c *restful.Container) error {
|
||||
ws := runtime.NewWebService(GroupVersion)
|
||||
|
||||
ok := "ok"
|
||||
handler := newIAMHandler()
|
||||
|
||||
ws.Route(ws.POST("/authenticate").
|
||||
To(iam.TokenReviewHandler).
|
||||
To(handler.TokenReviewHandler).
|
||||
Doc("TokenReview attempts to authenticate a token to a known user. Note: TokenReview requests may be cached by the webhook token authenticator plugin in the kube-apiserver.").
|
||||
Reads(iam.TokenReview{}).
|
||||
Returns(http.StatusOK, ok, iam.TokenReview{}).
|
||||
Reads(iamv1alpha2.TokenReview{}).
|
||||
Returns(http.StatusOK, api.StatusOK, iamv1alpha2.TokenReview{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.IdentityManagementTag}))
|
||||
ws.Route(ws.POST("/login").
|
||||
To(iam.Login).
|
||||
To(handler.Login).
|
||||
Doc("KubeSphere APIs support token-based authentication via the Authtoken request header. The POST Login API is used to retrieve the authentication token. After the authentication token is obtained, it must be inserted into the Authtoken header for all requests.").
|
||||
Reads(iam.LoginRequest{}).
|
||||
Returns(http.StatusOK, ok, models.AuthGrantResponse{}).
|
||||
Reads(iamv1alpha2.LoginRequest{}).
|
||||
Returns(http.StatusOK, api.StatusOK, models.AuthGrantResponse{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.IdentityManagementTag}))
|
||||
ws.Route(ws.POST("/token").
|
||||
To(iam.OAuth).
|
||||
Doc("OAuth API,only support resource owner password credentials grant").
|
||||
Reads(iam.LoginRequest{}).
|
||||
Returns(http.StatusOK, ok, models.AuthGrantResponse{}).
|
||||
ws.Route(ws.POST("/users").
|
||||
To(handler.CreateUser).
|
||||
Doc("Create a user account.").
|
||||
Reads(CreateUserRequest{}).
|
||||
Returns(http.StatusOK, api.StatusOK, errors.Error{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.IdentityManagementTag}))
|
||||
ws.Route(ws.GET("/users/{user}").
|
||||
To(iam.DescribeUser).
|
||||
Doc("Describe the specified user.").
|
||||
Param(ws.PathParameter("user", "username")).
|
||||
Returns(http.StatusOK, ok, models.User{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.IdentityManagementTag}))
|
||||
ws.Route(ws.POST("/users").
|
||||
To(iam.CreateUser).
|
||||
Doc("Create a user account.").
|
||||
Reads(CreateUserRequest{}).
|
||||
Returns(http.StatusOK, ok, errors.Error{}).
|
||||
Returns(http.StatusOK, api.StatusOK, iam2.User{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.IdentityManagementTag}))
|
||||
|
||||
ws.Route(ws.DELETE("/users/{user}").
|
||||
To(iam.DeleteUser).
|
||||
Doc("Delete the specified user.").
|
||||
Param(ws.PathParameter("user", "username")).
|
||||
Returns(http.StatusOK, ok, errors.Error{}).
|
||||
Returns(http.StatusOK, api.StatusOK, errors.Error{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.IdentityManagementTag}))
|
||||
ws.Route(ws.PUT("/users/{user}").
|
||||
To(iam.UpdateUser).
|
||||
Doc("Update information about the specified user.").
|
||||
Param(ws.PathParameter("user", "username")).
|
||||
Reads(UserUpdateRequest{}).
|
||||
Returns(http.StatusOK, ok, errors.Error{}).
|
||||
Returns(http.StatusOK, api.StatusOK, errors.Error{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.IdentityManagementTag}))
|
||||
ws.Route(ws.GET("/users/{user}/logs").
|
||||
To(iam.UserLoginLogs).
|
||||
Doc("Retrieve the \"login logs\" for the specified user.").
|
||||
Param(ws.PathParameter("user", "username")).
|
||||
Returns(http.StatusOK, ok, LoginLog{}).
|
||||
Returns(http.StatusOK, api.StatusOK, LoginLog{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.IdentityManagementTag}))
|
||||
ws.Route(ws.GET("/users").
|
||||
To(iam.ListUsers).
|
||||
Doc("List all users.").
|
||||
Returns(http.StatusOK, ok, UserList{}).
|
||||
Returns(http.StatusOK, api.StatusOK, UserList{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.IdentityManagementTag}))
|
||||
ws.Route(ws.GET("/users/{user}/roles").
|
||||
To(iam.ListUserRoles).
|
||||
Doc("Retrieve all the roles that are assigned to the specified user.").
|
||||
Param(ws.PathParameter("user", "username")).
|
||||
Returns(http.StatusOK, ok, iam.RoleList{}).
|
||||
Returns(http.StatusOK, api.StatusOK, iam.RoleList{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/roles").
|
||||
To(iam.ListRoles).
|
||||
Doc("Retrieve the roles that are assigned to the user in the specified namespace.").
|
||||
Param(ws.PathParameter("namespace", "kubernetes namespace")).
|
||||
Returns(http.StatusOK, ok, RoleList{}).
|
||||
Returns(http.StatusOK, api.StatusOK, RoleList{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
ws.Route(ws.GET("/clusterroles").
|
||||
To(iam.ListClusterRoles).
|
||||
Doc("List all cluster roles.").
|
||||
Returns(http.StatusOK, ok, ClusterRoleList{}).
|
||||
Returns(http.StatusOK, api.StatusOK, ClusterRoleList{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/roles/{role}/users").
|
||||
To(iam.ListRoleUsers).
|
||||
To(handler.ListRoleUsers).
|
||||
Doc("Retrieve the users that are bound to the role in the specified namespace.").
|
||||
Param(ws.PathParameter("namespace", "kubernetes namespace")).
|
||||
Param(ws.PathParameter("role", "role name")).
|
||||
Returns(http.StatusOK, ok, []NamespacedUser{}).
|
||||
Returns(http.StatusOK, api.StatusOK, []NamespacedUser{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/users").
|
||||
To(iam.ListNamespaceUsers).
|
||||
Doc("List all users in the specified namespace.").
|
||||
Param(ws.PathParameter("namespace", "kubernetes namespace")).
|
||||
Returns(http.StatusOK, ok, []NamespacedUser{}).
|
||||
Returns(http.StatusOK, api.StatusOK, []NamespacedUser{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
ws.Route(ws.GET("/clusterroles/{clusterrole}/users").
|
||||
To(iam.ListClusterRoleUsers).
|
||||
Doc("List all users that are bound to the specified cluster role.").
|
||||
Param(ws.PathParameter("clusterrole", "cluster role name")).
|
||||
Returns(http.StatusOK, ok, UserList{}).
|
||||
Returns(http.StatusOK, api.StatusOK, UserList{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
ws.Route(ws.GET("/clusterroles/{clusterrole}/rules").
|
||||
To(iam.ListClusterRoleRules).
|
||||
Doc("List all policy rules of the specified cluster role.").
|
||||
Param(ws.PathParameter("clusterrole", "cluster role name")).
|
||||
Returns(http.StatusOK, ok, []models.SimpleRule{}).
|
||||
Returns(http.StatusOK, api.StatusOK, []iam2.SimpleRule{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/roles/{role}/rules").
|
||||
To(iam.ListRoleRules).
|
||||
Doc("List all policy rules of the specified role in the given namespace.").
|
||||
Param(ws.PathParameter("namespace", "kubernetes namespace")).
|
||||
Param(ws.PathParameter("role", "role name")).
|
||||
Returns(http.StatusOK, ok, []models.SimpleRule{}).
|
||||
Returns(http.StatusOK, api.StatusOK, []iam2.SimpleRule{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
ws.Route(ws.GET("/devops/{devops}/roles/{role}/rules").
|
||||
To(iam.ListDevopsRoleRules).
|
||||
Doc("List all policy rules of the specified role in the given devops project.").
|
||||
Param(ws.PathParameter("devops", "devops project ID")).
|
||||
Param(ws.PathParameter("role", "devops role name")).
|
||||
Returns(http.StatusOK, ok, []models.SimpleRule{}).
|
||||
Returns(http.StatusOK, api.StatusOK, []iam2.SimpleRule{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
ws.Route(ws.GET("/rulesmapping/clusterroles").
|
||||
To(iam.ClusterRulesMapping).
|
||||
Doc("Get the mapping relationships between cluster roles and policy rules.").
|
||||
Returns(http.StatusOK, ok, policy.ClusterRoleRuleMapping).
|
||||
Returns(http.StatusOK, api.StatusOK, policy.ClusterRoleRuleMapping).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
ws.Route(ws.GET("/rulesmapping/roles").
|
||||
To(iam.RulesMapping).
|
||||
Doc("Get the mapping relationships between namespaced roles and policy rules.").
|
||||
Returns(http.StatusOK, ok, policy.RoleRuleMapping).
|
||||
Returns(http.StatusOK, api.StatusOK, policy.RoleRuleMapping).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
ws.Route(ws.GET("/workspaces/{workspace}/roles").
|
||||
To(iam.ListWorkspaceRoles).
|
||||
Doc("List all workspace roles.").
|
||||
Param(ws.PathParameter("workspace", "workspace name")).
|
||||
Returns(http.StatusOK, ok, ClusterRoleList{}).
|
||||
Returns(http.StatusOK, api.StatusOK, ClusterRoleList{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
ws.Route(ws.GET("/workspaces/{workspace}/roles/{role}").
|
||||
To(iam.DescribeWorkspaceRole).
|
||||
Doc("Describe the workspace role.").
|
||||
Param(ws.PathParameter("workspace", "workspace name")).
|
||||
Param(ws.PathParameter("role", "workspace role name")).
|
||||
Returns(http.StatusOK, ok, rbacv1.ClusterRole{}).
|
||||
Returns(http.StatusOK, api.StatusOK, rbacv1.ClusterRole{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
ws.Route(ws.GET("/workspaces/{workspace}/roles/{role}/rules").
|
||||
To(iam.ListWorkspaceRoleRules).
|
||||
Doc("List all policy rules of the specified workspace role.").
|
||||
Param(ws.PathParameter("workspace", "workspace name")).
|
||||
Param(ws.PathParameter("role", "workspace role name")).
|
||||
Returns(http.StatusOK, ok, []models.SimpleRule{}).
|
||||
Returns(http.StatusOK, api.StatusOK, []iam2.SimpleRule{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
ws.Route(ws.GET("/workspaces/{workspace}/members").
|
||||
To(iam.ListWorkspaceUsers).
|
||||
Doc("List all members in the specified workspace.").
|
||||
Param(ws.PathParameter("workspace", "workspace name")).
|
||||
Returns(http.StatusOK, ok, UserList{}).
|
||||
Returns(http.StatusOK, api.StatusOK, UserList{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
ws.Route(ws.POST("/workspaces/{workspace}/members").
|
||||
To(iam.InviteUser).
|
||||
Doc("Invite a member to the specified workspace.").
|
||||
Param(ws.PathParameter("workspace", "workspace name")).
|
||||
Reads(InviteUserRequest{}).
|
||||
Returns(http.StatusOK, ok, errors.Error{}).
|
||||
Returns(http.StatusOK, api.StatusOK, errors.Error{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
ws.Route(ws.DELETE("/workspaces/{workspace}/members/{member}").
|
||||
To(iam.RemoveUser).
|
||||
Doc("Remove the specified member from the workspace.").
|
||||
Param(ws.PathParameter("workspace", "workspace name")).
|
||||
Param(ws.PathParameter("member", "username")).
|
||||
Returns(http.StatusOK, ok, errors.Error{}).
|
||||
Returns(http.StatusOK, api.StatusOK, errors.Error{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
ws.Route(ws.GET("/workspaces/{workspace}/members/{member}").
|
||||
To(iam.DescribeWorkspaceUser).
|
||||
Doc("Describe the specified user in the given workspace.").
|
||||
Param(ws.PathParameter("workspace", "workspace name")).
|
||||
Param(ws.PathParameter("member", "username")).
|
||||
Returns(http.StatusOK, ok, DescribeWorkspaceUserResponse{}).
|
||||
Returns(http.StatusOK, api.StatusOK, DescribeWorkspaceUserResponse{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
c.Add(ws)
|
||||
return nil
|
||||
|
||||
@@ -26,6 +26,7 @@ func InstallAPIs(container *restful.Container, client k8s.Client) {
|
||||
urlruntime.Must(resourcesv1alpha2.AddToContainer(container, client))
|
||||
urlruntime.Must(tenantv1alpha2.AddToContainer(container))
|
||||
urlruntime.Must(terminalv1alpha2.AddToContainer(container))
|
||||
urlruntime.Must(tenantv1alpha2.AddToContainer(container))
|
||||
}
|
||||
|
||||
func InstallAuthorizationAPIs(container *restful.Container) {
|
||||
|
||||
@@ -1,18 +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 operations contains operations API versions
|
||||
package openpitrix
|
||||
@@ -1,33 +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 install
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
urlruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
||||
"kubesphere.io/kubesphere/pkg/kapis/openpitrix/v1"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Install(runtime.Container)
|
||||
}
|
||||
|
||||
func Install(container *restful.Container) {
|
||||
urlruntime.Must(v1.AddToContainer(container))
|
||||
}
|
||||
@@ -1,76 +1,925 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/emicklei/go-restful"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/klog"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
k8sinformers "k8s.io/client-go/informers"
|
||||
"kubesphere.io/kubesphere/pkg/api"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"kubesphere.io/kubesphere/pkg/models/openpitrix/application"
|
||||
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/resource"
|
||||
"kubesphere.io/kubesphere/pkg/models/openpitrix"
|
||||
"kubesphere.io/kubesphere/pkg/server/errors"
|
||||
"kubesphere.io/kubesphere/pkg/server/params"
|
||||
"openpitrix.io/openpitrix/pkg/pb"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
|
||||
op "kubesphere.io/kubesphere/pkg/simple/client/openpitrix"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type openpitrixHandler struct {
|
||||
namespacesGetter *resource.NamespacedResourceGetter
|
||||
applicationOperator application.Interface
|
||||
openpitrix openpitrix.Interface
|
||||
informers k8sinformers.SharedInformerFactory
|
||||
}
|
||||
|
||||
func newOpenpitrixHandler(factory informers.InformerFactory, client pb.ClusterManagerClient) *openpitrixHandler {
|
||||
func newOpenpitrixHandler(k8sClient k8s.Client, opClient op.Client) *openpitrixHandler {
|
||||
|
||||
factory := informers.NewInformerFactories(k8sClient.Kubernetes(), k8sClient.KubeSphere(), k8sClient.S2i(), k8sClient.Application())
|
||||
|
||||
return &openpitrixHandler{
|
||||
namespacesGetter: resource.New(factory),
|
||||
applicationOperator: application.NewApplicaitonOperator(factory.KubernetesSharedInformerFactory(), client),
|
||||
openpitrix: openpitrix.NewOpenpitrixOperator(factory.KubernetesSharedInformerFactory(), opClient),
|
||||
informers: factory.KubernetesSharedInformerFactory(),
|
||||
}
|
||||
}
|
||||
|
||||
func (h *openpitrixHandler) handleListApplications(request *restful.Request, response *restful.Response) {
|
||||
limit, offset := params.ParsePaging(request.QueryParameter(params.PagingParam))
|
||||
namespaceName := request.PathParameter("namespace")
|
||||
conditions, err := params.ParseConditions(request.QueryParameter(params.ConditionsParam))
|
||||
orderBy := request.QueryParameter(params.OrderByParam)
|
||||
reverse := params.ParseReverse(request)
|
||||
|
||||
if orderBy == "" {
|
||||
orderBy = "create_time"
|
||||
reverse = true
|
||||
}
|
||||
func (h *openpitrixHandler) ListApplications(request *restful.Request, response *restful.Response) {
|
||||
limit, offset := params.ParsePaging(request)
|
||||
namespace := request.PathParameter("namespace")
|
||||
orderBy := params.GetStringValueWithDefault(request, params.OrderByParam, openpitrix.CreateTime)
|
||||
reverse := params.GetBoolValueWithDefault(request, params.ReverseParam, true)
|
||||
conditions, err := params.ParseConditions(request)
|
||||
|
||||
if err != nil {
|
||||
api.HandleBadRequest(response, err)
|
||||
return
|
||||
}
|
||||
|
||||
if namespaceName != "" {
|
||||
namespace, err := h.namespacesGetter.Get(api.ResourceKindNamespace, "", namespaceName)
|
||||
// filter namespaced applications by runtime_id
|
||||
if namespace != "" {
|
||||
ns, err := h.informers.Core().V1().Namespaces().Lister().Get(namespace)
|
||||
|
||||
if err != nil {
|
||||
api.HandleInternalError(response, err)
|
||||
return
|
||||
}
|
||||
var runtimeId string
|
||||
|
||||
if ns, ok := namespace.(*v1.Namespace); ok {
|
||||
runtimeId = ns.Annotations[constants.OpenPitrixRuntimeAnnotationKey]
|
||||
}
|
||||
runtimeId := ns.Annotations[constants.OpenPitrixRuntimeAnnotationKey]
|
||||
|
||||
if runtimeId == "" {
|
||||
// runtime id not exist,return empty response
|
||||
response.WriteAsJson(models.PageableResponse{Items: []interface{}{}, TotalCount: 0})
|
||||
return
|
||||
} else {
|
||||
conditions.Match["runtime_id"] = runtimeId
|
||||
// filter by runtime id
|
||||
conditions.Match[openpitrix.RuntimeId] = runtimeId
|
||||
}
|
||||
}
|
||||
|
||||
result, err := h.applicationOperator.List(conditions, limit, offset, orderBy, reverse)
|
||||
result, err := h.openpitrix.ListApplications(conditions, limit, offset, orderBy, reverse)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(response, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(result)
|
||||
response.WriteAsJson(result)
|
||||
}
|
||||
|
||||
func (h *openpitrixHandler) DescribeApplication(req *restful.Request, resp *restful.Response) {
|
||||
clusterId := req.PathParameter("application")
|
||||
namespace := req.PathParameter("namespace")
|
||||
|
||||
app, err := h.openpitrix.DescribeApplication(namespace, clusterId)
|
||||
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.NotFound {
|
||||
api.HandleNotFound(resp, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
ns, err := h.informers.Core().V1().Namespaces().Lister().Get(namespace)
|
||||
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
runtimeId := ns.Annotations[constants.OpenPitrixRuntimeAnnotationKey]
|
||||
|
||||
if runtimeId != app.Cluster.RuntimeId {
|
||||
err = fmt.Errorf("rumtime not match %s,%s", app.Cluster.RuntimeId, runtimeId)
|
||||
api.HandleForbidden(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(app)
|
||||
return
|
||||
}
|
||||
|
||||
func (h *openpitrixHandler) CreateApplication(req *restful.Request, resp *restful.Response) {
|
||||
namespace := req.PathParameter("namespace")
|
||||
var createClusterRequest openpitrix.CreateClusterRequest
|
||||
err := req.ReadEntity(&createClusterRequest)
|
||||
if err != nil {
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
createClusterRequest.Username = req.HeaderParameter(constants.UserNameHeader)
|
||||
|
||||
err = h.openpitrix.CreateApplication(namespace, createClusterRequest)
|
||||
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(errors.None)
|
||||
}
|
||||
|
||||
func (h *openpitrixHandler) ModifyApplication(req *restful.Request, resp *restful.Response) {
|
||||
var modifyClusterAttributesRequest openpitrix.ModifyClusterAttributesRequest
|
||||
clusterId := req.PathParameter("application")
|
||||
namespace := req.PathParameter("namespace")
|
||||
err := req.ReadEntity(&modifyClusterAttributesRequest)
|
||||
if err != nil {
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
app, err := h.openpitrix.DescribeApplication(namespace, clusterId)
|
||||
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.NotFound {
|
||||
api.HandleNotFound(resp, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
ns, err := h.informers.Core().V1().Namespaces().Lister().Get(namespace)
|
||||
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
runtimeId := ns.Annotations[constants.OpenPitrixRuntimeAnnotationKey]
|
||||
|
||||
if runtimeId != app.Cluster.RuntimeId {
|
||||
err = fmt.Errorf("rumtime not match %s,%s", app.Cluster.RuntimeId, runtimeId)
|
||||
api.HandleForbidden(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = h.openpitrix.ModifyApplication(modifyClusterAttributesRequest)
|
||||
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.NotFound {
|
||||
api.HandleNotFound(resp, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(errors.None)
|
||||
}
|
||||
|
||||
func (h *openpitrixHandler) DeleteApplication(req *restful.Request, resp *restful.Response) {
|
||||
clusterId := req.PathParameter("application")
|
||||
namespace := req.PathParameter("namespace")
|
||||
app, err := h.openpitrix.DescribeApplication(namespace, clusterId)
|
||||
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.NotFound {
|
||||
api.HandleNotFound(resp, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
ns, err := h.informers.Core().V1().Namespaces().Lister().Get(namespace)
|
||||
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
runtimeId := ns.Annotations[constants.OpenPitrixRuntimeAnnotationKey]
|
||||
|
||||
if runtimeId != app.Cluster.RuntimeId {
|
||||
err = fmt.Errorf("rumtime not match %s,%s", app.Cluster.RuntimeId, runtimeId)
|
||||
api.HandleForbidden(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = h.openpitrix.DeleteApplication(clusterId)
|
||||
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.NotFound {
|
||||
api.HandleNotFound(resp, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(errors.None)
|
||||
}
|
||||
|
||||
func (h *openpitrixHandler) GetAppVersionPackage(req *restful.Request, resp *restful.Response) {
|
||||
appId := req.PathParameter("app")
|
||||
versionId := req.PathParameter("version")
|
||||
|
||||
result, err := h.openpitrix.GetAppVersionPackage(appId, versionId)
|
||||
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func (h *openpitrixHandler) DoAppAction(req *restful.Request, resp *restful.Response) {
|
||||
var doActionRequest openpitrix.ActionRequest
|
||||
err := req.ReadEntity(&doActionRequest)
|
||||
if err != nil {
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
appId := req.PathParameter("app")
|
||||
|
||||
err = h.openpitrix.DoAppAction(appId, &doActionRequest)
|
||||
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.NotFound {
|
||||
api.HandleNotFound(resp, err)
|
||||
return
|
||||
}
|
||||
if status.Code(err) == codes.InvalidArgument {
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(errors.None)
|
||||
}
|
||||
|
||||
func (h *openpitrixHandler) DoAppVersionAction(req *restful.Request, resp *restful.Response) {
|
||||
var doActionRequest openpitrix.ActionRequest
|
||||
err := req.ReadEntity(&doActionRequest)
|
||||
if err != nil {
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
doActionRequest.Username = req.HeaderParameter(constants.UserNameHeader)
|
||||
|
||||
versionId := req.PathParameter("version")
|
||||
|
||||
err = h.openpitrix.DoAppVersionAction(versionId, &doActionRequest)
|
||||
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.NotFound {
|
||||
api.HandleNotFound(resp, err)
|
||||
return
|
||||
}
|
||||
if status.Code(err) == codes.InvalidArgument {
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(errors.None)
|
||||
}
|
||||
|
||||
func (h *openpitrixHandler) GetAppVersionFiles(req *restful.Request, resp *restful.Response) {
|
||||
versionId := req.PathParameter("version")
|
||||
getAppVersionFilesRequest := &openpitrix.GetAppVersionFilesRequest{}
|
||||
if f := req.QueryParameter("files"); f != "" {
|
||||
getAppVersionFilesRequest.Files = strings.Split(f, ",")
|
||||
}
|
||||
|
||||
result, err := h.openpitrix.GetAppVersionFiles(versionId, getAppVersionFilesRequest)
|
||||
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.NotFound {
|
||||
api.HandleNotFound(resp, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func (h *openpitrixHandler) ListAppVersionAudits(req *restful.Request, resp *restful.Response) {
|
||||
limit, offset := params.ParsePaging(req)
|
||||
orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, openpitrix.StatusTime)
|
||||
reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, true)
|
||||
appId := req.PathParameter("app")
|
||||
versionId := req.PathParameter("version")
|
||||
conditions, err := params.ParseConditions(req)
|
||||
|
||||
if err != nil {
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
conditions.Match[openpitrix.AppId] = appId
|
||||
if versionId != "" {
|
||||
conditions.Match[openpitrix.VersionId] = versionId
|
||||
}
|
||||
|
||||
result, err := h.openpitrix.ListAppVersionAudits(conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func (h *openpitrixHandler) ListReviews(req *restful.Request, resp *restful.Response) {
|
||||
limit, offset := params.ParsePaging(req)
|
||||
orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, openpitrix.StatusTime)
|
||||
reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, true)
|
||||
conditions, err := params.ParseConditions(req)
|
||||
|
||||
if err != nil {
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.openpitrix.ListAppVersionReviews(conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func (h *openpitrixHandler) ListAppVersions(req *restful.Request, resp *restful.Response) {
|
||||
limit, offset := params.ParsePaging(req)
|
||||
orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, openpitrix.CreateTime)
|
||||
reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, true)
|
||||
appId := req.PathParameter("app")
|
||||
statistics := params.GetBoolValueWithDefault(req, "statistics", false)
|
||||
conditions, err := params.ParseConditions(req)
|
||||
|
||||
if err != nil {
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
conditions.Match[openpitrix.AppId] = appId
|
||||
|
||||
result, err := h.openpitrix.ListAppVersions(conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
if statistics {
|
||||
for _, item := range result.Items {
|
||||
if version, ok := item.(*openpitrix.AppVersion); ok {
|
||||
statisticsResult, err := h.openpitrix.ListApplications(¶ms.Conditions{Match: map[string]string{"app_id": version.AppId, "version_id": version.VersionId}}, 0, 0, "", false)
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
version.ClusterTotal = &statisticsResult.TotalCount
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func (h *openpitrixHandler) ListApps(req *restful.Request, resp *restful.Response) {
|
||||
limit, offset := params.ParsePaging(req)
|
||||
orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, openpitrix.CreateTime)
|
||||
reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, true)
|
||||
statistics := params.GetBoolValueWithDefault(req, "statistics", false)
|
||||
conditions, err := params.ParseConditions(req)
|
||||
|
||||
if err != nil {
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.openpitrix.ListApps(conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
if statistics {
|
||||
for _, item := range result.Items {
|
||||
if app, ok := item.(*openpitrix.App); ok {
|
||||
statuses := "active|used|enabled|stopped|pending|creating|upgrading|updating|rollbacking|stopping|starting|recovering|resizing|scaling|deleting"
|
||||
statisticsResult, err := h.openpitrix.ListApplications(¶ms.Conditions{Match: map[string]string{openpitrix.AppId: app.AppId, openpitrix.Status: statuses}}, 0, 0, "", false)
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
app.ClusterTotal = &statisticsResult.TotalCount
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func (h *openpitrixHandler) ModifyApp(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
var patchAppRequest openpitrix.ModifyAppRequest
|
||||
err := req.ReadEntity(&patchAppRequest)
|
||||
appId := req.PathParameter("app")
|
||||
|
||||
if err != nil {
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = h.openpitrix.ModifyApp(appId, &patchAppRequest)
|
||||
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.NotFound {
|
||||
api.HandleNotFound(resp, err)
|
||||
return
|
||||
}
|
||||
if status.Code(err) == codes.InvalidArgument {
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(errors.None)
|
||||
}
|
||||
|
||||
func (h *openpitrixHandler) DescribeApp(req *restful.Request, resp *restful.Response) {
|
||||
appId := req.PathParameter("app")
|
||||
|
||||
result, err := h.openpitrix.DescribeApp(appId)
|
||||
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.NotFound {
|
||||
api.HandleNotFound(resp, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func (h *openpitrixHandler) DeleteApp(req *restful.Request, resp *restful.Response) {
|
||||
appId := req.PathParameter("app")
|
||||
|
||||
err := h.openpitrix.DeleteApp(appId)
|
||||
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.NotFound {
|
||||
api.HandleNotFound(resp, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(errors.None)
|
||||
}
|
||||
|
||||
func (h *openpitrixHandler) CreateApp(req *restful.Request, resp *restful.Response) {
|
||||
createAppRequest := &openpitrix.CreateAppRequest{}
|
||||
err := req.ReadEntity(createAppRequest)
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
createAppRequest.Username = req.HeaderParameter(constants.UserNameHeader)
|
||||
|
||||
validate, _ := strconv.ParseBool(req.QueryParameter("validate"))
|
||||
|
||||
var result interface{}
|
||||
|
||||
if validate {
|
||||
validatePackageRequest := &openpitrix.ValidatePackageRequest{
|
||||
VersionPackage: createAppRequest.VersionPackage,
|
||||
VersionType: createAppRequest.VersionType,
|
||||
}
|
||||
result, err = h.openpitrix.ValidatePackage(validatePackageRequest)
|
||||
} else {
|
||||
result, err = h.openpitrix.CreateApp(createAppRequest)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.InvalidArgument {
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func (h *openpitrixHandler) CreateAppVersion(req *restful.Request, resp *restful.Response) {
|
||||
var createAppVersionRequest openpitrix.CreateAppVersionRequest
|
||||
err := req.ReadEntity(&createAppVersionRequest)
|
||||
if err != nil {
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
// override app id
|
||||
createAppVersionRequest.AppId = req.PathParameter("app")
|
||||
createAppVersionRequest.Username = req.HeaderParameter(constants.UserNameHeader)
|
||||
|
||||
validate, _ := strconv.ParseBool(req.QueryParameter("validate"))
|
||||
|
||||
var result interface{}
|
||||
|
||||
if validate {
|
||||
validatePackageRequest := &openpitrix.ValidatePackageRequest{
|
||||
VersionPackage: createAppVersionRequest.Package,
|
||||
VersionType: createAppVersionRequest.Type,
|
||||
}
|
||||
result, err = h.openpitrix.ValidatePackage(validatePackageRequest)
|
||||
} else {
|
||||
result, err = h.openpitrix.CreateAppVersion(&createAppVersionRequest)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.InvalidArgument {
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func (h *openpitrixHandler) ModifyAppVersion(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
var patchAppVersionRequest openpitrix.ModifyAppVersionRequest
|
||||
err := req.ReadEntity(&patchAppVersionRequest)
|
||||
versionId := req.PathParameter("version")
|
||||
|
||||
if err != nil {
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = h.openpitrix.ModifyAppVersion(versionId, &patchAppVersionRequest)
|
||||
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.InvalidArgument {
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(errors.None)
|
||||
}
|
||||
|
||||
func (h *openpitrixHandler) DeleteAppVersion(req *restful.Request, resp *restful.Response) {
|
||||
versionId := req.PathParameter("version")
|
||||
|
||||
err := h.openpitrix.DeleteAppVersion(versionId)
|
||||
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.NotFound {
|
||||
api.HandleNotFound(resp, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(errors.None)
|
||||
}
|
||||
|
||||
func (h *openpitrixHandler) DescribeAppVersion(req *restful.Request, resp *restful.Response) {
|
||||
versionId := req.PathParameter("version")
|
||||
|
||||
result, err := h.openpitrix.DescribeAppVersion(versionId)
|
||||
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.NotFound {
|
||||
api.HandleNotFound(resp, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func (h *openpitrixHandler) DescribeAttachment(req *restful.Request, resp *restful.Response) {
|
||||
attachmentId := req.PathParameter("attachment")
|
||||
fileName := req.QueryParameter("filename")
|
||||
result, err := h.openpitrix.DescribeAttachment(attachmentId)
|
||||
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.NotFound {
|
||||
api.HandleNotFound(resp, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
// file raw
|
||||
if fileName != "" {
|
||||
data := result.AttachmentContent[fileName]
|
||||
resp.Write(data)
|
||||
resp.Header().Set("Content-Type", "text/plain")
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func (h *openpitrixHandler) CreateCategory(req *restful.Request, resp *restful.Response) {
|
||||
createCategoryRequest := &openpitrix.CreateCategoryRequest{}
|
||||
err := req.ReadEntity(createCategoryRequest)
|
||||
if err != nil {
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.openpitrix.CreateCategory(createCategoryRequest)
|
||||
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.InvalidArgument {
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
func (h *openpitrixHandler) DeleteCategory(req *restful.Request, resp *restful.Response) {
|
||||
categoryId := req.PathParameter("category")
|
||||
|
||||
err := h.openpitrix.DeleteCategory(categoryId)
|
||||
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.NotFound {
|
||||
api.HandleNotFound(resp, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(errors.None)
|
||||
}
|
||||
func (h *openpitrixHandler) ModifyCategory(req *restful.Request, resp *restful.Response) {
|
||||
var modifyCategoryRequest openpitrix.ModifyCategoryRequest
|
||||
categoryId := req.PathParameter("category")
|
||||
err := req.ReadEntity(&modifyCategoryRequest)
|
||||
if err != nil {
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = h.openpitrix.ModifyCategory(categoryId, &modifyCategoryRequest)
|
||||
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.InvalidArgument {
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(errors.None)
|
||||
}
|
||||
func (h *openpitrixHandler) DescribeCategory(req *restful.Request, resp *restful.Response) {
|
||||
categoryId := req.PathParameter("category")
|
||||
|
||||
result, err := h.openpitrix.DescribeCategory(categoryId)
|
||||
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.NotFound {
|
||||
api.HandleNotFound(resp, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
func (h *openpitrixHandler) ListCategories(req *restful.Request, resp *restful.Response) {
|
||||
limit, offset := params.ParsePaging(req)
|
||||
orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, openpitrix.CreateTime)
|
||||
reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, true)
|
||||
statistics := params.GetBoolValueWithDefault(req, "statistics", false)
|
||||
conditions, err := params.ParseConditions(req)
|
||||
|
||||
if err != nil {
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.openpitrix.ListCategories(conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
if statistics {
|
||||
for _, item := range result.Items {
|
||||
if category, ok := item.(*openpitrix.Category); ok {
|
||||
statisticsResult, err := h.openpitrix.ListApps(¶ms.Conditions{Match: map[string]string{"category_id": category.CategoryID, "status": openpitrix.StatusActive, "repo": openpitrix.BuiltinRepoId}}, "", false, 0, 0)
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
category.AppTotal = &statisticsResult.TotalCount
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func (h *openpitrixHandler) CreateRepo(req *restful.Request, resp *restful.Response) {
|
||||
createRepoRequest := &openpitrix.CreateRepoRequest{}
|
||||
err := req.ReadEntity(createRepoRequest)
|
||||
if err != nil {
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
validate, _ := strconv.ParseBool(req.QueryParameter("validate"))
|
||||
|
||||
var result interface{}
|
||||
|
||||
if validate {
|
||||
validateRepoRequest := &openpitrix.ValidateRepoRequest{
|
||||
Type: createRepoRequest.Type,
|
||||
Url: createRepoRequest.URL,
|
||||
Credential: createRepoRequest.Credential,
|
||||
}
|
||||
result, err = h.openpitrix.ValidateRepo(validateRepoRequest)
|
||||
} else {
|
||||
result, err = h.openpitrix.CreateRepo(createRepoRequest)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.InvalidArgument {
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func (h *openpitrixHandler) DoRepoAction(req *restful.Request, resp *restful.Response) {
|
||||
repoActionRequest := &openpitrix.RepoActionRequest{}
|
||||
repoId := req.PathParameter("repo")
|
||||
err := req.ReadEntity(repoActionRequest)
|
||||
if err != nil {
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = h.openpitrix.DoRepoAction(repoId, repoActionRequest)
|
||||
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.InvalidArgument {
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(errors.None)
|
||||
}
|
||||
|
||||
func (h *openpitrixHandler) DeleteRepo(req *restful.Request, resp *restful.Response) {
|
||||
repoId := req.PathParameter("repo")
|
||||
|
||||
err := h.openpitrix.DeleteRepo(repoId)
|
||||
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.NotFound {
|
||||
api.HandleNotFound(resp, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(errors.None)
|
||||
}
|
||||
|
||||
func (h *openpitrixHandler) ModifyRepo(req *restful.Request, resp *restful.Response) {
|
||||
var updateRepoRequest openpitrix.ModifyRepoRequest
|
||||
repoId := req.PathParameter("repo")
|
||||
err := req.ReadEntity(&updateRepoRequest)
|
||||
if err != nil {
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = h.openpitrix.ModifyRepo(repoId, &updateRepoRequest)
|
||||
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.InvalidArgument {
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(errors.None)
|
||||
}
|
||||
|
||||
func (h *openpitrixHandler) DescribeRepo(req *restful.Request, resp *restful.Response) {
|
||||
repoId := req.PathParameter("repo")
|
||||
|
||||
result, err := h.openpitrix.DescribeRepo(repoId)
|
||||
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.NotFound {
|
||||
api.HandleNotFound(resp, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
func (h *openpitrixHandler) ListRepos(req *restful.Request, resp *restful.Response) {
|
||||
limit, offset := params.ParsePaging(req)
|
||||
orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, openpitrix.CreateTime)
|
||||
reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, true)
|
||||
conditions, err := params.ParseConditions(req)
|
||||
|
||||
if err != nil {
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.openpitrix.ListRepos(conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func (h *openpitrixHandler) ListRepoEvents(req *restful.Request, resp *restful.Response) {
|
||||
repoId := req.PathParameter("repo")
|
||||
limit, offset := params.ParsePaging(req)
|
||||
conditions, err := params.ParseConditions(req)
|
||||
|
||||
if err != nil {
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.openpitrix.ListRepoEvents(repoId, conditions, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
@@ -21,35 +21,33 @@ import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"github.com/emicklei/go-restful-openapi"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/openpitrix"
|
||||
"kubesphere.io/kubesphere/pkg/api"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"kubesphere.io/kubesphere/pkg/models/openpitrix/application"
|
||||
"kubesphere.io/kubesphere/pkg/models/openpitrix/type"
|
||||
openpitrix2 "kubesphere.io/kubesphere/pkg/models/openpitrix"
|
||||
"kubesphere.io/kubesphere/pkg/server/errors"
|
||||
"kubesphere.io/kubesphere/pkg/server/params"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
|
||||
op "kubesphere.io/kubesphere/pkg/simple/client/openpitrix"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
const GroupName = "openpitrix.io"
|
||||
const (
|
||||
GroupName = "openpitrix.io"
|
||||
)
|
||||
|
||||
var GroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1"}
|
||||
|
||||
var (
|
||||
WebServiceBuilder = runtime.NewContainerBuilder(addWebService)
|
||||
AddToContainer = WebServiceBuilder.AddToContainer
|
||||
)
|
||||
func AddToContainer(c *restful.Container, k8s k8s.Client, op op.Client) error {
|
||||
|
||||
func addWebService(c *restful.Container) error {
|
||||
|
||||
ok := "ok"
|
||||
mimePatch := []string{restful.MIME_JSON, runtime.MimeMergePatchJson, runtime.MimeJsonPatchJson}
|
||||
webservice := runtime.NewWebService(GroupVersion)
|
||||
handler := newOpenpitrixHandler(k8s, op)
|
||||
|
||||
webservice.Route(webservice.GET("/applications").
|
||||
To(openpitrix.ListApplications).
|
||||
Returns(http.StatusOK, ok, models.PageableResponse{}).
|
||||
To(handler.ListApplications).
|
||||
Returns(http.StatusOK, api.StatusOK, models.PageableResponse{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.NamespaceResourcesTag}).
|
||||
Doc("List all applications").
|
||||
Param(webservice.QueryParameter(params.ConditionsParam, "query conditions, connect multiple conditions with commas, equal symbol for exact query, wave symbol for fuzzy query e.g. name~a").
|
||||
@@ -63,8 +61,8 @@ func addWebService(c *restful.Container) error {
|
||||
DefaultValue("limit=10,page=1")))
|
||||
|
||||
webservice.Route(webservice.GET("/namespaces/{namespace}/applications").
|
||||
To(openpitrix.ListApplications).
|
||||
Returns(http.StatusOK, ok, models.PageableResponse{}).
|
||||
To(handler.ListApplications).
|
||||
Returns(http.StatusOK, api.StatusOK, models.PageableResponse{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.NamespaceResourcesTag}).
|
||||
Doc("List all applications within the specified namespace").
|
||||
Param(webservice.QueryParameter(params.ConditionsParam, "query conditions, connect multiple conditions with commas, equal symbol for exact query, wave symbol for fuzzy query e.g. name~a").
|
||||
@@ -78,72 +76,72 @@ func addWebService(c *restful.Container) error {
|
||||
DefaultValue("limit=10,page=1")))
|
||||
|
||||
webservice.Route(webservice.GET("/namespaces/{namespace}/applications/{application}").
|
||||
To(openpitrix.DescribeApplication).
|
||||
Returns(http.StatusOK, ok, application.Application{}).
|
||||
To(handler.DescribeApplication).
|
||||
Returns(http.StatusOK, api.StatusOK, openpitrix2.Application{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.NamespaceResourcesTag}).
|
||||
Doc("Describe the specified application of the namespace").
|
||||
Param(webservice.PathParameter("namespace", "the name of the project")).
|
||||
Param(webservice.PathParameter("application", "application ID")))
|
||||
|
||||
webservice.Route(webservice.POST("/namespaces/{namespace}/applications").
|
||||
To(openpitrix.CreateApplication).
|
||||
To(handler.CreateApplication).
|
||||
Doc("Deploy a new application").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.NamespaceResourcesTag}).
|
||||
Reads(types.CreateClusterRequest{}).
|
||||
Returns(http.StatusOK, ok, errors.Error{}).
|
||||
Reads(openpitrix2.CreateClusterRequest{}).
|
||||
Returns(http.StatusOK, api.StatusOK, errors.Error{}).
|
||||
Param(webservice.PathParameter("namespace", "the name of the project")))
|
||||
|
||||
webservice.Route(webservice.PATCH("/namespaces/{namespace}/applications/{application}").
|
||||
Consumes(mimePatch...).
|
||||
To(openpitrix.ModifyApplication).
|
||||
To(handler.ModifyApplication).
|
||||
Doc("Modify application").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.NamespaceResourcesTag}).
|
||||
Reads(types.ModifyClusterAttributesRequest{}).
|
||||
Returns(http.StatusOK, ok, errors.Error{}).
|
||||
Reads(openpitrix2.ModifyClusterAttributesRequest{}).
|
||||
Returns(http.StatusOK, api.StatusOK, errors.Error{}).
|
||||
Param(webservice.PathParameter("namespace", "the name of the project")).
|
||||
Param(webservice.PathParameter("application", "the id of the application cluster")))
|
||||
|
||||
webservice.Route(webservice.DELETE("/namespaces/{namespace}/applications/{application}").
|
||||
To(openpitrix.DeleteApplication).
|
||||
To(handler.DeleteApplication).
|
||||
Doc("Delete the specified application").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.NamespaceResourcesTag}).
|
||||
Returns(http.StatusOK, ok, errors.Error{}).
|
||||
Returns(http.StatusOK, api.StatusOK, errors.Error{}).
|
||||
Param(webservice.PathParameter("namespace", "the name of the project")).
|
||||
Param(webservice.PathParameter("application", "the id of the application cluster")))
|
||||
|
||||
webservice.Route(webservice.POST("/apps/{app}/versions").
|
||||
To(openpitrix.CreateAppVersion).
|
||||
To(handler.CreateAppVersion).
|
||||
Doc("Create a new app template version").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}).
|
||||
Reads(types.CreateAppVersionRequest{}).
|
||||
Reads(openpitrix2.CreateAppVersionRequest{}).
|
||||
Param(webservice.QueryParameter("validate", "Validate format of package(pack by op tool)")).
|
||||
Returns(http.StatusOK, ok, types.CreateAppVersionResponse{}).
|
||||
Returns(http.StatusOK, api.StatusOK, openpitrix2.CreateAppVersionResponse{}).
|
||||
Param(webservice.PathParameter("app", "app template id")))
|
||||
webservice.Route(webservice.DELETE("/apps/{app}/versions/{version}").
|
||||
To(openpitrix.DeleteAppVersion).
|
||||
To(handler.DeleteAppVersion).
|
||||
Doc("Delete the specified app template version").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}).
|
||||
Returns(http.StatusOK, ok, errors.Error{}).
|
||||
Returns(http.StatusOK, api.StatusOK, errors.Error{}).
|
||||
Param(webservice.PathParameter("version", "app template version id")).
|
||||
Param(webservice.PathParameter("app", "app template id")))
|
||||
webservice.Route(webservice.PATCH("/apps/{app}/versions/{version}").
|
||||
Consumes(mimePatch...).
|
||||
To(openpitrix.ModifyAppVersion).
|
||||
To(handler.ModifyAppVersion).
|
||||
Doc("Patch the specified app template version").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}).
|
||||
Reads(types.ModifyAppVersionRequest{}).
|
||||
Returns(http.StatusOK, ok, errors.Error{}).
|
||||
Reads(openpitrix2.ModifyAppVersionRequest{}).
|
||||
Returns(http.StatusOK, api.StatusOK, errors.Error{}).
|
||||
Param(webservice.PathParameter("version", "app template version id")).
|
||||
Param(webservice.PathParameter("app", "app template id")))
|
||||
webservice.Route(webservice.GET("/apps/{app}/versions/{version}").
|
||||
To(openpitrix.DescribeAppVersion).
|
||||
To(handler.DescribeAppVersion).
|
||||
Doc("Describe the specified app template version").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}).
|
||||
Returns(http.StatusOK, ok, types.AppVersion{}).
|
||||
Returns(http.StatusOK, api.StatusOK, openpitrix2.AppVersion{}).
|
||||
Param(webservice.PathParameter("version", "app template version id")).
|
||||
Param(webservice.PathParameter("app", "app template id")))
|
||||
webservice.Route(webservice.GET("/apps/{app}/versions").
|
||||
To(openpitrix.ListAppVersions).
|
||||
To(handler.ListAppVersions).
|
||||
Doc("Get active versions of app, can filter with these fields(version_id, app_id, name, owner, description, package_name, status, type), default return all active app versions").
|
||||
Param(webservice.QueryParameter(params.ConditionsParam, "query conditions,connect multiple conditions with commas, equal symbol for exact query, wave symbol for fuzzy query e.g. name~a").
|
||||
Required(false).
|
||||
@@ -155,33 +153,33 @@ func addWebService(c *restful.Container) error {
|
||||
Param(webservice.PathParameter("app", "app template id")).
|
||||
Param(webservice.QueryParameter(params.ReverseParam, "sort parameters, e.g. reverse=true")).
|
||||
Param(webservice.QueryParameter(params.OrderByParam, "sort parameters, e.g. orderBy=createTime")).
|
||||
Returns(http.StatusOK, ok, models.PageableResponse{}))
|
||||
Returns(http.StatusOK, api.StatusOK, models.PageableResponse{}))
|
||||
webservice.Route(webservice.GET("/apps/{app}/versions/{version}/audits").
|
||||
To(openpitrix.ListAppVersionAudits).
|
||||
To(handler.ListAppVersionAudits).
|
||||
Doc("List audits information of version-specific app template").
|
||||
Returns(http.StatusOK, ok, types.AppVersionAudit{}).
|
||||
Returns(http.StatusOK, api.StatusOK, openpitrix2.AppVersionAudit{}).
|
||||
Param(webservice.PathParameter("version", "app template version id")).
|
||||
Param(webservice.PathParameter("app", "app template id")))
|
||||
webservice.Route(webservice.GET("/apps/{app}/versions/{version}/package").
|
||||
To(openpitrix.GetAppVersionPackage).
|
||||
To(handler.GetAppVersionPackage).
|
||||
Doc("Get packages of version-specific app").
|
||||
Returns(http.StatusOK, ok, types.GetAppVersionPackageResponse{}).
|
||||
Returns(http.StatusOK, api.StatusOK, openpitrix2.GetAppVersionPackageResponse{}).
|
||||
Param(webservice.PathParameter("version", "app template version id")).
|
||||
Param(webservice.PathParameter("app", "app template id")))
|
||||
webservice.Route(webservice.POST("/apps/{app}/versions/{version}/action").
|
||||
To(openpitrix.DoAppVersionAction).
|
||||
To(handler.DoAppVersionAction).
|
||||
Doc("Perform submit or other operations on app").
|
||||
Returns(http.StatusOK, ok, errors.Error{}).
|
||||
Returns(http.StatusOK, api.StatusOK, errors.Error{}).
|
||||
Param(webservice.PathParameter("version", "app template version id")).
|
||||
Param(webservice.PathParameter("app", "app template id")))
|
||||
webservice.Route(webservice.GET("/apps/{app}/versions/{version}/files").
|
||||
To(openpitrix.GetAppVersionFiles).
|
||||
To(handler.GetAppVersionFiles).
|
||||
Doc("Get app template package files").
|
||||
Returns(http.StatusOK, ok, types.GetAppVersionPackageFilesResponse{}).
|
||||
Returns(http.StatusOK, api.StatusOK, openpitrix2.GetAppVersionPackageFilesResponse{}).
|
||||
Param(webservice.PathParameter("version", "app template version id")).
|
||||
Param(webservice.PathParameter("app", "app template id")))
|
||||
webservice.Route(webservice.GET("/reviews").
|
||||
To(openpitrix.ListReviews).
|
||||
To(handler.ListReviews).
|
||||
Doc("Get reviews of version-specific app").
|
||||
Param(webservice.QueryParameter(params.ConditionsParam, "query conditions,connect multiple conditions with commas, equal symbol for exact query, wave symbol for fuzzy query e.g. name~a").
|
||||
Required(false).
|
||||
@@ -190,47 +188,47 @@ func addWebService(c *restful.Container) error {
|
||||
Required(false).
|
||||
DataFormat("limit=%d,page=%d").
|
||||
DefaultValue("limit=10,page=1")).
|
||||
Returns(http.StatusOK, ok, types.AppVersionReview{}))
|
||||
Returns(http.StatusOK, api.StatusOK, openpitrix2.AppVersionReview{}))
|
||||
webservice.Route(webservice.GET("/apps/{app}/audits").
|
||||
To(openpitrix.ListAppVersionAudits).
|
||||
To(handler.ListAppVersionAudits).
|
||||
Doc("List audits information of the specific app template").
|
||||
Param(webservice.PathParameter("app", "app template id")).
|
||||
Returns(http.StatusOK, ok, types.AppVersionAudit{}))
|
||||
Returns(http.StatusOK, api.StatusOK, openpitrix2.AppVersionAudit{}))
|
||||
webservice.Route(webservice.POST("/apps").
|
||||
To(openpitrix.CreateApp).
|
||||
To(handler.CreateApp).
|
||||
Doc("Create a new app template").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}).
|
||||
Returns(http.StatusOK, ok, types.CreateAppResponse{}).
|
||||
Reads(types.CreateAppRequest{}).
|
||||
Returns(http.StatusOK, api.StatusOK, openpitrix2.CreateAppResponse{}).
|
||||
Reads(openpitrix2.CreateAppRequest{}).
|
||||
Param(webservice.PathParameter("app", "app template id")))
|
||||
webservice.Route(webservice.DELETE("/apps/{app}").
|
||||
To(openpitrix.DeleteApp).
|
||||
To(handler.DeleteApp).
|
||||
Doc("Delete the specified app template").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}).
|
||||
Returns(http.StatusOK, ok, errors.Error{}).
|
||||
Returns(http.StatusOK, api.StatusOK, errors.Error{}).
|
||||
Param(webservice.PathParameter("app", "app template id")))
|
||||
webservice.Route(webservice.PATCH("/apps/{app}").
|
||||
Consumes(mimePatch...).
|
||||
To(openpitrix.ModifyApp).
|
||||
To(handler.ModifyApp).
|
||||
Doc("Patch the specified app template").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}).
|
||||
Reads(types.ModifyAppVersionRequest{}).
|
||||
Returns(http.StatusOK, ok, errors.Error{}).
|
||||
Reads(openpitrix2.ModifyAppVersionRequest{}).
|
||||
Returns(http.StatusOK, api.StatusOK, errors.Error{}).
|
||||
Param(webservice.PathParameter("app", "app template id")))
|
||||
webservice.Route(webservice.GET("/apps/{app}").
|
||||
To(openpitrix.DescribeApp).
|
||||
To(handler.DescribeApp).
|
||||
Doc("Describe the specified app template").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}).
|
||||
Returns(http.StatusOK, ok, types.AppVersion{}).
|
||||
Returns(http.StatusOK, api.StatusOK, openpitrix2.AppVersion{}).
|
||||
Param(webservice.PathParameter("app", "app template id")))
|
||||
webservice.Route(webservice.POST("/apps/{app}/action").
|
||||
To(openpitrix.DoAppAction).
|
||||
To(handler.DoAppAction).
|
||||
Doc("Perform recover or suspend operation on app").
|
||||
Returns(http.StatusOK, ok, errors.Error{}).
|
||||
Returns(http.StatusOK, api.StatusOK, errors.Error{}).
|
||||
Param(webservice.PathParameter("version", "app template version id")).
|
||||
Param(webservice.PathParameter("app", "app template id")))
|
||||
webservice.Route(webservice.GET("/apps").
|
||||
To(openpitrix.ListApps).
|
||||
To(handler.ListApps).
|
||||
Doc("List app templates").
|
||||
Param(webservice.QueryParameter(params.ConditionsParam, "query conditions,connect multiple conditions with commas, equal symbol for exact query, wave symbol for fuzzy query e.g. name~a").
|
||||
Required(false).
|
||||
@@ -241,36 +239,36 @@ func addWebService(c *restful.Container) error {
|
||||
DefaultValue("limit=10,page=1")).
|
||||
Param(webservice.QueryParameter(params.ReverseParam, "sort parameters, e.g. reverse=true")).
|
||||
Param(webservice.QueryParameter(params.OrderByParam, "sort parameters, e.g. orderBy=createTime")).
|
||||
Returns(http.StatusOK, ok, models.PageableResponse{}))
|
||||
Returns(http.StatusOK, api.StatusOK, models.PageableResponse{}))
|
||||
webservice.Route(webservice.POST("/categories").
|
||||
To(openpitrix.CreateCategory).
|
||||
To(handler.CreateCategory).
|
||||
Doc("Create app template category").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}).
|
||||
Reads(types.CreateCategoryRequest{}).
|
||||
Returns(http.StatusOK, ok, types.CreateCategoryResponse{}).
|
||||
Reads(openpitrix2.CreateCategoryRequest{}).
|
||||
Returns(http.StatusOK, api.StatusOK, openpitrix2.CreateCategoryResponse{}).
|
||||
Param(webservice.PathParameter("app", "app template id")))
|
||||
webservice.Route(webservice.DELETE("/categories/{category}").
|
||||
To(openpitrix.DeleteCategory).
|
||||
To(handler.DeleteCategory).
|
||||
Doc("Delete the specified category").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}).
|
||||
Returns(http.StatusOK, ok, errors.Error{}).
|
||||
Returns(http.StatusOK, api.StatusOK, errors.Error{}).
|
||||
Param(webservice.PathParameter("category", "category id")))
|
||||
webservice.Route(webservice.PATCH("/categories/{category}").
|
||||
Consumes(mimePatch...).
|
||||
To(openpitrix.ModifyCategory).
|
||||
To(handler.ModifyCategory).
|
||||
Doc("Patch the specified category").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}).
|
||||
Reads(types.ModifyCategoryRequest{}).
|
||||
Returns(http.StatusOK, ok, errors.Error{}).
|
||||
Reads(openpitrix2.ModifyCategoryRequest{}).
|
||||
Returns(http.StatusOK, api.StatusOK, errors.Error{}).
|
||||
Param(webservice.PathParameter("category", "category id")))
|
||||
webservice.Route(webservice.GET("/categories/{category}").
|
||||
To(openpitrix.DescribeCategory).
|
||||
To(handler.DescribeCategory).
|
||||
Doc("Describe the specified category").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}).
|
||||
Returns(http.StatusOK, ok, types.Category{}).
|
||||
Returns(http.StatusOK, api.StatusOK, openpitrix2.Category{}).
|
||||
Param(webservice.PathParameter("category", "category id")))
|
||||
webservice.Route(webservice.GET("/categories").
|
||||
To(openpitrix.ListCategories).
|
||||
To(handler.ListCategories).
|
||||
Doc("List categories").
|
||||
Param(webservice.QueryParameter(params.ConditionsParam, "query conditions,connect multiple conditions with commas, equal symbol for exact query, wave symbol for fuzzy query e.g. name~a").
|
||||
Required(false).
|
||||
@@ -281,43 +279,43 @@ func addWebService(c *restful.Container) error {
|
||||
DefaultValue("limit=10,page=1")).
|
||||
Param(webservice.QueryParameter(params.ReverseParam, "sort parameters, e.g. reverse=true")).
|
||||
Param(webservice.QueryParameter(params.OrderByParam, "sort parameters, e.g. orderBy=createTime")).
|
||||
Returns(http.StatusOK, ok, models.PageableResponse{}))
|
||||
Returns(http.StatusOK, api.StatusOK, models.PageableResponse{}))
|
||||
|
||||
webservice.Route(webservice.GET("/attachments/{attachment}").
|
||||
To(openpitrix.DescribeAttachment).
|
||||
To(handler.DescribeAttachment).
|
||||
Doc("Get attachment by attachment id").
|
||||
Param(webservice.PathParameter("attachment", "attachment id")).
|
||||
Returns(http.StatusOK, ok, types.Attachment{}))
|
||||
Returns(http.StatusOK, api.StatusOK, openpitrix2.Attachment{}))
|
||||
|
||||
webservice.Route(webservice.POST("/repos").
|
||||
To(openpitrix.CreateRepo).
|
||||
To(handler.CreateRepo).
|
||||
Doc("Create repository, repository used to store package of app").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}).
|
||||
Param(webservice.QueryParameter("validate", "Validate repository")).
|
||||
Returns(http.StatusOK, ok, types.CreateRepoResponse{}).
|
||||
Reads(types.CreateRepoRequest{}))
|
||||
Returns(http.StatusOK, api.StatusOK, openpitrix2.CreateRepoResponse{}).
|
||||
Reads(openpitrix2.CreateRepoRequest{}))
|
||||
webservice.Route(webservice.DELETE("/repos/{repo}").
|
||||
To(openpitrix.DeleteRepo).
|
||||
To(handler.DeleteRepo).
|
||||
Doc("Delete the specified repository").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}).
|
||||
Returns(http.StatusOK, ok, errors.Error{}).
|
||||
Returns(http.StatusOK, api.StatusOK, errors.Error{}).
|
||||
Param(webservice.PathParameter("repo", "repo id")))
|
||||
webservice.Route(webservice.PATCH("/repos/{repo}").
|
||||
Consumes(mimePatch...).
|
||||
To(openpitrix.ModifyRepo).
|
||||
To(handler.ModifyRepo).
|
||||
Doc("Patch the specified repository").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}).
|
||||
Reads(types.ModifyRepoRequest{}).
|
||||
Returns(http.StatusOK, ok, errors.Error{}).
|
||||
Reads(openpitrix2.ModifyRepoRequest{}).
|
||||
Returns(http.StatusOK, api.StatusOK, errors.Error{}).
|
||||
Param(webservice.PathParameter("repo", "repo id")))
|
||||
webservice.Route(webservice.GET("/repos/{repo}").
|
||||
To(openpitrix.DescribeRepo).
|
||||
To(handler.DescribeRepo).
|
||||
Doc("Describe the specified repository").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}).
|
||||
Returns(http.StatusOK, ok, types.Repo{}).
|
||||
Returns(http.StatusOK, api.StatusOK, openpitrix2.Repo{}).
|
||||
Param(webservice.PathParameter("repo", "repo id")))
|
||||
webservice.Route(webservice.GET("/repos").
|
||||
To(openpitrix.ListRepos).
|
||||
To(handler.ListRepos).
|
||||
Doc("List repositories").
|
||||
Param(webservice.QueryParameter(params.ConditionsParam, "query conditions,connect multiple conditions with commas, equal symbol for exact query, wave symbol for fuzzy query e.g. name~a").
|
||||
Required(false).
|
||||
@@ -328,17 +326,17 @@ func addWebService(c *restful.Container) error {
|
||||
DefaultValue("limit=10,page=1")).
|
||||
Param(webservice.QueryParameter(params.ReverseParam, "sort parameters, e.g. reverse=true")).
|
||||
Param(webservice.QueryParameter(params.OrderByParam, "sort parameters, e.g. orderBy=createTime")).
|
||||
Returns(http.StatusOK, ok, models.PageableResponse{}))
|
||||
Returns(http.StatusOK, api.StatusOK, models.PageableResponse{}))
|
||||
webservice.Route(webservice.POST("/repos/{repo}/action").
|
||||
To(openpitrix.DoRepoAction).
|
||||
To(handler.DoRepoAction).
|
||||
Doc("Start index repository event").
|
||||
Reads(types.RepoActionRequest{}).
|
||||
Returns(http.StatusOK, ok, errors.Error{}).
|
||||
Reads(openpitrix2.RepoActionRequest{}).
|
||||
Returns(http.StatusOK, api.StatusOK, errors.Error{}).
|
||||
Param(webservice.PathParameter("repo", "repo id")))
|
||||
webservice.Route(webservice.GET("/repos/{repo}/events").
|
||||
To(openpitrix.ListRepoEvents).
|
||||
To(handler.ListRepoEvents).
|
||||
Doc("Get repository events").
|
||||
Returns(http.StatusOK, ok, models.PageableResponse{}).
|
||||
Returns(http.StatusOK, api.StatusOK, models.PageableResponse{}).
|
||||
Param(webservice.PathParameter("repo", "repo id")))
|
||||
|
||||
c.Add(webservice)
|
||||
|
||||
@@ -1,18 +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 operations contains operations API versions
|
||||
package operations
|
||||
@@ -1,33 +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 install
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
urlruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
||||
"kubesphere.io/kubesphere/pkg/kapis/operations/v1alpha2"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Install(runtime.Container)
|
||||
}
|
||||
|
||||
func Install(container *restful.Container) {
|
||||
urlruntime.Must(v1alpha2.AddToContainer(container, nil))
|
||||
}
|
||||
@@ -20,19 +20,21 @@ package v1alpha2
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"kubesphere.io/kubesphere/pkg/api"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
||||
"kubesphere.io/kubesphere/pkg/server/errors"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
const GroupName = "operations.kubesphere.io"
|
||||
const (
|
||||
GroupName = "operations.kubesphere.io"
|
||||
)
|
||||
|
||||
var GroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha2"}
|
||||
|
||||
func AddToContainer(c *restful.Container, client k8s.Client) error {
|
||||
|
||||
ok := "ok"
|
||||
webservice := runtime.NewWebService(GroupVersion)
|
||||
|
||||
handler := newOperationHandler(client)
|
||||
@@ -45,7 +47,7 @@ func AddToContainer(c *restful.Container, client k8s.Client) error {
|
||||
Param(webservice.PathParameter("namespace", "the name of the namespace where the job runs in")).
|
||||
Param(webservice.QueryParameter("action", "action must be \"rerun\"")).
|
||||
Param(webservice.QueryParameter("resourceVersion", "version of job, rerun when the version matches").Required(true)).
|
||||
Returns(http.StatusOK, ok, errors.Error{}))
|
||||
Returns(http.StatusOK, api.StatusOK, errors.Error{}))
|
||||
|
||||
c.Add(webservice)
|
||||
|
||||
|
||||
@@ -54,18 +54,18 @@ func (r *resourceHandler) handleGetNamespacedResources(request *restful.Request,
|
||||
|
||||
func (r *resourceHandler) handleListNamespaceResources(request *restful.Request, response *restful.Response) {
|
||||
namespace := request.PathParameter("namespace")
|
||||
resourceName := request.PathParameter("resources")
|
||||
conditions, err := params.ParseConditions(request.QueryParameter(params.ConditionsParam))
|
||||
resource := request.PathParameter("resources")
|
||||
orderBy := params.GetStringValueWithDefault(request, params.OrderByParam, v1alpha2.CreateTime)
|
||||
limit, offset := params.ParsePaging(request.QueryParameter(params.PagingParam))
|
||||
reverse := params.ParseReverse(request)
|
||||
limit, offset := params.ParsePaging(request)
|
||||
reverse := params.GetBoolValueWithDefault(request, params.ReverseParam, false)
|
||||
conditions, err := params.ParseConditions(request)
|
||||
|
||||
if err != nil {
|
||||
response.WriteHeaderAndEntity(http.StatusBadRequest, err)
|
||||
return
|
||||
}
|
||||
|
||||
result, err := r.resourcesGetter.ListResources(namespace, resourceName, conditions, orderBy, reverse, limit, offset)
|
||||
result, err := r.resourcesGetter.ListResources(namespace, resource, conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
api.HandleInternalError(response, err)
|
||||
|
||||
@@ -1,17 +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 tenant
|
||||
@@ -1,33 +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 install
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
urlruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
||||
tenantv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/tenant/v1alpha2"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Install(runtime.Container)
|
||||
}
|
||||
|
||||
func Install(container *restful.Container) {
|
||||
urlruntime.Must(tenantv1alpha2.AddToContainer(container))
|
||||
}
|
||||
@@ -1 +1,400 @@
|
||||
package v1alpha2
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
k8serr "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/util/net"
|
||||
"k8s.io/klog"
|
||||
"kubesphere.io/kubesphere/pkg/api"
|
||||
devopsv1alpha2 "kubesphere.io/kubesphere/pkg/api/devops/v1alpha2"
|
||||
loggingv1alpha2 "kubesphere.io/kubesphere/pkg/api/logging/v1alpha2"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/logging"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam"
|
||||
"kubesphere.io/kubesphere/pkg/models/metrics"
|
||||
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
|
||||
"kubesphere.io/kubesphere/pkg/models/tenant"
|
||||
"kubesphere.io/kubesphere/pkg/server/errors"
|
||||
"kubesphere.io/kubesphere/pkg/server/params"
|
||||
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type tenantHandler struct {
|
||||
tenant tenant.Interface
|
||||
}
|
||||
|
||||
func newTenantHandler() *tenantHandler {
|
||||
return &tenantHandler{}
|
||||
}
|
||||
|
||||
func (h *tenantHandler) ListWorkspaceRules(req *restful.Request, resp *restful.Response) {
|
||||
workspace := req.PathParameter("workspace")
|
||||
username := req.HeaderParameter(constants.UserNameHeader)
|
||||
|
||||
rules, err := iam.GetUserWorkspaceSimpleRules(workspace, username)
|
||||
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(rules)
|
||||
}
|
||||
|
||||
func (h *tenantHandler) ListWorkspaces(req *restful.Request, resp *restful.Response) {
|
||||
username := req.HeaderParameter(constants.UserNameHeader)
|
||||
orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, v1alpha2.CreateTime)
|
||||
limit, offset := params.ParsePaging(req)
|
||||
reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, true)
|
||||
conditions, err := params.ParseConditions(req)
|
||||
|
||||
if err != nil {
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.tenant.ListWorkspaces(username, conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(result)
|
||||
}
|
||||
|
||||
func (h *tenantHandler) DescribeWorkspace(req *restful.Request, resp *restful.Response) {
|
||||
username := req.HeaderParameter(constants.UserNameHeader)
|
||||
workspaceName := req.PathParameter("workspace")
|
||||
|
||||
result, err := h.tenant.DescribeWorkspace(username, workspaceName)
|
||||
|
||||
if err != nil {
|
||||
if k8serr.IsNotFound(err) {
|
||||
api.HandleNotFound(resp, err)
|
||||
} else {
|
||||
api.HandleInternalError(resp, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(result)
|
||||
}
|
||||
|
||||
func (h *tenantHandler) ListNamespaces(req *restful.Request, resp *restful.Response) {
|
||||
workspace := req.PathParameter("workspace")
|
||||
username := req.PathParameter("member")
|
||||
// /workspaces/{workspace}/members/{username}/namespaces
|
||||
if username == "" {
|
||||
// /workspaces/{workspace}/namespaces
|
||||
username = req.HeaderParameter(constants.UserNameHeader)
|
||||
}
|
||||
|
||||
orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, v1alpha2.CreateTime)
|
||||
limit, offset := params.ParsePaging(req)
|
||||
reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, true)
|
||||
conditions, err := params.ParseConditions(req)
|
||||
|
||||
if err != nil {
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
conditions.Match[constants.WorkspaceLabelKey] = workspace
|
||||
|
||||
result, err := h.tenant.ListNamespaces(username, conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
namespaces := make([]*v1.Namespace, 0)
|
||||
|
||||
for _, item := range result.Items {
|
||||
namespaces = append(namespaces, item.(*v1.Namespace).DeepCopy())
|
||||
}
|
||||
|
||||
namespaces = metrics.GetNamespacesWithMetrics(namespaces)
|
||||
|
||||
items := make([]interface{}, 0)
|
||||
|
||||
for _, item := range namespaces {
|
||||
items = append(items, item)
|
||||
}
|
||||
|
||||
result.Items = items
|
||||
|
||||
resp.WriteAsJson(result)
|
||||
}
|
||||
|
||||
func (h *tenantHandler) CreateNamespace(req *restful.Request, resp *restful.Response) {
|
||||
workspace := req.PathParameter("workspace")
|
||||
username := req.HeaderParameter(constants.UserNameHeader)
|
||||
var namespace v1.Namespace
|
||||
err := req.ReadEntity(&namespace)
|
||||
if err != nil {
|
||||
api.HandleNotFound(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = h.tenant.DescribeWorkspace("", workspace)
|
||||
|
||||
if err != nil {
|
||||
if k8serr.IsNotFound(err) {
|
||||
api.HandleForbidden(resp, err)
|
||||
} else {
|
||||
api.HandleInternalError(resp, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
created, err := h.tenant.CreateNamespace(workspace, &namespace, username)
|
||||
|
||||
if err != nil {
|
||||
if k8serr.IsAlreadyExists(err) {
|
||||
resp.WriteHeaderAndEntity(http.StatusConflict, err)
|
||||
} else {
|
||||
api.HandleInternalError(resp, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
resp.WriteAsJson(created)
|
||||
}
|
||||
|
||||
func (h *tenantHandler) DeleteNamespace(req *restful.Request, resp *restful.Response) {
|
||||
workspace := req.PathParameter("workspace")
|
||||
namespace := req.PathParameter("namespace")
|
||||
|
||||
err := h.tenant.DeleteNamespace(workspace, namespace)
|
||||
|
||||
if err != nil {
|
||||
if k8serr.IsNotFound(err) {
|
||||
api.HandleNotFound(resp, err)
|
||||
} else {
|
||||
api.HandleInternalError(resp, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(errors.None)
|
||||
}
|
||||
|
||||
func (h *tenantHandler) ListDevopsProjects(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
workspace := req.PathParameter("workspace")
|
||||
username := req.PathParameter("member")
|
||||
if username == "" {
|
||||
username = req.HeaderParameter(constants.UserNameHeader)
|
||||
}
|
||||
orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, v1alpha2.CreateTime)
|
||||
limit, offset := params.ParsePaging(req)
|
||||
reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, true)
|
||||
conditions, err := params.ParseConditions(req)
|
||||
|
||||
if err != nil {
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
result, err := tenant.ListDevopsProjects(workspace, username, conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(result)
|
||||
}
|
||||
|
||||
func (h *tenantHandler) GetDevOpsProjectsCount(req *restful.Request, resp *restful.Response) {
|
||||
username := req.HeaderParameter(constants.UserNameHeader)
|
||||
|
||||
result, err := tenant.GetDevOpsProjectsCount(username)
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
resp.WriteAsJson(struct {
|
||||
Count uint32 `json:"count"`
|
||||
}{Count: result})
|
||||
}
|
||||
func (h *tenantHandler) DeleteDevopsProject(req *restful.Request, resp *restful.Response) {
|
||||
projectId := req.PathParameter("devops")
|
||||
workspace := req.PathParameter("workspace")
|
||||
username := req.HeaderParameter(constants.UserNameHeader)
|
||||
|
||||
_, err := h.tenant.DescribeWorkspace("", workspace)
|
||||
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = tenant.DeleteDevOpsProject(projectId, username)
|
||||
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(errors.None)
|
||||
}
|
||||
|
||||
func (h *tenantHandler) CreateDevopsProject(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
workspaceName := req.PathParameter("workspace")
|
||||
username := req.HeaderParameter(constants.UserNameHeader)
|
||||
|
||||
var devops devopsv1alpha2.DevOpsProject
|
||||
|
||||
err := req.ReadEntity(&devops)
|
||||
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
project, err := tenant.CreateDevopsProject(username, workspaceName, &devops)
|
||||
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(project)
|
||||
}
|
||||
|
||||
func (h *tenantHandler) ListNamespaceRules(req *restful.Request, resp *restful.Response) {
|
||||
namespace := req.PathParameter("namespace")
|
||||
username := req.HeaderParameter(constants.UserNameHeader)
|
||||
|
||||
rules, err := iam.GetUserNamespaceSimpleRules(namespace, username)
|
||||
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(rules)
|
||||
}
|
||||
|
||||
func (h *tenantHandler) ListDevopsRules(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
devops := req.PathParameter("devops")
|
||||
username := req.HeaderParameter(constants.UserNameHeader)
|
||||
|
||||
rules, err := tenant.GetUserDevopsSimpleRules(username, devops)
|
||||
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(rules)
|
||||
}
|
||||
|
||||
func (h *tenantHandler) LogQuery(req *restful.Request, resp *restful.Response) {
|
||||
operation := req.QueryParameter("operation")
|
||||
req, err := h.regenerateLoggingRequest(req)
|
||||
switch {
|
||||
case err != nil:
|
||||
api.HandleInternalError(resp, err)
|
||||
case req != nil:
|
||||
logging.LoggingQueryCluster(req, resp)
|
||||
default:
|
||||
if operation == "export" {
|
||||
resp.Header().Set(restful.HEADER_ContentType, "text/plain")
|
||||
resp.Header().Set("Content-Disposition", "attachment")
|
||||
resp.Write(nil)
|
||||
} else {
|
||||
resp.WriteAsJson(loggingv1alpha2.QueryResult{Read: new(loggingv1alpha2.ReadResult)})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// override namespace query conditions
|
||||
func (h *tenantHandler) regenerateLoggingRequest(req *restful.Request) (*restful.Request, error) {
|
||||
|
||||
username := req.HeaderParameter(constants.UserNameHeader)
|
||||
|
||||
// regenerate the request for log query
|
||||
newUrl := net.FormatURL("http", "127.0.0.1", 80, "/kapis/logging.kubesphere.io/v1alpha2/cluster")
|
||||
values := req.Request.URL.Query()
|
||||
|
||||
clusterRules, err := iam.GetUserClusterRules(username)
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hasClusterLogAccess := iam.RulesMatchesRequired(clusterRules, rbacv1.PolicyRule{Verbs: []string{"get"}, Resources: []string{"*"}, APIGroups: []string{"logging.kubesphere.io"}})
|
||||
// if the user is not a cluster admin
|
||||
if !hasClusterLogAccess {
|
||||
queryNamespaces := strings.Split(req.QueryParameter("namespaces"), ",")
|
||||
// then the user can only view logs of namespaces he belongs to
|
||||
namespaces := make([]string, 0)
|
||||
roles, err := iam.GetUserRoles("", username)
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
return nil, err
|
||||
}
|
||||
for _, role := range roles {
|
||||
if !sliceutil.HasString(namespaces, role.Namespace) && iam.RulesMatchesRequired(role.Rules, rbacv1.PolicyRule{Verbs: []string{"get"}, Resources: []string{"*"}, APIGroups: []string{"logging.kubesphere.io"}}) {
|
||||
namespaces = append(namespaces, role.Namespace)
|
||||
}
|
||||
}
|
||||
|
||||
// if the user belongs to no namespace
|
||||
// then no log visible
|
||||
if len(namespaces) == 0 {
|
||||
return nil, nil
|
||||
} else if len(queryNamespaces) == 1 && queryNamespaces[0] == "" {
|
||||
values.Set("namespaces", strings.Join(namespaces, ","))
|
||||
} else {
|
||||
inter := intersection(queryNamespaces, namespaces)
|
||||
if len(inter) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
values.Set("namespaces", strings.Join(inter, ","))
|
||||
}
|
||||
}
|
||||
|
||||
newUrl.RawQuery = values.Encode()
|
||||
|
||||
// forward the request to logging model
|
||||
newHttpRequest, _ := http.NewRequest(http.MethodGet, newUrl.String(), nil)
|
||||
return restful.NewRequest(newHttpRequest), nil
|
||||
}
|
||||
|
||||
func intersection(s1, s2 []string) (inter []string) {
|
||||
hash := make(map[string]bool)
|
||||
for _, e := range s1 {
|
||||
hash[e] = true
|
||||
}
|
||||
for _, e := range s2 {
|
||||
// If elements present in the hashmap then append intersection list.
|
||||
if hash[e] {
|
||||
inter = append(inter, e)
|
||||
}
|
||||
}
|
||||
//Remove dups from slice.
|
||||
inter = removeDups(inter)
|
||||
return
|
||||
}
|
||||
|
||||
//Remove dups from slice.
|
||||
func removeDups(elements []string) (nodups []string) {
|
||||
encountered := make(map[string]bool)
|
||||
for _, element := range elements {
|
||||
if !encountered[element] {
|
||||
nodups = append(nodups, element)
|
||||
encountered[element] = true
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -22,13 +22,14 @@ import (
|
||||
"github.com/emicklei/go-restful-openapi"
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"kubesphere.io/kubesphere/pkg/api"
|
||||
devopsv1alpha2 "kubesphere.io/kubesphere/pkg/api/devops/v1alpha2"
|
||||
"kubesphere.io/kubesphere/pkg/api/logging/v1alpha2"
|
||||
"kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha1"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/tenant"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam"
|
||||
"kubesphere.io/kubesphere/pkg/server/errors"
|
||||
"kubesphere.io/kubesphere/pkg/server/params"
|
||||
|
||||
@@ -37,78 +38,72 @@ import (
|
||||
|
||||
const (
|
||||
GroupName = "tenant.kubesphere.io"
|
||||
RespOK = "ok"
|
||||
)
|
||||
|
||||
var GroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha2"}
|
||||
|
||||
var (
|
||||
WebServiceBuilder = runtime.NewContainerBuilder(addWebService)
|
||||
AddToContainer = WebServiceBuilder.AddToContainer
|
||||
)
|
||||
|
||||
func addWebService(c *restful.Container) error {
|
||||
ok := "ok"
|
||||
func AddToContainer(c *restful.Container) error {
|
||||
ws := runtime.NewWebService(GroupVersion)
|
||||
handler := newTenantHandler()
|
||||
|
||||
ws.Route(ws.GET("/workspaces").
|
||||
To(tenant.ListWorkspaces).
|
||||
Returns(http.StatusOK, ok, models.PageableResponse{}).
|
||||
To(handler.ListWorkspaces).
|
||||
Returns(http.StatusOK, api.StatusOK, models.PageableResponse{}).
|
||||
Doc("List all workspaces that belongs to the current user").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.TenantResourcesTag}))
|
||||
ws.Route(ws.GET("/workspaces/{workspace}").
|
||||
To(tenant.DescribeWorkspace).
|
||||
To(handler.DescribeWorkspace).
|
||||
Doc("Describe the specified workspace").
|
||||
Param(ws.PathParameter("workspace", "workspace name")).
|
||||
Returns(http.StatusOK, ok, v1alpha1.Workspace{}).
|
||||
Returns(http.StatusOK, api.StatusOK, v1alpha1.Workspace{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.TenantResourcesTag}))
|
||||
ws.Route(ws.GET("/workspaces/{workspace}/rules").
|
||||
To(tenant.ListWorkspaceRules).
|
||||
To(handler.ListWorkspaceRules).
|
||||
Param(ws.PathParameter("workspace", "workspace name")).
|
||||
Doc("List the rules of the specified workspace for the current user").
|
||||
Returns(http.StatusOK, ok, models.SimpleRule{}).
|
||||
Returns(http.StatusOK, api.StatusOK, iam.SimpleRule{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.TenantResourcesTag}))
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/rules").
|
||||
To(tenant.ListNamespaceRules).
|
||||
To(handler.ListNamespaceRules).
|
||||
Param(ws.PathParameter("namespace", "the name of the namespace")).
|
||||
Doc("List the rules of the specified namespace for the current user").
|
||||
Returns(http.StatusOK, ok, models.SimpleRule{}).
|
||||
Returns(http.StatusOK, api.StatusOK, iam.SimpleRule{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.TenantResourcesTag}))
|
||||
ws.Route(ws.GET("/devops/{devops}/rules").
|
||||
To(tenant.ListDevopsRules).
|
||||
To(handler.ListDevopsRules).
|
||||
Param(ws.PathParameter("devops", "devops project ID")).
|
||||
Doc("List the rules of the specified DevOps project for the current user").
|
||||
Returns(http.StatusOK, ok, models.SimpleRule{}).
|
||||
Returns(http.StatusOK, api.StatusOK, iam.SimpleRule{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.TenantResourcesTag}))
|
||||
ws.Route(ws.GET("/workspaces/{workspace}/namespaces").
|
||||
To(tenant.ListNamespaces).
|
||||
To(handler.ListNamespaces).
|
||||
Param(ws.PathParameter("workspace", "workspace name")).
|
||||
Doc("List the namespaces of the specified workspace for the current user").
|
||||
Returns(http.StatusOK, ok, []v1.Namespace{}).
|
||||
Returns(http.StatusOK, api.StatusOK, []v1.Namespace{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.TenantResourcesTag}))
|
||||
ws.Route(ws.GET("/workspaces/{workspace}/members/{member}/namespaces").
|
||||
To(tenant.ListNamespacesByUsername).
|
||||
To(handler.ListNamespaces).
|
||||
Param(ws.PathParameter("workspace", "workspace name")).
|
||||
Param(ws.PathParameter("member", "workspace member's username")).
|
||||
Doc("List the namespaces for the workspace member").
|
||||
Returns(http.StatusOK, ok, []v1.Namespace{}).
|
||||
Returns(http.StatusOK, api.StatusOK, []v1.Namespace{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.TenantResourcesTag}))
|
||||
ws.Route(ws.POST("/workspaces/{workspace}/namespaces").
|
||||
To(tenant.CreateNamespace).
|
||||
To(handler.CreateNamespace).
|
||||
Param(ws.PathParameter("workspace", "workspace name")).
|
||||
Doc("Create a namespace in the specified workspace").
|
||||
Returns(http.StatusOK, ok, []v1.Namespace{}).
|
||||
Returns(http.StatusOK, api.StatusOK, []v1.Namespace{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.TenantResourcesTag}))
|
||||
ws.Route(ws.DELETE("/workspaces/{workspace}/namespaces/{namespace}").
|
||||
To(tenant.DeleteNamespace).
|
||||
To(handler.DeleteNamespace).
|
||||
Param(ws.PathParameter("workspace", "workspace name")).
|
||||
Param(ws.PathParameter("namespace", "the name of the namespace")).
|
||||
Doc("Delete the specified namespace from the workspace").
|
||||
Returns(http.StatusOK, ok, errors.Error{}).
|
||||
Returns(http.StatusOK, api.StatusOK, errors.Error{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.TenantResourcesTag}))
|
||||
|
||||
ws.Route(ws.GET("/workspaces/{workspace}/devops").
|
||||
To(tenant.ListDevopsProjects).
|
||||
To(handler.ListDevopsProjects).
|
||||
Param(ws.PathParameter("workspace", "workspace name")).
|
||||
Param(ws.QueryParameter(params.PagingParam, "page").
|
||||
Required(false).
|
||||
@@ -120,7 +115,7 @@ func addWebService(c *restful.Container) error {
|
||||
Doc("List devops projects for the current user").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.TenantResourcesTag}))
|
||||
ws.Route(ws.GET("/workspaces/{workspace}/members/{member}/devops").
|
||||
To(tenant.ListDevopsProjectsByUsername).
|
||||
To(handler.ListDevopsProjects).
|
||||
Param(ws.PathParameter("workspace", "workspace name")).
|
||||
Param(ws.PathParameter("member", "workspace member's username")).
|
||||
Param(ws.QueryParameter(params.PagingParam, "page").
|
||||
@@ -130,32 +125,32 @@ func addWebService(c *restful.Container) error {
|
||||
Param(ws.QueryParameter(params.ConditionsParam, "query conditions").
|
||||
Required(false).
|
||||
DataFormat("key=%s,key~%s")).
|
||||
Returns(http.StatusOK, ok, models.PageableResponse{}).
|
||||
Returns(http.StatusOK, api.StatusOK, models.PageableResponse{}).
|
||||
Doc("List the devops projects for the workspace member").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.TenantResourcesTag}))
|
||||
ws.Route(ws.GET("/devopscount").
|
||||
To(tenant.GetDevOpsProjectsCount).
|
||||
Returns(http.StatusOK, ok, struct {
|
||||
To(handler.GetDevOpsProjectsCount).
|
||||
Returns(http.StatusOK, api.StatusOK, struct {
|
||||
Count uint32 `json:"count"`
|
||||
}{}).
|
||||
Doc("Get the devops projects count for the member").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.TenantResourcesTag}))
|
||||
ws.Route(ws.POST("/workspaces/{workspace}/devops").
|
||||
To(tenant.CreateDevopsProject).
|
||||
To(handler.CreateDevopsProject).
|
||||
Param(ws.PathParameter("workspace", "workspace name")).
|
||||
Doc("Create a devops project in the specified workspace").
|
||||
Reads(devopsv1alpha2.DevOpsProject{}).
|
||||
Returns(http.StatusOK, RespOK, devopsv1alpha2.DevOpsProject{}).
|
||||
Returns(http.StatusOK, api.StatusOK, devopsv1alpha2.DevOpsProject{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.TenantResourcesTag}))
|
||||
ws.Route(ws.DELETE("/workspaces/{workspace}/devops/{devops}").
|
||||
To(tenant.DeleteDevopsProject).
|
||||
To(handler.DeleteDevopsProject).
|
||||
Param(ws.PathParameter("workspace", "workspace name")).
|
||||
Param(ws.PathParameter("devops", "devops project ID")).
|
||||
Doc("Delete the specified devops project from the workspace").
|
||||
Returns(http.StatusOK, RespOK, devopsv1alpha2.DevOpsProject{}).
|
||||
Returns(http.StatusOK, api.StatusOK, devopsv1alpha2.DevOpsProject{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.TenantResourcesTag}))
|
||||
ws.Route(ws.GET("/logs").
|
||||
To(tenant.LogQuery).
|
||||
To(handler.LogQuery).
|
||||
Doc("Query cluster-level logs in a multi-tenants environment").
|
||||
Param(ws.QueryParameter("operation", "Operation type. This can be one of four types: query (for querying logs), statistics (for retrieving statistical data), histogram (for displaying log count by time interval) and export (for exporting logs). Defaults to query.").DefaultValue("query").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("workspaces", "A comma-separated list of workspaces. This field restricts the query to specified workspaces. For example, the following filter matches the workspace my-ws and demo-ws: `my-ws,demo-ws`").DataType("string").Required(false)).
|
||||
@@ -177,7 +172,7 @@ func addWebService(c *restful.Container) error {
|
||||
Param(ws.QueryParameter("size", "Size of result to return. It requires **operation** is set to query. Defaults to 10 (i.e. 10 log records).").DataType("integer").DefaultValue("10").Required(false)).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.TenantResourcesTag}).
|
||||
Writes(v1alpha2.Response{}).
|
||||
Returns(http.StatusOK, RespOK, v1alpha2.Response{})).
|
||||
Returns(http.StatusOK, api.StatusOK, v1alpha2.Response{})).
|
||||
Consumes(restful.MIME_JSON, restful.MIME_XML).
|
||||
Produces(restful.MIME_JSON, "text/plain")
|
||||
|
||||
|
||||
@@ -1,18 +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 terminal contains terminal API versions
|
||||
package terminal
|
||||
@@ -1,33 +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 install
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
urlruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
||||
"kubesphere.io/kubesphere/pkg/kapis/terminal/v1alpha2"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Install(runtime.Container)
|
||||
}
|
||||
|
||||
func Install(c *restful.Container) {
|
||||
urlruntime.Must(v1alpha2.AddToContainer(c, nil, nil))
|
||||
}
|
||||
@@ -24,12 +24,12 @@ import (
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
)
|
||||
|
||||
const (
|
||||
GroupName = "terminal.kubesphere.io"
|
||||
tag = "Terminal"
|
||||
)
|
||||
|
||||
var GroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha2"}
|
||||
@@ -43,7 +43,7 @@ func AddToContainer(c *restful.Container, client kubernetes.Interface, config *r
|
||||
webservice.Route(webservice.GET("/namespaces/{namespace}/pods/{pod}").
|
||||
To(handler.handleTerminalSession).
|
||||
Doc("create terminal session").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{tag}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.TerminalTag}).
|
||||
Writes(models.PodInfo{}))
|
||||
|
||||
c.Add(webservice)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -30,11 +30,10 @@ const (
|
||||
OrderByParam = "orderBy"
|
||||
ConditionsParam = "conditions"
|
||||
ReverseParam = "reverse"
|
||||
NameParam = "name"
|
||||
)
|
||||
|
||||
func ParsePaging(paging string) (limit, offset int) {
|
||||
|
||||
func ParsePaging(req *restful.Request) (limit, offset int) {
|
||||
paging := req.QueryParameter(PagingParam)
|
||||
limit = 10
|
||||
offset = 0
|
||||
if groups := regexp.MustCompile(`^limit=(-?\d+),page=(\d+)$`).FindStringSubmatch(paging); len(groups) == 3 {
|
||||
@@ -45,7 +44,9 @@ func ParsePaging(paging string) (limit, offset int) {
|
||||
return
|
||||
}
|
||||
|
||||
func ParseConditions(conditionsStr string) (*Conditions, error) {
|
||||
func ParseConditions(req *restful.Request) (*Conditions, error) {
|
||||
|
||||
conditionsStr := req.QueryParameter(ConditionsParam)
|
||||
|
||||
conditions := &Conditions{Match: make(map[string]string, 0), Fuzzy: make(map[string]string, 0)}
|
||||
|
||||
@@ -76,20 +77,19 @@ func ParseConditions(conditionsStr string) (*Conditions, error) {
|
||||
return conditions, nil
|
||||
}
|
||||
|
||||
func ParseReverse(req *restful.Request) bool {
|
||||
reverse := req.QueryParameter(ReverseParam)
|
||||
b, err := strconv.ParseBool(reverse)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
type Conditions struct {
|
||||
Match map[string]string
|
||||
Fuzzy map[string]string
|
||||
}
|
||||
|
||||
func GetBoolValueWithDefault(req *restful.Request, name string, dv bool) bool {
|
||||
reverse := req.QueryParameter(name)
|
||||
if v, err := strconv.ParseBool(reverse); err == nil {
|
||||
return v
|
||||
}
|
||||
return dv
|
||||
}
|
||||
|
||||
func GetStringValueWithDefault(req *restful.Request, name string, dv string) string {
|
||||
v := req.QueryParameter(name)
|
||||
if v == "" {
|
||||
|
||||
@@ -119,7 +119,7 @@ type ClientSet struct {
|
||||
redisClient cache.Interface
|
||||
s3Client s3.Interface
|
||||
prometheusClient *prometheus.Client
|
||||
openpitrixClient *openpitrix.Client
|
||||
openpitrixClient openpitrix.Client
|
||||
kubesphereClient *kubesphere.Client
|
||||
elasticSearchClient *esclient.ElasticSearchClient
|
||||
}
|
||||
@@ -292,7 +292,7 @@ func (cs *ClientSet) S3() (s3.Interface, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func (cs *ClientSet) OpenPitrix() (*openpitrix.Client, error) {
|
||||
func (cs *ClientSet) OpenPitrix() (openpitrix.Client, error) {
|
||||
var err error
|
||||
|
||||
if cs.csoptions.openPitrixOptions == nil ||
|
||||
|
||||
@@ -85,7 +85,7 @@ func (c *channelPool) Get() (*PoolConn, error) {
|
||||
return nil, ErrClosed
|
||||
}
|
||||
|
||||
// wrap our connections with our ldap.Client implementation (wrapConn
|
||||
// wrap our connections with our ldap.PoolClient implementation (wrapConn
|
||||
// method) that puts the connection back to the pool if it's closed.
|
||||
select {
|
||||
case conn := <-conns:
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"github.com/go-ldap/ldap"
|
||||
)
|
||||
|
||||
// PoolConn implements Client to override the Close() method
|
||||
// PoolConn implements PoolClient to override the Close() method
|
||||
type PoolConn struct {
|
||||
Conn ldap.Client
|
||||
c *channelPool
|
||||
|
||||
@@ -23,13 +23,19 @@ import (
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
type Client interface {
|
||||
NewConn() (ldap.Client, error)
|
||||
GroupSearchBase() string
|
||||
UserSearchBase() string
|
||||
}
|
||||
|
||||
type poolClient struct {
|
||||
pool Pool
|
||||
options *Options
|
||||
}
|
||||
|
||||
// panic if cannot connect to ldap service
|
||||
func NewLdapClient(options *Options, stopCh <-chan struct{}) (*Client, error) {
|
||||
func NewLdapClient(options *Options, stopCh <-chan struct{}) (Client, error) {
|
||||
pool, err := NewChannelPool(8, 64, "kubesphere", func(s string) (ldap.Client, error) {
|
||||
conn, err := ldap.Dial("tcp", options.Host)
|
||||
if err != nil {
|
||||
@@ -44,7 +50,7 @@ func NewLdapClient(options *Options, stopCh <-chan struct{}) (*Client, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client := &Client{
|
||||
client := &poolClient{
|
||||
pool: pool,
|
||||
options: options,
|
||||
}
|
||||
@@ -59,7 +65,7 @@ func NewLdapClient(options *Options, stopCh <-chan struct{}) (*Client, error) {
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func (l *Client) NewConn() (ldap.Client, error) {
|
||||
func (l *poolClient) NewConn() (ldap.Client, error) {
|
||||
if l.pool == nil {
|
||||
err := fmt.Errorf("ldap connection pool is not initialized")
|
||||
klog.Errorln(err)
|
||||
@@ -81,10 +87,10 @@ func (l *Client) NewConn() (ldap.Client, error) {
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func (l *Client) GroupSearchBase() string {
|
||||
func (l *poolClient) GroupSearchBase() string {
|
||||
return l.options.GroupSearchBase
|
||||
}
|
||||
|
||||
func (l *Client) UserSearchBase() string {
|
||||
func (l *poolClient) UserSearchBase() string {
|
||||
return l.options.UserSearchBase
|
||||
}
|
||||
|
||||
2017
pkg/simple/client/openpitrix/mock.go
Normal file
2017
pkg/simple/client/openpitrix/mock.go
Normal file
File diff suppressed because it is too large
Load Diff
@@ -30,16 +30,17 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
KubernetesProvider = "kubernetes"
|
||||
Unknown = "-"
|
||||
DeploySuffix = "-Deployment"
|
||||
DaemonSuffix = "-DaemonSet"
|
||||
StateSuffix = "-StatefulSet"
|
||||
SystemUsername = "system"
|
||||
SystemUserPath = ":system"
|
||||
RuntimeAnnotationKey = "openpitrix_runtime"
|
||||
KubernetesProvider = "kubernetes"
|
||||
Unknown = "-"
|
||||
DeploySuffix = "-Deployment"
|
||||
DaemonSuffix = "-DaemonSet"
|
||||
StateSuffix = "-StatefulSet"
|
||||
SystemUsername = "system"
|
||||
SystemUserPath = ":system"
|
||||
)
|
||||
|
||||
type Interface interface {
|
||||
type Client interface {
|
||||
pb.RuntimeManagerClient
|
||||
pb.ClusterManagerClient
|
||||
pb.AppManagerClient
|
||||
@@ -49,14 +50,14 @@ type Interface interface {
|
||||
pb.RepoIndexerClient
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
runtime pb.RuntimeManagerClient
|
||||
cluster pb.ClusterManagerClient
|
||||
app pb.AppManagerClient
|
||||
repo pb.RepoManagerClient
|
||||
category pb.CategoryManagerClient
|
||||
attachment pb.AttachmentManagerClient
|
||||
repoIndexer pb.RepoIndexerClient
|
||||
type client struct {
|
||||
pb.RuntimeManagerClient
|
||||
pb.ClusterManagerClient
|
||||
pb.AppManagerClient
|
||||
pb.RepoManagerClient
|
||||
pb.CategoryManagerClient
|
||||
pb.AttachmentManagerClient
|
||||
pb.RepoIndexerClient
|
||||
}
|
||||
|
||||
func parseToHostPort(endpoint string) (string, int, error) {
|
||||
@@ -133,7 +134,7 @@ func newAppManagerClient(endpoint string) (pb.AppManagerClient, error) {
|
||||
return pb.NewAppManagerClient(conn), nil
|
||||
}
|
||||
|
||||
func NewOpenPitrixClient(options *Options) (*Client, error) {
|
||||
func NewOpenPitrixClient(options *Options) (Client, error) {
|
||||
|
||||
runtimeMangerClient, err := newRuntimeManagerClient(options.RuntimeManagerEndpoint)
|
||||
|
||||
@@ -184,42 +185,18 @@ func NewOpenPitrixClient(options *Options) (*Client, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client := Client{
|
||||
runtime: runtimeMangerClient,
|
||||
cluster: clusterManagerClient,
|
||||
repo: repoManagerClient,
|
||||
app: appManagerClient,
|
||||
category: categoryManagerClient,
|
||||
attachment: attachmentManagerClient,
|
||||
repoIndexer: repoIndexerClient,
|
||||
client := client{
|
||||
RuntimeManagerClient: runtimeMangerClient,
|
||||
ClusterManagerClient: clusterManagerClient,
|
||||
RepoManagerClient: repoManagerClient,
|
||||
AppManagerClient: appManagerClient,
|
||||
CategoryManagerClient: categoryManagerClient,
|
||||
AttachmentManagerClient: attachmentManagerClient,
|
||||
RepoIndexerClient: repoIndexerClient,
|
||||
}
|
||||
|
||||
return &client, nil
|
||||
}
|
||||
func (c *Client) Runtime() pb.RuntimeManagerClient {
|
||||
return c.runtime
|
||||
}
|
||||
func (c *Client) App() pb.AppManagerClient {
|
||||
return c.app
|
||||
}
|
||||
func (c *Client) Cluster() pb.ClusterManagerClient {
|
||||
return c.cluster
|
||||
}
|
||||
func (c *Client) Category() pb.CategoryManagerClient {
|
||||
return c.category
|
||||
}
|
||||
|
||||
func (c *Client) Repo() pb.RepoManagerClient {
|
||||
return c.repo
|
||||
}
|
||||
|
||||
func (c *Client) RepoIndexer() pb.RepoIndexerClient {
|
||||
return c.repoIndexer
|
||||
}
|
||||
|
||||
func (c *Client) Attachment() pb.AttachmentManagerClient {
|
||||
return c.attachment
|
||||
}
|
||||
|
||||
func SystemContext() context.Context {
|
||||
ctx := context.Background()
|
||||
@@ -20,7 +20,7 @@ package k8sutil
|
||||
import (
|
||||
"k8s.io/api/rbac/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam"
|
||||
)
|
||||
|
||||
func IsControlledBy(reference []metav1.OwnerReference, kind string, name string) bool {
|
||||
@@ -55,15 +55,15 @@ func ContainsUser(subjects interface{}, username string) bool {
|
||||
return true
|
||||
}
|
||||
}
|
||||
case []models.User:
|
||||
for _, u := range subjects.([]models.User) {
|
||||
case []iam.User:
|
||||
for _, u := range subjects.([]iam.User) {
|
||||
if u.Username == username {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
case []*models.User:
|
||||
for _, u := range subjects.([]*models.User) {
|
||||
case []*iam.User:
|
||||
for _, u := range subjects.([]*iam.User) {
|
||||
if u.Username == username {
|
||||
return true
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user