add ks-iam and ks-apigateway
Signed-off-by: hongming <talonwan@yunify.com>
This commit is contained in:
172
pkg/apigateway/caddy-plugin/authenticate/authenticate.go
Normal file
172
pkg/apigateway/caddy-plugin/authenticate/authenticate.go
Normal file
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
|
||||
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 authenticate
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"github.com/mholt/caddy/caddyhttp/httpserver"
|
||||
)
|
||||
|
||||
type Auth struct {
|
||||
Rule Rule
|
||||
Next httpserver.Handler
|
||||
}
|
||||
|
||||
type Rule struct {
|
||||
Secret []byte
|
||||
Path string
|
||||
ExceptedPath []string
|
||||
}
|
||||
|
||||
type User struct {
|
||||
Username string `json:"username"`
|
||||
UID string `json:"uid"`
|
||||
Groups *[]string `json:"groups,omitempty"`
|
||||
Extra *map[string]interface{} `json:"extra,omitempty"`
|
||||
}
|
||||
|
||||
func (h Auth) ServeHTTP(resp http.ResponseWriter, req *http.Request) (int, error) {
|
||||
for _, path := range h.Rule.ExceptedPath {
|
||||
if httpserver.Path(req.URL.Path).Matches(path) {
|
||||
return h.Next.ServeHTTP(resp, req)
|
||||
}
|
||||
}
|
||||
|
||||
if httpserver.Path(req.URL.Path).Matches(h.Rule.Path) {
|
||||
|
||||
uToken, err := h.ExtractToken(req)
|
||||
|
||||
if err != nil {
|
||||
return h.HandleUnauthorized(resp, err), nil
|
||||
}
|
||||
|
||||
token, err := h.Validate(uToken)
|
||||
|
||||
if err != nil {
|
||||
return h.HandleUnauthorized(resp, err), nil
|
||||
}
|
||||
|
||||
req, err = h.InjectContext(req, token)
|
||||
|
||||
if err != nil {
|
||||
return h.HandleUnauthorized(resp, err), nil
|
||||
}
|
||||
}
|
||||
|
||||
return h.Next.ServeHTTP(resp, req)
|
||||
}
|
||||
|
||||
func (h Auth) InjectContext(req *http.Request, token *jwt.Token) (*http.Request, error) {
|
||||
|
||||
payLoad, ok := token.Claims.(jwt.MapClaims)
|
||||
|
||||
if !ok {
|
||||
return nil, errors.New("invalid payload")
|
||||
}
|
||||
|
||||
for header := range req.Header {
|
||||
if strings.HasPrefix(header, "X-Token-") {
|
||||
req.Header.Del(header)
|
||||
}
|
||||
}
|
||||
|
||||
username, ok := payLoad["username"].(string)
|
||||
|
||||
if ok && username != "" {
|
||||
req.Header.Set("X-Token-Username", username)
|
||||
}
|
||||
|
||||
uid := payLoad["uid"]
|
||||
|
||||
if uid != nil {
|
||||
switch uid.(type) {
|
||||
case int:
|
||||
req.Header.Set("X-Token-UID", strconv.Itoa(uid.(int)))
|
||||
break
|
||||
case string:
|
||||
req.Header.Set("X-Token-UID", uid.(string))
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
groups, ok := payLoad["groups"].([]string)
|
||||
|
||||
if ok && len(groups) > 0 {
|
||||
req.Header.Set("X-Token-Groups", strings.Join(groups, ","))
|
||||
}
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func (h Auth) Validate(uToken string) (*jwt.Token, error) {
|
||||
|
||||
if len(uToken) == 0 {
|
||||
return nil, fmt.Errorf("token length is zero")
|
||||
}
|
||||
|
||||
token, err := jwt.Parse(uToken, h.ProvideKey)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return token, nil
|
||||
}
|
||||
|
||||
func (h Auth) HandleUnauthorized(w http.ResponseWriter, err error) int {
|
||||
message := fmt.Sprintf("Unauthorized,%v", err)
|
||||
w.Header().Add("WWW-Authenticate", message)
|
||||
return http.StatusUnauthorized
|
||||
}
|
||||
|
||||
func (h Auth) ExtractToken(r *http.Request) (string, error) {
|
||||
|
||||
jwtHeader := strings.Split(r.Header.Get("Authorization"), " ")
|
||||
|
||||
if jwtHeader[0] == "Bearer" && len(jwtHeader) == 2 {
|
||||
return jwtHeader[1], nil
|
||||
}
|
||||
|
||||
jwtCookie, err := r.Cookie("token")
|
||||
|
||||
if err == nil {
|
||||
return jwtCookie.Value, nil
|
||||
}
|
||||
|
||||
jwtQuery := r.URL.Query().Get("token")
|
||||
|
||||
if jwtQuery != "" {
|
||||
return jwtQuery, nil
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("no token found")
|
||||
}
|
||||
|
||||
func (h Auth) ProvideKey(token *jwt.Token) (interface{}, error) {
|
||||
if _, ok := token.Method.(*jwt.SigningMethodHMAC); ok {
|
||||
return h.Rule.Secret, nil
|
||||
} else {
|
||||
return nil, fmt.Errorf("expect token signed with HMAC but got %v", token.Header["alg"])
|
||||
}
|
||||
}
|
||||
110
pkg/apigateway/caddy-plugin/authenticate/auto_load.go
Normal file
110
pkg/apigateway/caddy-plugin/authenticate/auto_load.go
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
|
||||
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 authenticate
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/mholt/caddy"
|
||||
"github.com/mholt/caddy/caddyhttp/httpserver"
|
||||
)
|
||||
|
||||
func init() {
|
||||
caddy.RegisterPlugin("authenticate", caddy.Plugin{
|
||||
ServerType: "http",
|
||||
Action: Setup,
|
||||
})
|
||||
}
|
||||
|
||||
func Setup(c *caddy.Controller) error {
|
||||
|
||||
rule, err := parse(c)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.OnStartup(func() error {
|
||||
fmt.Println("Authenticate middleware is initiated")
|
||||
return nil
|
||||
})
|
||||
|
||||
httpserver.GetConfig(c).AddMiddleware(func(next httpserver.Handler) httpserver.Handler {
|
||||
return &Auth{Next: next, Rule: rule}
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
func parse(c *caddy.Controller) (Rule, error) {
|
||||
|
||||
rule := Rule{ExceptedPath: make([]string, 0)}
|
||||
|
||||
if c.Next() {
|
||||
args := c.RemainingArgs()
|
||||
switch len(args) {
|
||||
case 0:
|
||||
for c.NextBlock() {
|
||||
switch c.Val() {
|
||||
case "path":
|
||||
if !c.NextArg() {
|
||||
return rule, c.ArgErr()
|
||||
}
|
||||
|
||||
rule.Path = c.Val()
|
||||
|
||||
if c.NextArg() {
|
||||
return rule, c.ArgErr()
|
||||
}
|
||||
case "secret":
|
||||
if !c.NextArg() {
|
||||
return rule, c.ArgErr()
|
||||
}
|
||||
|
||||
rule.Secret = []byte(c.Val())
|
||||
|
||||
if c.NextArg() {
|
||||
return rule, c.ArgErr()
|
||||
}
|
||||
case "except":
|
||||
if !c.NextArg() {
|
||||
return rule, c.ArgErr()
|
||||
}
|
||||
|
||||
rule.ExceptedPath = strings.Split(c.Val(), ",")
|
||||
|
||||
for i := 0; i < len(rule.ExceptedPath); i++ {
|
||||
rule.ExceptedPath[i] = strings.TrimSpace(rule.ExceptedPath[i])
|
||||
}
|
||||
|
||||
if c.NextArg() {
|
||||
return rule, c.ArgErr()
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
return rule, c.ArgErr()
|
||||
}
|
||||
}
|
||||
|
||||
if c.Next() {
|
||||
return rule, c.ArgErr()
|
||||
}
|
||||
|
||||
return rule, nil
|
||||
}
|
||||
300
pkg/apigateway/caddy-plugin/authentication/authentication.go
Normal file
300
pkg/apigateway/caddy-plugin/authentication/authentication.go
Normal file
@@ -0,0 +1,300 @@
|
||||
/*
|
||||
|
||||
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 authentication
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||
"k8s.io/apiserver/pkg/endpoints/request"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/mholt/caddy/caddyhttp/httpserver"
|
||||
"k8s.io/api/rbac/v1"
|
||||
k8serr "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/kubernetes/pkg/util/slice"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
sliceutils "kubesphere.io/kubesphere/pkg/utils"
|
||||
)
|
||||
|
||||
type Authentication struct {
|
||||
Rule Rule
|
||||
Next httpserver.Handler
|
||||
}
|
||||
|
||||
type Rule struct {
|
||||
Path string
|
||||
ExceptedPath []string
|
||||
}
|
||||
|
||||
func (c Authentication) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
|
||||
|
||||
if httpserver.Path(r.URL.Path).Matches(c.Rule.Path) {
|
||||
|
||||
for _, path := range c.Rule.ExceptedPath {
|
||||
if httpserver.Path(r.URL.Path).Matches(path) {
|
||||
return c.Next.ServeHTTP(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
attrs, err := getAuthorizerAttributes(r.Context())
|
||||
|
||||
if err != nil {
|
||||
return http.StatusInternalServerError, err
|
||||
}
|
||||
|
||||
permitted, err := permissionValidate(attrs)
|
||||
|
||||
if err != nil {
|
||||
return http.StatusInternalServerError, err
|
||||
}
|
||||
|
||||
if !permitted {
|
||||
err = k8serr.NewForbidden(schema.GroupResource{Group: attrs.GetAPIGroup(), Resource: attrs.GetResource()}, attrs.GetName(), fmt.Errorf("permission undefined"))
|
||||
return handleForbidden(w, err), nil
|
||||
}
|
||||
}
|
||||
|
||||
return c.Next.ServeHTTP(w, r)
|
||||
|
||||
}
|
||||
|
||||
func handleForbidden(w http.ResponseWriter, err error) int {
|
||||
message := fmt.Sprintf("Forbidden,%s", err.Error())
|
||||
w.Header().Add("WWW-Authenticate", message)
|
||||
return http.StatusForbidden
|
||||
}
|
||||
|
||||
func permissionValidate(attrs authorizer.Attributes) (bool, error) {
|
||||
|
||||
permitted, err := clusterRoleValidate(attrs)
|
||||
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if permitted {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
if attrs.GetNamespace() != "" {
|
||||
permitted, err = roleValidate(attrs)
|
||||
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if permitted {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func roleValidate(attrs authorizer.Attributes) (bool, error) {
|
||||
roleBindingLister := informers.SharedInformerFactory().Rbac().V1().RoleBindings().Lister()
|
||||
roleLister := informers.SharedInformerFactory().Rbac().V1().Roles().Lister()
|
||||
roleBindings, err := roleBindingLister.RoleBindings(attrs.GetNamespace()).List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
fullSource := attrs.GetResource()
|
||||
|
||||
if attrs.GetSubresource() != "" {
|
||||
fullSource = fullSource + "/" + attrs.GetSubresource()
|
||||
}
|
||||
|
||||
for _, roleBinding := range roleBindings {
|
||||
|
||||
for _, subj := range roleBinding.Subjects {
|
||||
|
||||
if (subj.Kind == v1.UserKind && subj.Name == attrs.GetUser().GetName()) ||
|
||||
(subj.Kind == v1.GroupKind && slice.ContainsString(attrs.GetUser().GetGroups(), subj.Name, nil)) {
|
||||
role, err := roleLister.Roles(attrs.GetNamespace()).Get(roleBinding.RoleRef.Name)
|
||||
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
for _, rule := range role.Rules {
|
||||
if ruleMatchesRequest(rule, attrs.GetAPIGroup(), "", attrs.GetResource(), attrs.GetSubresource(), attrs.GetName(), attrs.GetVerb()) {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func clusterRoleValidate(attrs authorizer.Attributes) (bool, error) {
|
||||
clusterRoleBindingLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoleBindings().Lister()
|
||||
clusterRoleBindings, err := clusterRoleBindingLister.List(labels.Everything())
|
||||
clusterRoleLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoles().Lister()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
for _, clusterRoleBinding := range clusterRoleBindings {
|
||||
|
||||
for _, subject := range clusterRoleBinding.Subjects {
|
||||
|
||||
if (subject.Kind == v1.UserKind && subject.Name == attrs.GetUser().GetName()) ||
|
||||
(subject.Kind == v1.GroupKind && sliceutils.HasString(attrs.GetUser().GetGroups(), subject.Name)) {
|
||||
|
||||
clusterRole, err := clusterRoleLister.Get(clusterRoleBinding.RoleRef.Name)
|
||||
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
for _, rule := range clusterRole.Rules {
|
||||
if attrs.IsResourceRequest() {
|
||||
if ruleMatchesRequest(rule, attrs.GetAPIGroup(), "", attrs.GetResource(), attrs.GetSubresource(), attrs.GetName(), attrs.GetVerb()) {
|
||||
return true, nil
|
||||
}
|
||||
} else {
|
||||
if ruleMatchesRequest(rule, "", attrs.GetPath(), "", "", "", attrs.GetVerb()) {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func ruleMatchesResources(rule v1.PolicyRule, apiGroup string, resource string, subresource string, resourceName string) bool {
|
||||
|
||||
if resource == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
if !sliceutils.HasString(rule.APIGroups, apiGroup) && !sliceutils.HasString(rule.APIGroups, v1.ResourceAll) {
|
||||
return false
|
||||
}
|
||||
|
||||
if len(rule.ResourceNames) > 0 && !sliceutils.HasString(rule.ResourceNames, resourceName) {
|
||||
return false
|
||||
}
|
||||
|
||||
combinedResource := resource
|
||||
|
||||
if subresource != "" {
|
||||
combinedResource = combinedResource + "/" + subresource
|
||||
}
|
||||
|
||||
for _, res := range rule.Resources {
|
||||
|
||||
// match "*"
|
||||
if res == v1.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 v1.PolicyRule, apiGroup string, nonResourceURL string, resource string, subresource string, resourceName string, verb string) bool {
|
||||
|
||||
if !sliceutils.HasString(rule.Verbs, verb) && !sliceutils.HasString(rule.Verbs, v1.VerbAll) {
|
||||
return false
|
||||
}
|
||||
|
||||
if nonResourceURL == "" {
|
||||
return ruleMatchesResources(rule, apiGroup, resource, subresource, resourceName)
|
||||
} else {
|
||||
return ruleMatchesNonResource(rule, nonResourceURL)
|
||||
}
|
||||
}
|
||||
|
||||
func ruleMatchesNonResource(rule v1.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 {
|
||||
if spec == "*" {
|
||||
return true
|
||||
}
|
||||
if spec == path {
|
||||
return true
|
||||
}
|
||||
if strings.HasSuffix(spec, "*") && strings.HasPrefix(path, strings.TrimRight(spec, "*")) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func getAuthorizerAttributes(ctx request.Context) (authorizer.Attributes, error) {
|
||||
attribs := authorizer.AttributesRecord{}
|
||||
|
||||
user, ok := request.UserFrom(ctx)
|
||||
if ok {
|
||||
attribs.User = user
|
||||
}
|
||||
|
||||
requestInfo, found := request.RequestInfoFrom(ctx)
|
||||
if !found {
|
||||
return nil, errors.New("no RequestInfo found in the context")
|
||||
}
|
||||
|
||||
// Start with common attributes that apply to resource and non-resource requests
|
||||
attribs.ResourceRequest = requestInfo.IsResourceRequest
|
||||
attribs.Path = requestInfo.Path
|
||||
attribs.Verb = requestInfo.Verb
|
||||
|
||||
attribs.APIGroup = requestInfo.APIGroup
|
||||
attribs.APIVersion = requestInfo.APIVersion
|
||||
attribs.Resource = requestInfo.Resource
|
||||
attribs.Subresource = requestInfo.Subresource
|
||||
attribs.Namespace = requestInfo.Namespace
|
||||
attribs.Name = requestInfo.Name
|
||||
|
||||
return &attribs, nil
|
||||
}
|
||||
119
pkg/apigateway/caddy-plugin/authentication/auto_load.go
Normal file
119
pkg/apigateway/caddy-plugin/authentication/auto_load.go
Normal file
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
|
||||
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 authentication
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/mholt/caddy"
|
||||
"github.com/mholt/caddy/caddyhttp/httpserver"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/signals"
|
||||
)
|
||||
|
||||
func init() {
|
||||
caddy.RegisterPlugin("authentication", caddy.Plugin{
|
||||
ServerType: "http",
|
||||
Action: Setup,
|
||||
})
|
||||
}
|
||||
|
||||
// Setup is called by Caddy to parse the config block
|
||||
func Setup(c *caddy.Controller) error {
|
||||
|
||||
rule, err := parse(c)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.OnStartup(func() error {
|
||||
stopChan := signals.SetupSignalHandler()
|
||||
informers.SharedInformerFactory().Start(stopChan)
|
||||
informers.SharedInformerFactory().WaitForCacheSync(stopChan)
|
||||
fmt.Println("Authentication middleware is initiated")
|
||||
return nil
|
||||
})
|
||||
|
||||
httpserver.GetConfig(c).AddMiddleware(func(next httpserver.Handler) httpserver.Handler {
|
||||
return &Authentication{Next: next, Rule: rule}
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func parse(c *caddy.Controller) (Rule, error) {
|
||||
|
||||
rule := Rule{ExceptedPath: make([]string, 0)}
|
||||
|
||||
if c.Next() {
|
||||
args := c.RemainingArgs()
|
||||
switch len(args) {
|
||||
case 0:
|
||||
for c.NextBlock() {
|
||||
switch c.Val() {
|
||||
case "path":
|
||||
if !c.NextArg() {
|
||||
return rule, c.ArgErr()
|
||||
}
|
||||
|
||||
rule.Path = c.Val()
|
||||
|
||||
if c.NextArg() {
|
||||
return rule, c.ArgErr()
|
||||
}
|
||||
|
||||
break
|
||||
case "except":
|
||||
if !c.NextArg() {
|
||||
return rule, c.ArgErr()
|
||||
}
|
||||
|
||||
rule.ExceptedPath = strings.Split(c.Val(), ",")
|
||||
|
||||
for i := 0; i < len(rule.ExceptedPath); i++ {
|
||||
rule.ExceptedPath[i] = strings.TrimSpace(rule.ExceptedPath[i])
|
||||
}
|
||||
|
||||
if c.NextArg() {
|
||||
return rule, c.ArgErr()
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
case 1:
|
||||
rule.Path = args[0]
|
||||
if c.NextBlock() {
|
||||
return rule, c.ArgErr()
|
||||
}
|
||||
default:
|
||||
return rule, c.ArgErr()
|
||||
}
|
||||
}
|
||||
|
||||
if c.Next() {
|
||||
return rule, c.ArgErr()
|
||||
}
|
||||
|
||||
return rule, nil
|
||||
}
|
||||
100
pkg/apigateway/caddy-plugin/swagger/auto_load.go
Normal file
100
pkg/apigateway/caddy-plugin/swagger/auto_load.go
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
|
||||
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 authenticate
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/mholt/caddy"
|
||||
"github.com/mholt/caddy/caddyhttp/httpserver"
|
||||
)
|
||||
|
||||
func init() {
|
||||
caddy.RegisterPlugin("swagger", caddy.Plugin{
|
||||
ServerType: "http",
|
||||
Action: Setup,
|
||||
})
|
||||
}
|
||||
|
||||
func Setup(c *caddy.Controller) error {
|
||||
|
||||
handler, err := parse(c)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.OnStartup(func() error {
|
||||
fmt.Println("Swagger middleware is initiated")
|
||||
return nil
|
||||
})
|
||||
|
||||
httpserver.GetConfig(c).AddMiddleware(func(next httpserver.Handler) httpserver.Handler {
|
||||
return &Swagger{Next: next, Handler: handler}
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
func parse(c *caddy.Controller) (Handler, error) {
|
||||
|
||||
handler := Handler{URL: "/swagger-ui", FilePath: "/var/static/swagger-ui"}
|
||||
|
||||
if c.Next() {
|
||||
args := c.RemainingArgs()
|
||||
switch len(args) {
|
||||
case 0:
|
||||
for c.NextBlock() {
|
||||
switch c.Val() {
|
||||
case "url":
|
||||
if !c.NextArg() {
|
||||
return handler, c.ArgErr()
|
||||
}
|
||||
|
||||
handler.URL = c.Val()
|
||||
|
||||
if c.NextArg() {
|
||||
return handler, c.ArgErr()
|
||||
}
|
||||
case "filePath":
|
||||
if !c.NextArg() {
|
||||
return handler, c.ArgErr()
|
||||
}
|
||||
|
||||
handler.FilePath = c.Val()
|
||||
|
||||
if c.NextArg() {
|
||||
return handler, c.ArgErr()
|
||||
}
|
||||
default:
|
||||
return handler, c.ArgErr()
|
||||
}
|
||||
}
|
||||
default:
|
||||
return handler, c.ArgErr()
|
||||
}
|
||||
}
|
||||
|
||||
if c.Next() {
|
||||
return handler, c.ArgErr()
|
||||
}
|
||||
|
||||
handler.Handler = http.StripPrefix(handler.URL, http.FileServer(http.Dir(handler.FilePath)))
|
||||
|
||||
return handler, nil
|
||||
}
|
||||
45
pkg/apigateway/caddy-plugin/swagger/swagger.go
Normal file
45
pkg/apigateway/caddy-plugin/swagger/swagger.go
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
|
||||
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 authenticate
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/mholt/caddy/caddyhttp/httpserver"
|
||||
)
|
||||
|
||||
type Swagger struct {
|
||||
Handler Handler
|
||||
Next httpserver.Handler
|
||||
}
|
||||
|
||||
type Handler struct {
|
||||
URL string
|
||||
FilePath string
|
||||
Handler http.Handler
|
||||
}
|
||||
|
||||
func (h Swagger) ServeHTTP(resp http.ResponseWriter, req *http.Request) (int, error) {
|
||||
|
||||
if httpserver.Path(req.URL.Path).Matches(h.Handler.URL) {
|
||||
h.Handler.Handler.ServeHTTP(resp, req)
|
||||
return http.StatusOK, nil
|
||||
}
|
||||
|
||||
return h.Next.ServeHTTP(resp, req)
|
||||
}
|
||||
@@ -15,17 +15,19 @@
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
package monitoring
|
||||
package install
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/monitoring/v1alpha2"
|
||||
urlruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
iamv1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
||||
)
|
||||
|
||||
const apiGroup = "monitoring.kubesphere.io"
|
||||
|
||||
func AddToContainer(container *restful.Container) error {
|
||||
container.Add(v1alpha2.WebService(apiGroup))
|
||||
return nil
|
||||
func init() {
|
||||
Install(runtime.Container)
|
||||
}
|
||||
|
||||
func Install(container *restful.Container) {
|
||||
urlruntime.Must(iamv1alpha2.AddToContainer(container))
|
||||
}
|
||||
214
pkg/apis/iam/v1alpha2/register.go
Normal file
214
pkg/apis/iam/v1alpha2/register.go
Normal file
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
|
||||
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 v1alpha2
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"github.com/emicklei/go-restful-openapi"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/iam"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
)
|
||||
|
||||
const GroupName = "iam.kubesphere.io"
|
||||
|
||||
var GroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha2"}
|
||||
|
||||
var (
|
||||
WebServiceBuilder = runtime.NewContainerBuilder(addWebService)
|
||||
AddToContainer = WebServiceBuilder.AddToContainer
|
||||
)
|
||||
|
||||
func addWebService(c *restful.Container) error {
|
||||
tags := []string{"IAM"}
|
||||
ws := runtime.NewWebService(GroupVersion)
|
||||
|
||||
ws.Route(ws.POST("/authenticate").
|
||||
To(iam.TokenReviewHandler).
|
||||
Doc("Token review").
|
||||
Reads(iam.TokenReview{}).
|
||||
Writes(iam.TokenReview{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
ws.Route(ws.POST("/login").
|
||||
To(iam.LoginHandler).
|
||||
Doc("User login").
|
||||
Reads(iam.LoginRequest{}).
|
||||
Writes(models.Token{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
|
||||
ws.Route(ws.GET("/users/{name}").
|
||||
To(iam.UserDetail).
|
||||
Doc("User detail").
|
||||
Writes(models.User{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
ws.Route(ws.POST("/users").
|
||||
To(iam.CreateUser).
|
||||
Reads(models.User{}).
|
||||
Writes(errors.Error{}).
|
||||
Doc("Create user").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
ws.Route(ws.DELETE("/users/{name}").
|
||||
To(iam.DeleteUser).
|
||||
Doc("Delete user").
|
||||
Writes(errors.Error{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
ws.Route(ws.PUT("/users/{name}").
|
||||
To(iam.UpdateUser).
|
||||
Reads(models.User{}).
|
||||
Writes(errors.Error{}).
|
||||
Doc("Update user").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
|
||||
ws.Route(ws.GET("/users/{name}/log").
|
||||
To(iam.UserLoginLog).
|
||||
Doc("User login log").
|
||||
Writes([]map[string]string{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
ws.Route(ws.GET("/users").
|
||||
To(iam.UserList).
|
||||
Doc("User list").
|
||||
Writes(models.PageableResponse{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
ws.Route(ws.GET("/groups").
|
||||
To(iam.RootGroupList).
|
||||
Writes([]models.Group{}).
|
||||
Doc("User group list").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
|
||||
ws.Route(ws.GET("/groups/{path}").
|
||||
To(iam.GroupDetail).
|
||||
Doc("User group detail").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
ws.Route(ws.GET("/groups/{path}/users").
|
||||
To(iam.GroupUsers).
|
||||
Doc("Group user list").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
ws.Route(ws.POST("/groups").
|
||||
To(iam.CreateGroup).
|
||||
Reads(models.Group{}).
|
||||
Doc("Create user group").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
ws.Route(ws.DELETE("/groups/{path}").
|
||||
To(iam.DeleteGroup).
|
||||
Doc("Delete user group").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
ws.Route(ws.PUT("/groups/{path}").
|
||||
To(iam.UpdateGroup).
|
||||
Doc("Update user group").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
ws.Route(ws.GET("/users/{username}/roles").
|
||||
To(iam.UserRoles).
|
||||
Doc("Get user role list").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/roles/{role}/users").
|
||||
To(iam.RoleUsers).
|
||||
Doc("Get user list by role").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/roles/{role}/rules").
|
||||
To(iam.RoleRules).
|
||||
Doc("Get role detail").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/users").
|
||||
To(iam.NamespaceUsers).
|
||||
Doc("Get user list by namespace").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
ws.Route(ws.GET("/clusterroles/{clusterrole}/users").
|
||||
To(iam.ClusterRoleUsers).
|
||||
Doc("Get user list by cluster role").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
ws.Route(ws.GET("/clusterroles/{clusterrole}/rules").
|
||||
To(iam.ClusterRoleRules).
|
||||
Doc("Get cluster role detail").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
ws.Route(ws.GET("/rulesmapping/clusterroles").
|
||||
To(iam.ClusterRulesMappingHandler).
|
||||
Doc("Get cluster role policy rules mapping").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
ws.Route(ws.GET("/rulesmapping/roles").
|
||||
To(iam.RulesMappingHandler).
|
||||
Doc("Get role policy rules mapping").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
|
||||
ws.Route(ws.GET("/workspaces/{workspace}/rules").
|
||||
To(iam.WorkspaceRulesHandler).
|
||||
Doc("Get workspace level policy rules").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
ws.Route(ws.GET("/workspaces/{workspace}/members").
|
||||
To(iam.WorkspaceMemberList).
|
||||
Doc("Get workspace member list").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/rules").
|
||||
To(iam.NamespacesRulesHandler).
|
||||
Doc("Get namespace level policy rules").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
ws.Route(ws.GET("/devops/{devops}/rules").
|
||||
To(iam.DevopsRulesHandler).
|
||||
Doc("Get devops project level policy rules").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
|
||||
tags = []string{"Workspace"}
|
||||
|
||||
ws.Route(ws.GET("/workspaces").
|
||||
To(iam.UserWorkspaceListHandler).
|
||||
Doc("Get workspace list").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Writes([]models.Workspace{}))
|
||||
ws.Route(ws.POST("/workspaces").
|
||||
To(iam.WorkspaceCreateHandler).
|
||||
Doc("Create workspace").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Writes(models.Workspace{}))
|
||||
ws.Route(ws.DELETE("/workspaces/{name}").
|
||||
To(iam.DeleteWorkspaceHandler).
|
||||
Doc("Delete workspace").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Writes(errors.Error{}))
|
||||
ws.Route(ws.GET("/workspaces/{name}").
|
||||
To(iam.WorkspaceDetailHandler).
|
||||
Doc("Get workspace detail").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Writes(models.Workspace{}))
|
||||
ws.Route(ws.PUT("/workspaces/{name}").
|
||||
To(iam.WorkspaceEditHandler).
|
||||
Doc("Update workspace").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Writes(models.Workspace{}))
|
||||
|
||||
ws.Route(ws.GET("/workspaces/{name}/members/{member}").
|
||||
To(iam.WorkspaceMemberDetail).
|
||||
Doc("Get workspace member detail").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
ws.Route(ws.GET("/workspaces/{name}/roles").
|
||||
To(iam.WorkspaceRoles).
|
||||
Doc("Get workspace roles").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
|
||||
ws.Route(ws.POST("/workspaces/{name}/members").
|
||||
To(iam.WorkspaceMemberInvite).
|
||||
Doc("Add user to workspace").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
ws.Route(ws.DELETE("/workspaces/{name}/members").
|
||||
To(iam.WorkspaceMemberRemove).
|
||||
Doc("Delete user from workspace").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
|
||||
c.Add(ws)
|
||||
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 metrics
|
||||
@@ -19,6 +19,7 @@ package v1alpha2
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"github.com/emicklei/go-restful-openapi"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/metrics"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
||||
@@ -36,8 +37,20 @@ var (
|
||||
func addWebService(c *restful.Container) error {
|
||||
webservice := runtime.NewWebService(GroupVersion)
|
||||
|
||||
webservice.Route(webservice.GET("/storageclasses/{storageclass}").To(metrics.GetScMetrics))
|
||||
webservice.Route(webservice.GET("/metrics/storageclass").To(metrics.GetScMetricsList))
|
||||
tags := []string{"metrics"}
|
||||
|
||||
webservice.Route(webservice.GET("/storageclasses/{storageclass}").
|
||||
To(metrics.GetScMetrics).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Doc("").
|
||||
Param(webservice.PathParameter("storageclass", "storageclass's name")).
|
||||
Writes(metrics.ScMetricsItem{}))
|
||||
|
||||
webservice.Route(webservice.GET("/storageclasses").
|
||||
To(metrics.GetScMetricsList).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Doc("").
|
||||
Writes([]metrics.ScMetricsItem{}))
|
||||
|
||||
c.Add(webservice)
|
||||
|
||||
|
||||
@@ -15,22 +15,19 @@
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
package v1alpha2
|
||||
package install
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
urlruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
monitoringv1alpha2 "kubesphere.io/kubesphere/pkg/apis/monitoring/v1alpha2"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
||||
)
|
||||
|
||||
const apiVersion = "v1alpha2"
|
||||
|
||||
var addToWebServiceFuncs []func(ws *restful.WebService)
|
||||
|
||||
func WebService(apiGroup string) *restful.WebService {
|
||||
ws := new(restful.WebService)
|
||||
ws.Path("/apis/" + apiGroup + "/" + apiVersion).
|
||||
Produces(restful.MIME_JSON).Consumes(restful.MIME_JSON)
|
||||
for _, f := range addToWebServiceFuncs {
|
||||
f(ws)
|
||||
}
|
||||
return ws
|
||||
func init() {
|
||||
Install(runtime.Container)
|
||||
}
|
||||
|
||||
func Install(container *restful.Container) {
|
||||
urlruntime.Must(monitoringv1alpha2.AddToContainer(container))
|
||||
}
|
||||
207
pkg/apis/monitoring/v1alpha2/register.go
Normal file
207
pkg/apis/monitoring/v1alpha2/register.go
Normal file
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
|
||||
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 v1alpha2
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"github.com/emicklei/go-restful-openapi"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/monitoring"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
||||
)
|
||||
|
||||
const GroupName = "monitoring.kubesphere.io"
|
||||
|
||||
var GroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha2"}
|
||||
|
||||
var (
|
||||
WebServiceBuilder = runtime.NewContainerBuilder(addWebService)
|
||||
AddToContainer = WebServiceBuilder.AddToContainer
|
||||
)
|
||||
|
||||
func addWebService(c *restful.Container) error {
|
||||
ws := runtime.NewWebService(GroupVersion)
|
||||
|
||||
tags := []string{"Monitoring"}
|
||||
|
||||
ws.Route(ws.GET("/clusters").To(monitoring.MonitorCluster).
|
||||
Doc("monitor cluster level metrics").
|
||||
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...in re2 regex").Required(false).DefaultValue("cluster_cpu_utilisation")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
|
||||
ws.Route(ws.GET("/nodes").To(monitoring.MonitorNode).
|
||||
Doc("monitor nodes level metrics").
|
||||
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...in re2 regex").Required(false).DefaultValue("node_cpu_utilisation")).
|
||||
Param(ws.QueryParameter("nodes_filter", "node re2 expression filter").Required(false).DefaultValue("")).
|
||||
Param(ws.QueryParameter("sort_metric", "sort metric").Required(false)).
|
||||
Param(ws.QueryParameter("sort_type", "ascending descending order").Required(false)).
|
||||
Param(ws.QueryParameter("page", "page number").Required(false).DefaultValue("1")).
|
||||
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").Required(false).DefaultValue("4")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
|
||||
ws.Route(ws.GET("/nodes/{node}").To(monitoring.MonitorNode).
|
||||
Doc("monitor specific node level metrics").
|
||||
Param(ws.PathParameter("node", "specific node").Required(true).DefaultValue("")).
|
||||
Param(ws.QueryParameter("metrics_name", "metrics name cpu memory...").Required(true).DefaultValue("node_cpu_utilisation")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
|
||||
ws.Route(ws.GET("/namespaces").To(monitoring.MonitorNamespace).
|
||||
Doc("monitor namespaces level metrics").
|
||||
Param(ws.QueryParameter("namespaces_filter", "namespaces re2 expression filter").Required(false).DefaultValue("")).
|
||||
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...in re2 regex").Required(false).DefaultValue("namespace_memory_utilisation")).
|
||||
Param(ws.QueryParameter("sort_metric", "sort metric").Required(false)).
|
||||
Param(ws.QueryParameter("sort_type", "ascending descending order").Required(false)).
|
||||
Param(ws.QueryParameter("page", "page number").Required(false).DefaultValue("1")).
|
||||
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").Required(false).DefaultValue("4")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
|
||||
ws.Route(ws.GET("/namespaces/{namespace}").To(monitoring.MonitorNamespace).
|
||||
Doc("monitor specific namespace level metrics").
|
||||
Param(ws.PathParameter("namespace", "specific namespace").Required(true).DefaultValue("monitoring")).
|
||||
Param(ws.QueryParameter("metrics_name", "metrics name cpu memory...").Required(true).DefaultValue("namespace_memory_utilisation")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/pods").To(monitoring.MonitorPod).
|
||||
Doc("monitor pods level metrics").
|
||||
Param(ws.PathParameter("namespace", "specific namespace").Required(true).DefaultValue("monitoring")).
|
||||
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...in re2 regex").Required(false).DefaultValue("pod_memory_utilisation_wo_cache")).
|
||||
Param(ws.QueryParameter("pods_filter", "pod re2 expression filter").Required(false).DefaultValue("")).
|
||||
Param(ws.QueryParameter("sort_metric", "sort metric").Required(false)).
|
||||
Param(ws.QueryParameter("sort_type", "ascending descending order").Required(false)).
|
||||
Param(ws.QueryParameter("page", "page number").Required(false).DefaultValue("1")).
|
||||
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").Required(false).DefaultValue("4")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/pods/{pod}").To(monitoring.MonitorPod).
|
||||
Doc("monitor specific pod level metrics").
|
||||
Param(ws.PathParameter("namespace", "specific namespace").Required(true).DefaultValue("monitoring")).
|
||||
Param(ws.PathParameter("pod", "specific pod").Required(true).DefaultValue("")).
|
||||
Param(ws.QueryParameter("metrics_name", "metrics name cpu memory...").Required(true).DefaultValue("pod_memory_utilisation_wo_cache")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
|
||||
ws.Route(ws.GET("/nodes/{node}/pods").To(monitoring.MonitorPod).
|
||||
Doc("monitor pods level metrics by nodeid").
|
||||
Param(ws.PathParameter("node", "specific node").Required(true).DefaultValue("i-k89a62il")).
|
||||
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...in re2 regex").Required(false).DefaultValue("pod_memory_utilisation_wo_cache")).
|
||||
Param(ws.QueryParameter("pods_filter", "pod re2 expression filter").Required(false).DefaultValue("openpitrix.*")).
|
||||
Param(ws.QueryParameter("sort_metric", "sort metric").Required(false)).
|
||||
Param(ws.QueryParameter("sort_type", "ascending descending order").Required(false)).
|
||||
Param(ws.QueryParameter("page", "page number").Required(false).DefaultValue("1")).
|
||||
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").Required(false).DefaultValue("4")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
|
||||
ws.Route(ws.GET("/nodes/{node}/pods/{pod}").To(monitoring.MonitorPod).
|
||||
Doc("monitor specific pod level metrics by nodeid").
|
||||
Param(ws.PathParameter("node", "specific node").Required(true).DefaultValue("i-k89a62il")).
|
||||
Param(ws.PathParameter("pod", "specific pod").Required(true).DefaultValue("")).
|
||||
Param(ws.QueryParameter("metrics_name", "metrics name cpu memory...").Required(true).DefaultValue("pod_memory_utilisation_wo_cache")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
|
||||
ws.Route(ws.GET("/nodes/{node}/pods/{pod}/containers").To(monitoring.MonitorContainer).
|
||||
Doc("monitor specific pod level metrics by nodeid").
|
||||
Param(ws.PathParameter("node", "specific node").Required(true)).
|
||||
Param(ws.PathParameter("pod", "specific pod").Required(true)).
|
||||
Param(ws.QueryParameter("containers_filter", "container re2 expression filter").Required(false).DefaultValue("")).
|
||||
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...").Required(false)).
|
||||
Param(ws.QueryParameter("metrics_name", "metrics name cpu memory...").Required(true).DefaultValue("pod_memory_utilisation_wo_cache")).
|
||||
Param(ws.QueryParameter("sort_metric", "sort metric").Required(false)).
|
||||
Param(ws.QueryParameter("sort_type", "ascending descending order").Required(false)).
|
||||
Param(ws.QueryParameter("page", "page number").Required(false).DefaultValue("1")).
|
||||
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").Required(false).DefaultValue("4")).
|
||||
Param(ws.QueryParameter("type", "rank, statistic").Required(false).DefaultValue("rank")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/pods/{pod}/containers").To(monitoring.MonitorContainer).
|
||||
Doc("monitor containers level metrics").
|
||||
Param(ws.PathParameter("namespace", "specific namespace").Required(true).DefaultValue("monitoring")).
|
||||
Param(ws.PathParameter("pod", "specific pod").Required(true).DefaultValue("")).
|
||||
Param(ws.QueryParameter("containers_filter", "container re2 expression filter").Required(false).DefaultValue("")).
|
||||
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...").Required(false)).
|
||||
Param(ws.QueryParameter("metrics_name", "metrics name cpu memory...").Required(true).DefaultValue("container_memory_utilisation_wo_cache")).
|
||||
Param(ws.QueryParameter("sort_metric", "sort metric").Required(false)).
|
||||
Param(ws.QueryParameter("sort_type", "ascending descending order").Required(false)).
|
||||
Param(ws.QueryParameter("page", "page number").Required(false).DefaultValue("1")).
|
||||
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").Required(false).DefaultValue("4")).
|
||||
Param(ws.QueryParameter("type", "rank, statistic").Required(false).DefaultValue("rank")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/pods/{pod}/containers/{container}").To(monitoring.MonitorContainer).
|
||||
Doc("monitor specific container level metrics").
|
||||
Param(ws.PathParameter("namespace", "specific namespace").Required(true).DefaultValue("monitoring")).
|
||||
Param(ws.PathParameter("pod", "specific pod").Required(true).DefaultValue("")).
|
||||
Param(ws.PathParameter("container", "specific container").Required(true).DefaultValue("")).
|
||||
Param(ws.QueryParameter("metrics_name", "metrics name cpu memory...").Required(true).DefaultValue("container_memory_utilisation_wo_cache")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/workloads/{workload_kind}").To(monitoring.MonitorWorkload).
|
||||
Doc("monitor specific workload level metrics").
|
||||
Param(ws.PathParameter("namespace", "namespace").Required(true).DefaultValue("kube-system")).
|
||||
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...").Required(false)).
|
||||
Param(ws.PathParameter("workload_kind", "workload kind").Required(false).DefaultValue("daemonset")).
|
||||
Param(ws.QueryParameter("workload_name", "workload name").Required(true).DefaultValue("")).
|
||||
Param(ws.QueryParameter("pods_filter", "pod re2 expression filter").Required(false).DefaultValue("openpitrix.*")).
|
||||
Param(ws.QueryParameter("sort_metric", "sort metric").Required(false)).
|
||||
Param(ws.QueryParameter("sort_type", "ascending descending order").Required(false)).
|
||||
Param(ws.QueryParameter("page", "page number").Required(false).DefaultValue("1")).
|
||||
Param(ws.QueryParameter("limit", "max metric items in a page").Required(false).DefaultValue("4")).
|
||||
Param(ws.QueryParameter("type", "rank, statistic").Required(false).DefaultValue("rank")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/workloads").To(monitoring.MonitorWorkload).
|
||||
Doc("monitor all workload level metrics").
|
||||
Param(ws.PathParameter("namespace", "namespace").Required(true).DefaultValue("kube-system")).
|
||||
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...").Required(false)).
|
||||
Param(ws.QueryParameter("workloads_filter", "pod re2 expression filter").Required(false).DefaultValue("")).
|
||||
Param(ws.QueryParameter("sort_metric", "sort metric").Required(false)).
|
||||
Param(ws.QueryParameter("sort_type", "ascending descending order").Required(false)).
|
||||
Param(ws.QueryParameter("page", "page number").Required(false).DefaultValue("1")).
|
||||
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").Required(false).DefaultValue("4")).
|
||||
Param(ws.QueryParameter("type", "rank, statistic").Required(false).DefaultValue("rank")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
|
||||
// list all namespace in this workspace by selected metrics
|
||||
ws.Route(ws.GET("/workspaces/{workspace}").To(monitoring.MonitorOneWorkspace).
|
||||
Doc("monitor workspaces level metrics").
|
||||
Param(ws.PathParameter("workspace", "workspace name").Required(true)).
|
||||
Param(ws.QueryParameter("namespaces_filter", "namespaces filter").Required(false).DefaultValue("k.*")).
|
||||
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...in re2 regex").Required(false).DefaultValue("namespace_memory_utilisation_wo_cache")).
|
||||
Param(ws.QueryParameter("sort_metric", "sort metric").Required(false)).
|
||||
Param(ws.QueryParameter("sort_type", "ascending descending order").Required(false)).
|
||||
Param(ws.QueryParameter("page", "page number").Required(false).DefaultValue("1")).
|
||||
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").Required(false).DefaultValue("4")).
|
||||
Param(ws.QueryParameter("type", "rank, statistic").Required(false).DefaultValue("rank")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
|
||||
ws.Route(ws.GET("/workspaces").To(monitoring.MonitorAllWorkspaces).
|
||||
Doc("monitor workspaces level metrics").
|
||||
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...in re2 regex").Required(false).DefaultValue("workspace_memory_utilisation")).
|
||||
Param(ws.QueryParameter("workspaces_filter", "workspaces re2 expression filter").Required(false).DefaultValue(".*")).
|
||||
Param(ws.QueryParameter("sort_metric", "sort metric").Required(false)).
|
||||
Param(ws.QueryParameter("sort_type", "ascending descending order").Required(false)).
|
||||
Param(ws.QueryParameter("page", "page number").Required(false).DefaultValue("1")).
|
||||
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").Required(false).DefaultValue("4")).
|
||||
Param(ws.QueryParameter("type", "rank, statistic").Required(false).DefaultValue("rank")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
|
||||
ws.Route(ws.GET("/components").To(monitoring.MonitorComponentStatus).
|
||||
Doc("monitor k8s components status").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
|
||||
c.Add(ws)
|
||||
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 operations
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/operations"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
)
|
||||
|
||||
const GroupName = "operations.kubesphere.io"
|
||||
@@ -36,20 +37,24 @@ var (
|
||||
|
||||
func addWebService(c *restful.Container) error {
|
||||
|
||||
tags := []string{"Operations"}
|
||||
|
||||
webservice := runtime.NewWebService(GroupVersion)
|
||||
|
||||
webservice.Route(webservice.POST("/nodes/{node}/drainage").To(operations.DrainNode))
|
||||
webservice.Route(webservice.POST("/nodes/{node}/drainage").
|
||||
To(operations.DrainNode).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Doc("").
|
||||
Param(webservice.PathParameter("node", "node name")).
|
||||
Writes(errors.Error{}))
|
||||
|
||||
webservice.Route(webservice.POST("/namespaces/{namespace}/jobs/{job}").
|
||||
To(operations.RerunJob).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{"jobs"}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Doc("Handle job operation").
|
||||
Param(webservice.PathParameter("job", "job name").
|
||||
DataType("string")).
|
||||
Param(webservice.PathParameter("namespace", "job's namespace").
|
||||
DataType("string")).
|
||||
Param(webservice.QueryParameter("a", "action").
|
||||
DataType("string")).
|
||||
Param(webservice.PathParameter("job", "job name")).
|
||||
Param(webservice.PathParameter("namespace", "job's namespace")).
|
||||
Param(webservice.QueryParameter("a", "action")).
|
||||
Writes(""))
|
||||
|
||||
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 metrics
|
||||
@@ -20,9 +20,20 @@ package v1alpha2
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"github.com/emicklei/go-restful-openapi"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/components"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/quotas"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/registries"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/resources"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/revisions"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/routers"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/workloadstatuses"
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
)
|
||||
|
||||
const GroupName = "resources.kubesphere.io"
|
||||
@@ -38,18 +49,182 @@ func addWebService(c *restful.Container) error {
|
||||
|
||||
webservice := runtime.NewWebService(GroupVersion)
|
||||
|
||||
webservice.Route(webservice.GET("/namespaces/{namespace}/{resources}").To(resources.NamespaceResourceHandler))
|
||||
tags := []string{"Namespace resources"}
|
||||
|
||||
webservice.Route(webservice.GET("/{resources}").To(resources.ClusterResourceHandler))
|
||||
webservice.Route(webservice.GET("/namespaces/{namespace}/{resources}").
|
||||
To(resources.NamespaceResourceHandler).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Doc("Namespace level resource query").
|
||||
Param(webservice.PathParameter("namespace", "which namespace")).
|
||||
Param(webservice.PathParameter("resources", "namespace level resource type")).
|
||||
Param(webservice.QueryParameter(params.ConditionsParam, "query conditions").
|
||||
Required(false).
|
||||
DataFormat("key=%s,key~%s")).
|
||||
Param(webservice.QueryParameter(params.PagingParam, "page").
|
||||
Required(false).
|
||||
DataFormat("limit=%d,page=%d").
|
||||
DefaultValue("limit=10,page=1")).
|
||||
Writes(models.PageableResponse{}))
|
||||
|
||||
webservice.Route(webservice.GET("/storageclasses/{storageclass}/persistentvolumeclaims").To(resources.GetPvcListBySc))
|
||||
webservice.Route(webservice.GET("/namespaces/{namespace}/persistentvolumeclaims/{pvc}/pods").To(resources.GetPodListByPvc))
|
||||
tags = []string{"Cluster resources"}
|
||||
|
||||
tags := []string{"users"}
|
||||
webservice.Route(webservice.GET("/users/{username}/kubectl").Doc("get user's kubectl pod").Param(webservice.PathParameter("username",
|
||||
"username").DataType("string")).Metadata(restfulspec.KeyOpenAPITags, tags).To(resources.GetKubectl))
|
||||
webservice.Route(webservice.GET("/users/{username}/kubeconfig").Doc("get users' kubeconfig").Param(webservice.PathParameter("username",
|
||||
"username").DataType("string")).Metadata(restfulspec.KeyOpenAPITags, tags).To(resources.GetKubeconfig))
|
||||
webservice.Route(webservice.GET("/{resources}").
|
||||
To(resources.ClusterResourceHandler).
|
||||
Writes(models.PageableResponse{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Doc("Cluster level resource query").
|
||||
Param(webservice.PathParameter("resources", "cluster level resource type"))).
|
||||
Param(webservice.QueryParameter(params.ConditionsParam, "query conditions").
|
||||
Required(false).
|
||||
DataFormat("key=value,key~value").
|
||||
DefaultValue("")).
|
||||
Param(webservice.QueryParameter(params.PagingParam, "page").
|
||||
Required(false).
|
||||
DataFormat("limit=%d,page=%d").
|
||||
DefaultValue("limit=10,page=1"))
|
||||
|
||||
webservice.Route(webservice.GET("/storageclasses/{storageclass}/persistentvolumeclaims").
|
||||
To(resources.GetPvcListBySc).
|
||||
Doc("get user's kubectl pod").
|
||||
Param(webservice.PathParameter("username", "username")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
webservice.Route(webservice.GET("/namespaces/{namespace}/persistentvolumeclaims/{pvc}/pods").
|
||||
To(resources.GetPodListByPvc))
|
||||
|
||||
tags = []string{"User resources"}
|
||||
|
||||
webservice.Route(webservice.GET("/users/{username}/kubectl").
|
||||
To(resources.GetKubectl).
|
||||
Doc("get user's kubectl pod").
|
||||
Param(webservice.PathParameter("username", "username")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Writes(models.PodInfo{}))
|
||||
|
||||
webservice.Route(webservice.GET("/users/{username}/kubeconfig").
|
||||
To(resources.GetKubeconfig).
|
||||
Doc("get users' kubeconfig").
|
||||
Param(webservice.PathParameter("username", "username")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
|
||||
tags = []string{"Components"}
|
||||
|
||||
webservice.Route(webservice.GET("/components").
|
||||
To(components.GetComponents).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Doc("").
|
||||
Writes(map[string]models.Component{}))
|
||||
webservice.Route(webservice.GET("/components/{component}").
|
||||
To(components.GetComponentStatus).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Doc("").
|
||||
Param(webservice.PathParameter("component", "component name")).
|
||||
Writes(models.Component{}))
|
||||
webservice.Route(webservice.GET("/health").
|
||||
To(components.GetSystemHealthStatus).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Doc("").
|
||||
Writes(map[string]int{}))
|
||||
|
||||
tags = []string{"Quotas"}
|
||||
|
||||
webservice.Route(webservice.GET("/quotas").
|
||||
To(quotas.GetClusterQuotas).
|
||||
Doc("get whole cluster's resource usage").
|
||||
Writes(models.ResourceQuota{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
|
||||
webservice.Route(webservice.GET("/namespaces/{namespace}/quotas").
|
||||
Doc("get specified namespace's resource quota and usage").
|
||||
Param(webservice.PathParameter("namespace", "namespace's name")).
|
||||
Writes(models.ResourceQuota{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
To(quotas.GetNamespaceQuotas))
|
||||
|
||||
tags = []string{"Registries"}
|
||||
|
||||
webservice.Route(webservice.POST("registries/verify").
|
||||
To(registries.RegistryVerify).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Doc("docker registry verify").
|
||||
Writes(errors.Error{}))
|
||||
|
||||
tags = []string{"Revision"}
|
||||
|
||||
webservice.Route(webservice.GET("/namespaces/{namespace}/daemonsets/{daemonset}/revisions/{revision}").
|
||||
To(revisions.GetDaemonSetRevision).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Doc("Handle daemonset operation").
|
||||
Param(webservice.PathParameter("daemonset", "daemonset's name")).
|
||||
Param(webservice.PathParameter("namespace", "daemonset's namespace")).
|
||||
Param(webservice.PathParameter("revision", "daemonset's revision")).
|
||||
Writes(appsv1.DaemonSet{}))
|
||||
webservice.Route(webservice.GET("/namespaces/{namespace}/deployments/{deployment}/revisions/{revision}").
|
||||
To(revisions.GetDeployRevision).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Doc("Handle deployment operation").
|
||||
Param(webservice.PathParameter("deployment", "deployment's name")).
|
||||
Param(webservice.PathParameter("namespace", "deployment's namespace")).
|
||||
Param(webservice.PathParameter("revision", "deployment's revision")).
|
||||
Writes(appsv1.ReplicaSet{}))
|
||||
webservice.Route(webservice.GET("/namespaces/{namespace}/statefulsets/{statefulset}/revisions/{revision}").
|
||||
To(revisions.GetStatefulSetRevision).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Doc("Handle statefulset operation").
|
||||
Param(webservice.PathParameter("statefulset", "statefulset's name")).
|
||||
Param(webservice.PathParameter("namespace", "statefulset's namespace")).
|
||||
Param(webservice.PathParameter("revision", "statefulset's revision")).
|
||||
Writes(appsv1.StatefulSet{}))
|
||||
|
||||
tags = []string{"Router"}
|
||||
|
||||
webservice.Route(webservice.GET("/routers").
|
||||
To(routers.GetAllRouters).
|
||||
Doc("Get all routers").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Writes(corev1.Service{}))
|
||||
|
||||
webservice.Route(webservice.GET("/users/{username}/routers").
|
||||
To(routers.GetAllRoutersOfUser).
|
||||
Doc("Get routers for user").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Param(webservice.PathParameter("username", "")).
|
||||
Writes(corev1.Service{}))
|
||||
|
||||
webservice.Route(webservice.GET("/namespaces/{namespace}/router").
|
||||
To(routers.GetRouter).
|
||||
Doc("Get router of a specified project").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Param(webservice.PathParameter("namespace", "name of the project")))
|
||||
|
||||
webservice.Route(webservice.DELETE("/namespaces/{namespace}/router").
|
||||
To(routers.DeleteRouter).
|
||||
Doc("Get router of a specified project").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Param(webservice.PathParameter("namespace", "name of the project")))
|
||||
|
||||
webservice.Route(webservice.POST("/namespaces/{namespace}/router").
|
||||
To(routers.CreateRouter).
|
||||
Doc("Create a router for a specified project").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Param(webservice.PathParameter("namespace", "name of the project")))
|
||||
|
||||
webservice.Route(webservice.PUT("/namespaces/{namespace}/router").
|
||||
To(routers.UpdateRouter).
|
||||
Doc("Update a router for a specified project").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Param(webservice.PathParameter("namespace", "name of the project")))
|
||||
|
||||
tags = []string{"WorkloadStatus"}
|
||||
|
||||
webservice.Route(webservice.GET("/workloadstatuses").
|
||||
Doc("get abnormal workloads' count of whole cluster").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
To(workloadstatuses.GetClusterResourceStatus))
|
||||
webservice.Route(webservice.GET("/namespaces/{namespace}/workloadstatuses").
|
||||
Doc("get abnormal workloads' count of specified namespace").
|
||||
Param(webservice.PathParameter("namespace", "the name of namespace")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
To(workloadstatuses.GetNamespacesResourceStatus))
|
||||
|
||||
c.Add(webservice)
|
||||
|
||||
|
||||
@@ -22,18 +22,14 @@ import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
"kubesphere.io/kubesphere/pkg/models/components"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func V1Alpha2(ws *restful.WebService) {
|
||||
ws.Route(ws.GET("/components").To(getComponents))
|
||||
ws.Route(ws.GET("/components/{component}").To(getComponentStatus))
|
||||
ws.Route(ws.GET("/health").To(getSystemHealthStatus))
|
||||
}
|
||||
func GetSystemHealthStatus(request *restful.Request, response *restful.Response) {
|
||||
result, err := components.GetSystemHealthStatus()
|
||||
|
||||
func getSystemHealthStatus(request *restful.Request, response *restful.Response) {
|
||||
result, err := components.GetAllComponentsStatus()
|
||||
|
||||
if errors.HandlerError(err, response) {
|
||||
if err != nil {
|
||||
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -41,12 +37,13 @@ func getSystemHealthStatus(request *restful.Request, response *restful.Response)
|
||||
}
|
||||
|
||||
// get a specific component status
|
||||
func getComponentStatus(request *restful.Request, response *restful.Response) {
|
||||
func GetComponentStatus(request *restful.Request, response *restful.Response) {
|
||||
component := request.PathParameter("component")
|
||||
|
||||
result, err := components.GetComponentStatus(component)
|
||||
|
||||
if errors.HandlerError(err, response) {
|
||||
if err != nil {
|
||||
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -54,11 +51,12 @@ func getComponentStatus(request *restful.Request, response *restful.Response) {
|
||||
}
|
||||
|
||||
// get all componentsHandler
|
||||
func getComponents(request *restful.Request, response *restful.Response) {
|
||||
func GetComponents(request *restful.Request, response *restful.Response) {
|
||||
|
||||
result, err := components.GetAllComponentsStatus()
|
||||
|
||||
if errors.HandlerError(err, response) {
|
||||
if err != nil {
|
||||
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -1,52 +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 hpa
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"github.com/emicklei/go-restful-openapi"
|
||||
"k8s.io/api/autoscaling/v1"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
"kubesphere.io/kubesphere/pkg/models/hpa"
|
||||
)
|
||||
|
||||
func V1Alpha2(ws *restful.WebService) {
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/horizontalpodautoscalers/{horizontalpodautoscaler}").
|
||||
To(getHpa).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{"hpa"}).
|
||||
Doc("get horizontalpodautoscalers").
|
||||
Param(ws.PathParameter("namespace", "horizontalpodautoscalers's namespace").
|
||||
DataType("string")).
|
||||
Param(ws.PathParameter("horizontalpodautoscaler", "horizontalpodautoscaler's name")).
|
||||
Writes(v1.HorizontalPodAutoscaler{}))
|
||||
}
|
||||
|
||||
func getHpa(req *restful.Request, resp *restful.Response) {
|
||||
name := req.PathParameter("horizontalpodautoscaler")
|
||||
namespace := req.PathParameter("namespace")
|
||||
|
||||
result, err := hpa.GetHPA(namespace, name)
|
||||
|
||||
if errors.HandlerError(err, resp) {
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(result)
|
||||
}
|
||||
190
pkg/apiserver/iam/am.go
Normal file
190
pkg/apiserver/iam/am.go
Normal file
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
|
||||
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
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"k8s.io/api/rbac/v1"
|
||||
"net/http"
|
||||
"sort"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam/policy"
|
||||
)
|
||||
|
||||
type roleList struct {
|
||||
ClusterRoles []*v1.ClusterRole `json:"clusterRoles" protobuf:"bytes,2,rep,name=clusterRoles"`
|
||||
Roles []*v1.Role `json:"roles" protobuf:"bytes,2,rep,name=roles"`
|
||||
}
|
||||
|
||||
func RoleRules(req *restful.Request, resp *restful.Response) {
|
||||
namespace := req.PathParameter("namespace")
|
||||
roleName := req.PathParameter("role")
|
||||
|
||||
role, err := iam.GetRole(namespace, roleName)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteError(http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
||||
rules, err := iam.GetRoleSimpleRules([]*v1.Role{role}, namespace)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteError(http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(rules[namespace])
|
||||
}
|
||||
|
||||
func RoleUsers(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 NamespaceUsers(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.Slice(users, func(i, j int) bool {
|
||||
return users[i].Username < users[j].Username
|
||||
})
|
||||
|
||||
resp.WriteAsJson(users)
|
||||
}
|
||||
|
||||
func UserRoles(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
username := req.PathParameter("username")
|
||||
|
||||
roles, err := iam.GetRoles(username, "")
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
clusterRoles, err := iam.GetClusterRoles(username)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
roleList := roleList{}
|
||||
roleList.Roles = roles
|
||||
roleList.ClusterRoles = clusterRoles
|
||||
|
||||
resp.WriteAsJson(roleList)
|
||||
}
|
||||
|
||||
func NamespaceRulesHandler(req *restful.Request, resp *restful.Response) {
|
||||
namespace := req.PathParameter("namespace")
|
||||
username := req.HeaderParameter(constants.UserNameHeader)
|
||||
|
||||
clusterRoles, err := iam.GetClusterRoles(username)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteError(http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
||||
roles, err := iam.GetRoles(username, namespace)
|
||||
if err != nil {
|
||||
resp.WriteError(http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, clusterRole := range clusterRoles {
|
||||
role := new(v1.Role)
|
||||
role.Name = clusterRole.Name
|
||||
role.Labels = clusterRole.Labels
|
||||
role.Namespace = namespace
|
||||
role.Annotations = clusterRole.Annotations
|
||||
role.Kind = "Role"
|
||||
role.Rules = clusterRole.Rules
|
||||
roles = append(roles, role)
|
||||
}
|
||||
|
||||
rules, err := iam.GetRoleSimpleRules(roles, namespace)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteError(http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(rules[namespace])
|
||||
}
|
||||
|
||||
func RulesMappingHandler(req *restful.Request, resp *restful.Response) {
|
||||
rules := policy.RoleRuleMapping
|
||||
resp.WriteAsJson(rules)
|
||||
}
|
||||
|
||||
func ClusterRulesMappingHandler(req *restful.Request, resp *restful.Response) {
|
||||
rules := policy.ClusterRoleRuleMapping
|
||||
resp.WriteAsJson(rules)
|
||||
}
|
||||
|
||||
func ClusterRoleRules(req *restful.Request, resp *restful.Response) {
|
||||
clusterRoleName := req.PathParameter("clusterrole")
|
||||
clusterRole, err := iam.GetClusterRole(clusterRoleName)
|
||||
if err != nil {
|
||||
resp.WriteError(http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
rules, err := iam.GetClusterRoleSimpleRules([]*v1.ClusterRole{clusterRole})
|
||||
if err != nil {
|
||||
resp.WriteError(http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(rules)
|
||||
}
|
||||
|
||||
func ClusterRoleUsers(req *restful.Request, resp *restful.Response) {
|
||||
clusterRoleName := req.PathParameter("clusterrole")
|
||||
|
||||
users, err := iam.ClusterRoleUsers(clusterRoleName)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteError(http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(users)
|
||||
}
|
||||
142
pkg/apiserver/iam/auth.go
Normal file
142
pkg/apiserver/iam/auth.go
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
|
||||
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
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"github.com/emicklei/go-restful"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"net/http"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam"
|
||||
"kubesphere.io/kubesphere/pkg/utils"
|
||||
jwtutils "kubesphere.io/kubesphere/pkg/utils/jwt"
|
||||
)
|
||||
|
||||
type Spec struct {
|
||||
Token string `json:"token"`
|
||||
}
|
||||
|
||||
type Status struct {
|
||||
Authenticated bool `json:"authenticated"`
|
||||
User map[string]interface{} `json:"user,omitempty"`
|
||||
}
|
||||
|
||||
type TokenReview struct {
|
||||
APIVersion string `json:"apiVersion"`
|
||||
Kind string `json:"kind"`
|
||||
Spec *Spec `json:"spec,omitempty"`
|
||||
Status *Status `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
type LoginRequest struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
const (
|
||||
APIVersion = "authentication.k8s.io/v1beta1"
|
||||
KindTokenReview = "TokenReview"
|
||||
)
|
||||
|
||||
func LoginHandler(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.Wrap(fmt.Errorf("incorrect username or password")))
|
||||
return
|
||||
}
|
||||
|
||||
ip := utils.RemoteIp(req.Request)
|
||||
|
||||
token, err := iam.Login(loginRequest.Username, loginRequest.Password, ip)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusUnauthorized, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(models.Token{Token: token})
|
||||
}
|
||||
|
||||
// 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.Wrap(fmt.Errorf("token must not be null")))
|
||||
return
|
||||
}
|
||||
|
||||
uToken := tokenReview.Spec.Token
|
||||
|
||||
token, err := jwtutils.ValidateToken(uToken)
|
||||
|
||||
if err != nil {
|
||||
failed := TokenReview{APIVersion: APIVersion,
|
||||
Kind: KindTokenReview,
|
||||
Status: &Status{
|
||||
Authenticated: false,
|
||||
},
|
||||
}
|
||||
resp.WriteAsJson(failed)
|
||||
return
|
||||
}
|
||||
|
||||
claims := token.Claims.(jwt.MapClaims)
|
||||
|
||||
username := claims["username"].(string)
|
||||
|
||||
conn, err := iam.NewConnection()
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
defer conn.Close()
|
||||
|
||||
user, err := iam.UserDetail(username, conn)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
success := TokenReview{APIVersion: APIVersion,
|
||||
Kind: KindTokenReview,
|
||||
Status: &Status{
|
||||
Authenticated: true,
|
||||
User: map[string]interface{}{"username": user.Username, "uid": user.Username, "groups": user.Groups},
|
||||
},
|
||||
}
|
||||
|
||||
resp.WriteAsJson(success)
|
||||
return
|
||||
}
|
||||
253
pkg/apiserver/iam/groups.go
Normal file
253
pkg/apiserver/iam/groups.go
Normal file
@@ -0,0 +1,253 @@
|
||||
/*
|
||||
|
||||
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
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/emicklei/go-restful"
|
||||
"github.com/go-ldap/ldap"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam"
|
||||
)
|
||||
|
||||
func CreateGroup(req *restful.Request, resp *restful.Response) {
|
||||
//var json map[string]interface{}
|
||||
|
||||
var group models.Group
|
||||
|
||||
err := req.ReadEntity(&group)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if !regexp.MustCompile("[a-z0-9]([-a-z0-9]*[a-z0-9])?").MatchString(group.Name) {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, fmt.Errorf("incalid group name %s", group))
|
||||
return
|
||||
}
|
||||
|
||||
if group.Creator == "" {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, fmt.Errorf("creator should not be null"))
|
||||
return
|
||||
}
|
||||
|
||||
created, err := iam.CreateGroup(group)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(created)
|
||||
}
|
||||
|
||||
func DeleteGroup(req *restful.Request, resp *restful.Response) {
|
||||
path := req.PathParameter("path")
|
||||
|
||||
if path == "" {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("group path must not be null")))
|
||||
return
|
||||
}
|
||||
|
||||
err := iam.DeleteGroup(path)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(errors.None)
|
||||
|
||||
}
|
||||
|
||||
func UpdateGroup(req *restful.Request, resp *restful.Response) {
|
||||
groupPathInPath := req.PathParameter("path")
|
||||
|
||||
var group models.Group
|
||||
|
||||
req.ReadEntity(&group)
|
||||
|
||||
if groupPathInPath != group.Path {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("the path of group (%s) does not match the path on the URL (%s)", group.Path, groupPathInPath)))
|
||||
return
|
||||
}
|
||||
|
||||
edited, err := iam.UpdateGroup(&group)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(edited)
|
||||
|
||||
}
|
||||
|
||||
func GroupDetail(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
path := req.PathParameter("path")
|
||||
|
||||
conn, err := iam.NewConnection()
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
defer conn.Close()
|
||||
|
||||
group, err := iam.GroupDetail(path, conn)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(group)
|
||||
|
||||
}
|
||||
|
||||
func GroupUsers(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
path := req.PathParameter("path")
|
||||
|
||||
conn, err := iam.NewConnection()
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
defer conn.Close()
|
||||
|
||||
group, err := iam.GroupDetail(path, conn)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
users := make([]*models.User, 0)
|
||||
|
||||
modify := false
|
||||
|
||||
for i := 0; i < len(group.Members); i++ {
|
||||
name := group.Members[i]
|
||||
user, err := iam.UserDetail(name, conn)
|
||||
|
||||
if err != nil {
|
||||
if ldap.IsErrorWithCode(err, 32) {
|
||||
group.Members = append(group.Members[:i], group.Members[i+1:]...)
|
||||
i--
|
||||
modify = true
|
||||
continue
|
||||
} else {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
clusterRoles, err := iam.GetClusterRoles(name)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
for i := 0; i < len(clusterRoles); i++ {
|
||||
if clusterRoles[i].Annotations["rbac.authorization.k8s.io/clusterrole"] == "true" {
|
||||
user.ClusterRole = clusterRoles[i].Name
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if group.Path == group.Name {
|
||||
workspaceRole := iam.GetWorkspaceRole(clusterRoles, group.Name)
|
||||
user.WorkspaceRole = workspaceRole
|
||||
}
|
||||
|
||||
users = append(users, user)
|
||||
}
|
||||
|
||||
if modify {
|
||||
go iam.UpdateGroup(group)
|
||||
}
|
||||
|
||||
resp.WriteAsJson(users)
|
||||
|
||||
}
|
||||
|
||||
func CountHandler(req *restful.Request, resp *restful.Response) {
|
||||
count, err := iam.CountChild("")
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(map[string]int{"total_count": count})
|
||||
}
|
||||
|
||||
func RootGroupList(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
array := req.QueryParameter("path")
|
||||
|
||||
if array == "" {
|
||||
groups, err := iam.ChildList("")
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(groups)
|
||||
} else {
|
||||
paths := strings.Split(array, ",")
|
||||
|
||||
groups := make([]*models.Group, 0)
|
||||
|
||||
conn, err := iam.NewConnection()
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
defer conn.Close()
|
||||
|
||||
for _, v := range paths {
|
||||
path := strings.TrimSpace(v)
|
||||
group, err := iam.GroupDetail(path, conn)
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
groups = append(groups, group)
|
||||
}
|
||||
|
||||
resp.WriteAsJson(groups)
|
||||
}
|
||||
|
||||
}
|
||||
365
pkg/apiserver/iam/users.go
Normal file
365
pkg/apiserver/iam/users.go
Normal file
@@ -0,0 +1,365 @@
|
||||
/*
|
||||
|
||||
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
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/emicklei/go-restful"
|
||||
"github.com/go-ldap/ldap"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam"
|
||||
)
|
||||
|
||||
const (
|
||||
emailRegex = "^[a-z0-9]+([._\\-]*[a-z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$"
|
||||
)
|
||||
|
||||
func CreateUser(req *restful.Request, resp *restful.Response) {
|
||||
var user models.User
|
||||
|
||||
err := req.ReadEntity(&user)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if user.Username == "" {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("invalid username")))
|
||||
return
|
||||
}
|
||||
|
||||
if !regexp.MustCompile(emailRegex).MatchString(user.Email) {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("invalid email")))
|
||||
return
|
||||
}
|
||||
|
||||
if len(user.Password) < 6 {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("invalid password")))
|
||||
return
|
||||
}
|
||||
|
||||
err = iam.CreateUser(user)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(errors.None)
|
||||
}
|
||||
|
||||
func DeleteUser(req *restful.Request, resp *restful.Response) {
|
||||
username := req.PathParameter("name")
|
||||
|
||||
operator := req.HeaderParameter(constants.UserNameHeader)
|
||||
|
||||
if operator == username {
|
||||
resp.WriteHeaderAndEntity(http.StatusForbidden, errors.Wrap(fmt.Errorf("cannot delete yourself")))
|
||||
return
|
||||
}
|
||||
|
||||
err := iam.DeleteUser(username)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(errors.None)
|
||||
}
|
||||
|
||||
func UpdateUser(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
usernameInPath := req.PathParameter("name")
|
||||
username := req.HeaderParameter(constants.UserNameHeader)
|
||||
var user models.User
|
||||
|
||||
err := req.ReadEntity(&user)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if usernameInPath != user.Username {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("the name of user (%s) does not match the name on the URL (%s)", user.Username, usernameInPath)))
|
||||
return
|
||||
}
|
||||
|
||||
if !regexp.MustCompile(emailRegex).MatchString(user.Email) {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("invalid email")))
|
||||
return
|
||||
}
|
||||
|
||||
if user.Password != "" && len(user.Password) < 6 {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("invalid password")))
|
||||
return
|
||||
}
|
||||
|
||||
if username == user.Username && user.Password != "" {
|
||||
_, err = iam.Login(username, user.CurrentPassword, "")
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("incorrect current password")))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
err = iam.UpdateUser(user)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(errors.None)
|
||||
}
|
||||
|
||||
func UserLoginLog(req *restful.Request, resp *restful.Response) {
|
||||
username := req.PathParameter("name")
|
||||
logs, err := iam.LoginLog(username)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
result := make([]map[string]string, 0)
|
||||
|
||||
for _, v := range logs {
|
||||
item := strings.Split(v, ",")
|
||||
time := item[0]
|
||||
var ip string
|
||||
if len(item) > 1 {
|
||||
ip = item[1]
|
||||
}
|
||||
result = append(result, map[string]string{"login_time": time, "login_ip": ip})
|
||||
}
|
||||
|
||||
resp.WriteAsJson(result)
|
||||
}
|
||||
|
||||
func CurrentUserDetail(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
username := req.HeaderParameter(constants.UserNameHeader)
|
||||
|
||||
conn, err := iam.NewConnection()
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
defer conn.Close()
|
||||
|
||||
user, err := iam.UserDetail(username, conn)
|
||||
|
||||
if err != nil {
|
||||
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
|
||||
resp.WriteHeaderAndEntity(http.StatusForbidden, errors.Wrap(err))
|
||||
} else {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
clusterRoles, err := iam.GetClusterRoles(username)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
clusterRules, err := iam.GetClusterRoleSimpleRules(clusterRoles)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
for i := 0; i < len(clusterRoles); i++ {
|
||||
if clusterRoles[i].Annotations["rbac.authorization.k8s.io/clusterrole"] == "true" {
|
||||
user.ClusterRole = clusterRoles[i].Name
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
user.ClusterRules = clusterRules
|
||||
|
||||
resp.WriteAsJson(user)
|
||||
}
|
||||
|
||||
func NamespacesListHandler(req *restful.Request, resp *restful.Response) {
|
||||
username := req.PathParameter("name")
|
||||
|
||||
namespaces, err := iam.GetNamespaces(username)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(namespaces)
|
||||
}
|
||||
|
||||
func UserDetail(req *restful.Request, resp *restful.Response) {
|
||||
username := req.PathParameter("name")
|
||||
|
||||
conn, err := iam.NewConnection()
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
defer conn.Close()
|
||||
|
||||
user, err := iam.UserDetail(username, conn)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
clusterRoles, err := iam.GetClusterRoles(username)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
clusterRules, err := iam.GetClusterRoleSimpleRules(clusterRoles)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
workspaceRoles := iam.GetWorkspaceRoles(clusterRoles)
|
||||
|
||||
for i := 0; i < len(clusterRoles); i++ {
|
||||
if clusterRoles[i].Annotations["rbac.authorization.k8s.io/clusterrole"] == "true" {
|
||||
user.ClusterRole = clusterRoles[i].Name
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
user.ClusterRules = clusterRules
|
||||
|
||||
user.WorkspaceRoles = workspaceRoles
|
||||
|
||||
resp.WriteAsJson(user)
|
||||
}
|
||||
|
||||
func UserList(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
limit, err := strconv.Atoi(req.QueryParameter("limit"))
|
||||
if err != nil {
|
||||
limit = 65535
|
||||
}
|
||||
offset, err := strconv.Atoi(req.QueryParameter("offset"))
|
||||
if err != nil {
|
||||
offset = 0
|
||||
}
|
||||
|
||||
if check := req.QueryParameter("check"); check != "" {
|
||||
exist, err := iam.UserCreateCheck(check)
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(map[string]bool{"exist": exist})
|
||||
return
|
||||
}
|
||||
|
||||
conn, err := iam.NewConnection()
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
defer conn.Close()
|
||||
|
||||
if query := req.QueryParameter("name"); query != "" {
|
||||
names := strings.Split(query, ",")
|
||||
users := make([]*models.User, 0)
|
||||
for _, name := range names {
|
||||
user, err := iam.UserDetail(name, conn)
|
||||
if err != nil {
|
||||
if ldap.IsErrorWithCode(err, 32) {
|
||||
continue
|
||||
} else {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
}
|
||||
users = append(users, user)
|
||||
}
|
||||
|
||||
resp.WriteAsJson(users)
|
||||
return
|
||||
}
|
||||
|
||||
var total int
|
||||
var users []models.User
|
||||
|
||||
if query := req.QueryParameter("search"); query != "" {
|
||||
total, users, err = iam.Search(query, limit, offset)
|
||||
} else if query := req.QueryParameter("keyword"); query != "" {
|
||||
total, users, err = iam.Search(query, limit, offset)
|
||||
} else {
|
||||
total, users, err = iam.UserList(limit, offset)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
for i := 0; i < len(users); i++ {
|
||||
clusterRoles, err := iam.GetClusterRoles(users[i].Username)
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
for j := 0; j < len(clusterRoles); j++ {
|
||||
if clusterRoles[j].Annotations["rbac.authorization.k8s.io/clusterrole"] == "true" {
|
||||
users[i].ClusterRole = clusterRoles[j].Name
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
items := make([]interface{}, 0)
|
||||
|
||||
for _, u := range users {
|
||||
items = append(items, u)
|
||||
}
|
||||
|
||||
resp.WriteAsJson(models.PageableResponse{Items: items, TotalCount: total})
|
||||
}
|
||||
746
pkg/apiserver/iam/workspaces.go
Normal file
746
pkg/apiserver/iam/workspaces.go
Normal file
@@ -0,0 +1,746 @@
|
||||
/*
|
||||
|
||||
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
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/emicklei/go-restful"
|
||||
"github.com/go-ldap/ldap"
|
||||
"k8s.io/api/core/v1"
|
||||
rbac "k8s.io/api/rbac/v1"
|
||||
apierror "k8s.io/apimachinery/pkg/api/errors"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam"
|
||||
"kubesphere.io/kubesphere/pkg/models/metrics"
|
||||
"kubesphere.io/kubesphere/pkg/models/workspaces"
|
||||
sliceutils "kubesphere.io/kubesphere/pkg/utils"
|
||||
)
|
||||
|
||||
const UserNameHeader = "X-Token-Username"
|
||||
|
||||
func WorkspaceRoles(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
name := req.PathParameter("name")
|
||||
|
||||
workspace, err := workspaces.Detail(name)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
roles, err := workspaces.Roles(workspace)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(roles)
|
||||
}
|
||||
|
||||
func WorkspaceMemberQuery(req *restful.Request, resp *restful.Response) {
|
||||
workspace := req.PathParameter("name")
|
||||
keyword := req.QueryParameter("keyword")
|
||||
|
||||
users, err := workspaces.GetWorkspaceMembers(workspace, keyword)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(users)
|
||||
}
|
||||
|
||||
func WorkspaceMemberDetail(req *restful.Request, resp *restful.Response) {
|
||||
workspace := req.PathParameter("name")
|
||||
username := req.PathParameter("member")
|
||||
|
||||
user, err := iam.GetUser(username)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
namespaces, err := workspaces.Namespaces(workspace)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
user.WorkspaceRole = user.WorkspaceRoles[workspace]
|
||||
|
||||
roles := make(map[string]string)
|
||||
|
||||
for _, namespace := range namespaces {
|
||||
if role := user.Roles[namespace.Name]; role != "" {
|
||||
roles[namespace.Name] = role
|
||||
}
|
||||
}
|
||||
|
||||
user.Roles = roles
|
||||
user.Rules = nil
|
||||
user.WorkspaceRules = nil
|
||||
user.WorkspaceRoles = nil
|
||||
user.ClusterRules = nil
|
||||
resp.WriteAsJson(user)
|
||||
}
|
||||
|
||||
func WorkspaceMemberInvite(req *restful.Request, resp *restful.Response) {
|
||||
var users []models.UserInvite
|
||||
workspace := req.PathParameter("name")
|
||||
err := req.ReadEntity(&users)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
err = workspaces.Invite(workspace, users)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(errors.None)
|
||||
}
|
||||
|
||||
func WorkspaceMemberRemove(req *restful.Request, resp *restful.Response) {
|
||||
query := req.QueryParameter("name")
|
||||
workspace := req.PathParameter("name")
|
||||
|
||||
names := strings.Split(query, ",")
|
||||
|
||||
err := workspaces.RemoveMembers(workspace, names)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(errors.None)
|
||||
}
|
||||
|
||||
func NamespaceCheckHandler(req *restful.Request, resp *restful.Response) {
|
||||
namespace := req.PathParameter("namespace")
|
||||
|
||||
exist, err := workspaces.NamespaceExistCheck(namespace)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(map[string]bool{"exist": exist})
|
||||
}
|
||||
|
||||
func NamespaceDeleteHandler(req *restful.Request, resp *restful.Response) {
|
||||
namespace := req.PathParameter("namespace")
|
||||
workspace := req.PathParameter("name")
|
||||
|
||||
err := workspaces.DeleteNamespace(workspace, namespace)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(errors.None)
|
||||
}
|
||||
|
||||
func DevOpsProjectDeleteHandler(req *restful.Request, resp *restful.Response) {
|
||||
devops := req.PathParameter("id")
|
||||
workspace := req.PathParameter("name")
|
||||
force := req.QueryParameter("force")
|
||||
username := req.HeaderParameter(UserNameHeader)
|
||||
|
||||
err := workspaces.UnBindDevopsProject(workspace, devops)
|
||||
|
||||
if err != nil && force != "true" {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
err = workspaces.DeleteDevopsProject(username, devops)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(errors.None)
|
||||
}
|
||||
|
||||
func DevOpsProjectCreateHandler(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
workspace := req.PathParameter("name")
|
||||
username := req.HeaderParameter(UserNameHeader)
|
||||
|
||||
var devops models.DevopsProject
|
||||
|
||||
err := req.ReadEntity(&devops)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
project, err := workspaces.CreateDevopsProject(username, workspace, devops)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(project)
|
||||
|
||||
}
|
||||
|
||||
func NamespaceCreateHandler(req *restful.Request, resp *restful.Response) {
|
||||
workspace := req.PathParameter("name")
|
||||
username := req.HeaderParameter(UserNameHeader)
|
||||
|
||||
namespace := &v1.Namespace{}
|
||||
|
||||
err := req.ReadEntity(namespace)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if namespace.Annotations == nil {
|
||||
namespace.Annotations = make(map[string]string, 0)
|
||||
}
|
||||
|
||||
namespace.Annotations["creator"] = username
|
||||
namespace.Annotations["workspace"] = workspace
|
||||
|
||||
if namespace.Labels == nil {
|
||||
namespace.Labels = make(map[string]string, 0)
|
||||
}
|
||||
|
||||
namespace.Labels["kubesphere.io/workspace"] = workspace
|
||||
|
||||
namespace, err = workspaces.CreateNamespace(namespace)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("invalid workspace name")))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(namespace)
|
||||
}
|
||||
|
||||
func DevOpsProjectHandler(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
workspace := req.PathParameter("name")
|
||||
username := req.PathParameter("username")
|
||||
keyword := req.QueryParameter("keyword")
|
||||
|
||||
if username == "" {
|
||||
username = req.HeaderParameter(UserNameHeader)
|
||||
}
|
||||
|
||||
limit := 65535
|
||||
offset := 0
|
||||
orderBy := "createTime"
|
||||
reverse := true
|
||||
|
||||
if groups := regexp.MustCompile(`^limit=(\d+),page=(\d+)$`).FindStringSubmatch(req.QueryParameter("paging")); len(groups) == 3 {
|
||||
limit, _ = strconv.Atoi(groups[1])
|
||||
page, _ := strconv.Atoi(groups[2])
|
||||
offset = (page - 1) * limit
|
||||
}
|
||||
|
||||
if groups := regexp.MustCompile(`^(createTime|name)$`).FindStringSubmatch(req.QueryParameter("order")); len(groups) == 2 {
|
||||
orderBy = groups[1]
|
||||
reverse = false
|
||||
}
|
||||
|
||||
if q := req.QueryParameter("reverse"); q != "" {
|
||||
b, err := strconv.ParseBool(q)
|
||||
if err == nil {
|
||||
reverse = b
|
||||
}
|
||||
}
|
||||
|
||||
total, devOpsProjects, err := workspaces.ListDevopsProjectsByUser(username, workspace, keyword, orderBy, reverse, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
result := models.PageableResponse{}
|
||||
result.TotalCount = total
|
||||
result.Items = make([]interface{}, 0)
|
||||
for _, n := range devOpsProjects {
|
||||
result.Items = append(result.Items, n)
|
||||
}
|
||||
resp.WriteAsJson(result)
|
||||
}
|
||||
|
||||
func WorkspaceCreateHandler(req *restful.Request, resp *restful.Response) {
|
||||
var workspace models.Workspace
|
||||
username := req.HeaderParameter(UserNameHeader)
|
||||
err := req.ReadEntity(&workspace)
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
if workspace.Name == "" || strings.Contains(workspace.Name, ":") {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("invalid workspace name")))
|
||||
return
|
||||
}
|
||||
|
||||
workspace.Path = workspace.Name
|
||||
workspace.Members = nil
|
||||
|
||||
if workspace.Admin != "" {
|
||||
workspace.Creator = workspace.Admin
|
||||
} else {
|
||||
workspace.Creator = username
|
||||
}
|
||||
|
||||
created, err := workspaces.Create(&workspace)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(created)
|
||||
|
||||
}
|
||||
|
||||
func DeleteWorkspaceHandler(req *restful.Request, resp *restful.Response) {
|
||||
name := req.PathParameter("name")
|
||||
|
||||
if name == "" || strings.Contains(name, ":") {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("invalid workspace name")))
|
||||
return
|
||||
}
|
||||
|
||||
workspace, err := workspaces.Detail(name)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
err = workspaces.Delete(workspace)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(errors.None)
|
||||
}
|
||||
func WorkspaceEditHandler(req *restful.Request, resp *restful.Response) {
|
||||
var workspace models.Workspace
|
||||
name := req.PathParameter("name")
|
||||
err := req.ReadEntity(&workspace)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if name != workspace.Name {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("the name of workspace (%s) does not match the name on the URL (%s)", workspace.Name, name)))
|
||||
return
|
||||
}
|
||||
|
||||
if workspace.Name == "" || strings.Contains(workspace.Name, ":") {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("invalid workspace name")))
|
||||
return
|
||||
}
|
||||
|
||||
workspace.Path = workspace.Name
|
||||
|
||||
workspace.Members = nil
|
||||
|
||||
edited, err := workspaces.Edit(&workspace)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(edited)
|
||||
}
|
||||
func WorkspaceDetailHandler(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
name := req.PathParameter("name")
|
||||
|
||||
workspace, err := workspaces.Detail(name)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(workspace)
|
||||
}
|
||||
|
||||
// List all workspaces for the current user
|
||||
func UserWorkspaceListHandler(req *restful.Request, resp *restful.Response) {
|
||||
keyword := req.QueryParameter("keyword")
|
||||
username := req.HeaderParameter(constants.UserNameHeader)
|
||||
|
||||
ws, err := workspaces.ListWorkspaceByUser(username, keyword)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
sort.Slice(ws, func(i, j int) bool {
|
||||
t1, err := ws[i].GetCreateTime()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
t2, err := ws[j].GetCreateTime()
|
||||
if err != nil {
|
||||
return true
|
||||
}
|
||||
return t1.After(t2)
|
||||
})
|
||||
|
||||
resp.WriteAsJson(ws)
|
||||
}
|
||||
|
||||
func UserNamespaceListHandler(req *restful.Request, resp *restful.Response) {
|
||||
withMetrics, err := strconv.ParseBool(req.QueryParameter("metrics"))
|
||||
|
||||
if err != nil {
|
||||
withMetrics = false
|
||||
}
|
||||
|
||||
username := req.PathParameter("username")
|
||||
keyword := req.QueryParameter("keyword")
|
||||
if username == "" {
|
||||
username = req.HeaderParameter(UserNameHeader)
|
||||
}
|
||||
limit := 65535
|
||||
offset := 0
|
||||
orderBy := "createTime"
|
||||
reverse := true
|
||||
|
||||
if groups := regexp.MustCompile(`^limit=(\d+),page=(\d+)$`).FindStringSubmatch(req.QueryParameter("paging")); len(groups) == 3 {
|
||||
limit, _ = strconv.Atoi(groups[1])
|
||||
page, _ := strconv.Atoi(groups[2])
|
||||
if page < 0 {
|
||||
page = 1
|
||||
}
|
||||
offset = (page - 1) * limit
|
||||
}
|
||||
|
||||
if groups := regexp.MustCompile(`^(createTime|name)$`).FindStringSubmatch(req.QueryParameter("order")); len(groups) == 2 {
|
||||
orderBy = groups[1]
|
||||
reverse = false
|
||||
}
|
||||
|
||||
if q := req.QueryParameter("reverse"); q != "" {
|
||||
b, err := strconv.ParseBool(q)
|
||||
if err == nil {
|
||||
reverse = b
|
||||
}
|
||||
}
|
||||
|
||||
workspaceName := req.PathParameter("workspace")
|
||||
|
||||
total, namespaces, err := workspaces.ListNamespaceByUser(workspaceName, username, keyword, orderBy, reverse, limit, offset)
|
||||
|
||||
if withMetrics {
|
||||
namespaces = metrics.GetNamespacesWithMetrics(namespaces)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
result := models.PageableResponse{}
|
||||
result.TotalCount = total
|
||||
result.Items = make([]interface{}, 0)
|
||||
for _, n := range namespaces {
|
||||
result.Items = append(result.Items, n)
|
||||
}
|
||||
|
||||
resp.WriteAsJson(result)
|
||||
}
|
||||
|
||||
func DevopsRulesHandler(req *restful.Request, resp *restful.Response) {
|
||||
//workspaceName := req.PathParameter("workspace")
|
||||
username := req.HeaderParameter(constants.UserNameHeader)
|
||||
devopsName := req.PathParameter("devops")
|
||||
|
||||
var rules []models.SimpleRule
|
||||
|
||||
role, err := iam.GetDevopsRole(devopsName, username)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
switch role {
|
||||
case "developer":
|
||||
rules = []models.SimpleRule{
|
||||
{Name: "pipelines", Actions: []string{"view", "trigger"}},
|
||||
{Name: "roles", Actions: []string{"view"}},
|
||||
{Name: "members", Actions: []string{"view"}},
|
||||
{Name: "devops", Actions: []string{"view"}},
|
||||
}
|
||||
break
|
||||
case "owner":
|
||||
rules = []models.SimpleRule{
|
||||
{Name: "pipelines", Actions: []string{"create", "edit", "view", "delete", "trigger"}},
|
||||
{Name: "roles", Actions: []string{"view"}},
|
||||
{Name: "members", Actions: []string{"create", "edit", "view", "delete"}},
|
||||
{Name: "credentials", Actions: []string{"create", "edit", "view", "delete"}},
|
||||
{Name: "devops", Actions: []string{"edit", "view", "delete"}},
|
||||
}
|
||||
break
|
||||
case "maintainer":
|
||||
rules = []models.SimpleRule{
|
||||
{Name: "pipelines", Actions: []string{"create", "edit", "view", "delete", "trigger"}},
|
||||
{Name: "roles", Actions: []string{"view"}},
|
||||
{Name: "members", Actions: []string{"view"}},
|
||||
{Name: "credentials", Actions: []string{"create", "edit", "view", "delete"}},
|
||||
{Name: "devops", Actions: []string{"view"}},
|
||||
}
|
||||
break
|
||||
case "reporter":
|
||||
fallthrough
|
||||
default:
|
||||
rules = []models.SimpleRule{
|
||||
{Name: "pipelines", Actions: []string{"view"}},
|
||||
{Name: "roles", Actions: []string{"view"}},
|
||||
{Name: "members", Actions: []string{"view"}},
|
||||
{Name: "devops", Actions: []string{"view"}},
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
resp.WriteAsJson(rules)
|
||||
}
|
||||
|
||||
func NamespacesRulesHandler(req *restful.Request, resp *restful.Response) {
|
||||
workspaceName := req.PathParameter("workspace")
|
||||
username := req.HeaderParameter(constants.UserNameHeader)
|
||||
namespaceName := req.PathParameter("namespace")
|
||||
|
||||
namespace, err := iam.GetNamespace(namespaceName)
|
||||
|
||||
if err != nil {
|
||||
if apierror.IsNotFound(err) {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("permission undefined")))
|
||||
} else {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if namespace.Labels == nil || namespace.Labels["kubesphere.io/workspace"] != workspaceName {
|
||||
resp.WriteHeaderAndEntity(http.StatusForbidden, errors.Wrap(fmt.Errorf("permission undefined")))
|
||||
return
|
||||
}
|
||||
|
||||
clusterRoles, err := iam.GetClusterRoles(username)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
roles, err := iam.GetRoles(username, namespaceName)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
for _, clusterRole := range clusterRoles {
|
||||
role := new(rbac.Role)
|
||||
role.Name = clusterRole.Name
|
||||
role.Labels = clusterRole.Labels
|
||||
role.Namespace = namespaceName
|
||||
role.Annotations = clusterRole.Annotations
|
||||
role.Kind = "Role"
|
||||
role.Rules = clusterRole.Rules
|
||||
roles = append(roles, role)
|
||||
}
|
||||
|
||||
rules, err := iam.GetRoleSimpleRules(roles, namespaceName)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if rules[namespaceName] == nil {
|
||||
resp.WriteAsJson(make([]models.SimpleRule, 0))
|
||||
} else {
|
||||
resp.WriteAsJson(rules[namespaceName])
|
||||
}
|
||||
}
|
||||
|
||||
func WorkspaceRulesHandler(req *restful.Request, resp *restful.Response) {
|
||||
workspace := req.PathParameter("workspace")
|
||||
|
||||
username := req.HeaderParameter(constants.UserNameHeader)
|
||||
|
||||
clusterRoles, err := iam.GetClusterRoles(username)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
rules := iam.GetWorkspaceSimpleRules(clusterRoles, workspace)
|
||||
|
||||
if rules[workspace] != nil {
|
||||
resp.WriteAsJson(rules[workspace])
|
||||
} else if rules["*"] != nil {
|
||||
resp.WriteAsJson(rules["*"])
|
||||
} else {
|
||||
resp.WriteAsJson(make([]models.SimpleRule, 0))
|
||||
}
|
||||
}
|
||||
|
||||
func WorkspaceMemberList(req *restful.Request, resp *restful.Response) {
|
||||
workspace := req.PathParameter("workspace")
|
||||
limit, err := strconv.Atoi(req.QueryParameter("limit"))
|
||||
if err != nil {
|
||||
limit = 500
|
||||
}
|
||||
offset, err := strconv.Atoi(req.QueryParameter("offset"))
|
||||
if err != nil {
|
||||
offset = 0
|
||||
}
|
||||
|
||||
conn, err := iam.NewConnection()
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
defer conn.Close()
|
||||
|
||||
group, err := iam.GroupDetail(workspace, conn)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
keyword := ""
|
||||
|
||||
if query := req.QueryParameter("keyword"); query != "" {
|
||||
keyword = query
|
||||
}
|
||||
|
||||
users := make([]*models.User, 0)
|
||||
|
||||
total := len(group.Members)
|
||||
|
||||
members := sliceutils.RemoveString(group.Members, func(item string) bool {
|
||||
return keyword != "" && !strings.Contains(item, keyword)
|
||||
})
|
||||
|
||||
for i := 0; i < len(members); i++ {
|
||||
username := members[i]
|
||||
|
||||
if i < offset {
|
||||
continue
|
||||
}
|
||||
|
||||
if len(users) == limit {
|
||||
break
|
||||
}
|
||||
|
||||
user, err := iam.UserDetail(username, conn)
|
||||
|
||||
if err != nil {
|
||||
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
|
||||
group.Members = sliceutils.RemoveString(group.Members, func(item string) bool {
|
||||
return item == username
|
||||
})
|
||||
continue
|
||||
} else {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
clusterRoles, err := iam.GetClusterRoles(username)
|
||||
|
||||
for i := 0; i < len(clusterRoles); i++ {
|
||||
if clusterRoles[i].Annotations["rbac.authorization.k8s.io/clusterrole"] == "true" {
|
||||
user.ClusterRole = clusterRoles[i].Name
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if group.Path == group.Name {
|
||||
|
||||
workspaceRole := iam.GetWorkspaceRole(clusterRoles, group.Name)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
user.WorkspaceRole = workspaceRole
|
||||
}
|
||||
|
||||
users = append(users, user)
|
||||
}
|
||||
|
||||
if total > len(group.Members) {
|
||||
go iam.UpdateGroup(group)
|
||||
}
|
||||
if req.QueryParameter("limit") != "" {
|
||||
resp.WriteAsJson(map[string]interface{}{"items": users, "total_count": len(members)})
|
||||
} else {
|
||||
resp.WriteAsJson(users)
|
||||
}
|
||||
}
|
||||
@@ -21,9 +21,10 @@ import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
"kubesphere.io/kubesphere/pkg/models/storage"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type scMetricsItem struct {
|
||||
type ScMetricsItem struct {
|
||||
Name string `json:"name"`
|
||||
Metrics *storage.ScMetrics `json:"metrics"`
|
||||
}
|
||||
@@ -35,11 +36,12 @@ func GetScMetrics(request *restful.Request, response *restful.Response) {
|
||||
|
||||
metrics, err := storage.GetScMetrics(scName)
|
||||
|
||||
if errors.HandlerError(err, response) {
|
||||
if err != nil {
|
||||
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
result := scMetricsItem{
|
||||
result := ScMetricsItem{
|
||||
Name: scName, Metrics: metrics,
|
||||
}
|
||||
|
||||
@@ -51,21 +53,23 @@ func GetScMetrics(request *restful.Request, response *restful.Response) {
|
||||
func GetScMetricsList(request *restful.Request, response *restful.Response) {
|
||||
scList, err := storage.GetScList()
|
||||
|
||||
if errors.HandlerError(err, response) {
|
||||
if err != nil {
|
||||
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
// Set return value
|
||||
items := make([]scMetricsItem, 0)
|
||||
items := make([]ScMetricsItem, 0)
|
||||
|
||||
for _, v := range scList {
|
||||
metrics, err := storage.GetScMetrics(v.GetName())
|
||||
|
||||
if errors.HandlerError(err, response) {
|
||||
if err != nil {
|
||||
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
item := scMetricsItem{
|
||||
item := ScMetricsItem{
|
||||
Name: v.GetName(), Metrics: metrics,
|
||||
}
|
||||
|
||||
|
||||
220
pkg/apiserver/monitoring/monitoring.go
Normal file
220
pkg/apiserver/monitoring/monitoring.go
Normal file
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
|
||||
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 monitoring
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"kubesphere.io/kubesphere/pkg/client"
|
||||
"kubesphere.io/kubesphere/pkg/models/metrics"
|
||||
)
|
||||
|
||||
func MonitorPod(request *restful.Request, response *restful.Response) {
|
||||
requestParams := client.ParseMonitoringRequestParams(request)
|
||||
podName := requestParams.PodName
|
||||
metricName := requestParams.MetricsName
|
||||
if podName != "" {
|
||||
// single pod single metric
|
||||
queryType, params, nullRule := metrics.AssemblePodMetricRequestInfo(requestParams, metricName)
|
||||
var res *metrics.FormatedMetric
|
||||
if !nullRule {
|
||||
res = metrics.GetMetric(queryType, params, metricName)
|
||||
}
|
||||
response.WriteAsJson(res)
|
||||
|
||||
} else {
|
||||
// multiple
|
||||
rawMetrics := metrics.MonitorAllMetrics(requestParams, metrics.MetricLevelPod)
|
||||
// sorting
|
||||
sortedMetrics, maxMetricCount := metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics, metrics.MetricLevelPodName)
|
||||
// paging
|
||||
pagedMetrics := metrics.Page(requestParams.PageNum, requestParams.LimitNum, sortedMetrics, maxMetricCount)
|
||||
|
||||
response.WriteAsJson(pagedMetrics)
|
||||
}
|
||||
}
|
||||
|
||||
func MonitorContainer(request *restful.Request, response *restful.Response) {
|
||||
requestParams := client.ParseMonitoringRequestParams(request)
|
||||
metricName := requestParams.MetricsName
|
||||
if requestParams.MetricsFilter != "" {
|
||||
rawMetrics := metrics.MonitorAllMetrics(requestParams, metrics.MetricLevelContainer)
|
||||
// sorting
|
||||
sortedMetrics, maxMetricCount := metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics, metrics.MetricLevelContainerName)
|
||||
// paging
|
||||
pagedMetrics := metrics.Page(requestParams.PageNum, requestParams.LimitNum, sortedMetrics, maxMetricCount)
|
||||
|
||||
response.WriteAsJson(pagedMetrics)
|
||||
|
||||
} else {
|
||||
res := metrics.MonitorContainer(requestParams, metricName)
|
||||
response.WriteAsJson(res)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func MonitorWorkload(request *restful.Request, response *restful.Response) {
|
||||
requestParams := client.ParseMonitoringRequestParams(request)
|
||||
|
||||
rawMetrics := metrics.MonitorAllMetrics(requestParams, metrics.MetricLevelWorkload)
|
||||
|
||||
var sortedMetrics *metrics.FormatedLevelMetric
|
||||
var maxMetricCount int
|
||||
|
||||
wlKind := requestParams.WorkloadKind
|
||||
|
||||
// sorting
|
||||
if wlKind == "" {
|
||||
|
||||
sortedMetrics, maxMetricCount = metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics, metrics.MetricLevelWorkload)
|
||||
} else {
|
||||
|
||||
sortedMetrics, maxMetricCount = metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics, metrics.MetricLevelPodName)
|
||||
}
|
||||
|
||||
// paging
|
||||
pagedMetrics := metrics.Page(requestParams.PageNum, requestParams.LimitNum, sortedMetrics, maxMetricCount)
|
||||
|
||||
response.WriteAsJson(pagedMetrics)
|
||||
|
||||
}
|
||||
|
||||
func MonitorAllWorkspaces(request *restful.Request, response *restful.Response) {
|
||||
|
||||
requestParams := client.ParseMonitoringRequestParams(request)
|
||||
|
||||
tp := requestParams.Tp
|
||||
if tp == "_statistics" {
|
||||
// merge multiple metric: all-devops, all-roles, all-projects...this api is designed for admin
|
||||
res := metrics.MonitorAllWorkspacesStatistics()
|
||||
|
||||
response.WriteAsJson(res)
|
||||
|
||||
} else if tp == "rank" {
|
||||
rawMetrics := metrics.MonitorAllWorkspaces(requestParams)
|
||||
// sorting
|
||||
sortedMetrics, maxMetricCount := metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics, metrics.MetricLevelWorkspace)
|
||||
// paging
|
||||
pagedMetrics := metrics.Page(requestParams.PageNum, requestParams.LimitNum, sortedMetrics, maxMetricCount)
|
||||
|
||||
response.WriteAsJson(pagedMetrics)
|
||||
} else {
|
||||
res := metrics.MonitorAllMetrics(requestParams, metrics.MetricLevelWorkspace)
|
||||
response.WriteAsJson(res)
|
||||
}
|
||||
}
|
||||
|
||||
func MonitorOneWorkspace(request *restful.Request, response *restful.Response) {
|
||||
requestParams := client.ParseMonitoringRequestParams(request)
|
||||
|
||||
tp := requestParams.Tp
|
||||
if tp == "rank" {
|
||||
// multiple
|
||||
rawMetrics := metrics.MonitorAllMetrics(requestParams, metrics.MetricLevelWorkspace)
|
||||
// sorting
|
||||
sortedMetrics, maxMetricCount := metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics, metrics.MetricLevelNamespace)
|
||||
// paging
|
||||
pagedMetrics := metrics.Page(requestParams.PageNum, requestParams.LimitNum, sortedMetrics, maxMetricCount)
|
||||
|
||||
response.WriteAsJson(pagedMetrics)
|
||||
|
||||
} else if tp == "_statistics" {
|
||||
wsName := requestParams.WsName
|
||||
|
||||
// merge multiple metric: devops, roles, projects...
|
||||
res := metrics.MonitorOneWorkspaceStatistics(wsName)
|
||||
response.WriteAsJson(res)
|
||||
} else {
|
||||
res := metrics.MonitorAllMetrics(requestParams, metrics.MetricLevelWorkspace)
|
||||
response.WriteAsJson(res)
|
||||
}
|
||||
}
|
||||
|
||||
func MonitorNamespace(request *restful.Request, response *restful.Response) {
|
||||
requestParams := client.ParseMonitoringRequestParams(request)
|
||||
metricName := requestParams.MetricsName
|
||||
nsName := requestParams.NsName
|
||||
if nsName != "" {
|
||||
// single
|
||||
queryType, params := metrics.AssembleNamespaceMetricRequestInfo(requestParams, metricName)
|
||||
res := metrics.GetMetric(queryType, params, metricName)
|
||||
response.WriteAsJson(res)
|
||||
} else {
|
||||
// multiple
|
||||
rawMetrics := metrics.MonitorAllMetrics(requestParams, metrics.MetricLevelNamespace)
|
||||
// sorting
|
||||
sortedMetrics, maxMetricCount := metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics, metrics.MetricLevelNamespace)
|
||||
// paging
|
||||
pagedMetrics := metrics.Page(requestParams.PageNum, requestParams.LimitNum, sortedMetrics, maxMetricCount)
|
||||
|
||||
response.WriteAsJson(pagedMetrics)
|
||||
}
|
||||
}
|
||||
|
||||
func MonitorCluster(request *restful.Request, response *restful.Response) {
|
||||
requestParams := client.ParseMonitoringRequestParams(request)
|
||||
|
||||
metricName := requestParams.MetricsName
|
||||
if metricName != "" {
|
||||
// single
|
||||
queryType, params := metrics.AssembleClusterMetricRequestInfo(requestParams, metricName)
|
||||
res := metrics.GetMetric(queryType, params, metricName)
|
||||
|
||||
response.WriteAsJson(res)
|
||||
} else {
|
||||
// multiple
|
||||
res := metrics.MonitorAllMetrics(requestParams, metrics.MetricLevelCluster)
|
||||
response.WriteAsJson(res)
|
||||
}
|
||||
}
|
||||
|
||||
func MonitorNode(request *restful.Request, response *restful.Response) {
|
||||
requestParams := client.ParseMonitoringRequestParams(request)
|
||||
|
||||
metricName := requestParams.MetricsName
|
||||
if metricName != "" {
|
||||
// single
|
||||
queryType, params := metrics.AssembleNodeMetricRequestInfo(requestParams, metricName)
|
||||
res := metrics.GetMetric(queryType, params, metricName)
|
||||
nodeAddress := metrics.GetNodeAddressInfo()
|
||||
metrics.AddNodeAddressMetric(res, nodeAddress)
|
||||
response.WriteAsJson(res)
|
||||
} else {
|
||||
// multiple
|
||||
rawMetrics := metrics.MonitorAllMetrics(requestParams, metrics.MetricLevelNode)
|
||||
nodeAddress := metrics.GetNodeAddressInfo()
|
||||
|
||||
for i := 0; i < len(rawMetrics.Results); i++ {
|
||||
metrics.AddNodeAddressMetric(&rawMetrics.Results[i], nodeAddress)
|
||||
}
|
||||
|
||||
// sorting
|
||||
sortedMetrics, maxMetricCount := metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics, metrics.MetricLevelNode)
|
||||
// paging
|
||||
pagedMetrics := metrics.Page(requestParams.PageNum, requestParams.LimitNum, sortedMetrics, maxMetricCount)
|
||||
|
||||
response.WriteAsJson(pagedMetrics)
|
||||
}
|
||||
}
|
||||
|
||||
// k8s component(controller, scheduler, etcd) status
|
||||
func MonitorComponentStatus(request *restful.Request, response *restful.Response) {
|
||||
requestParams := client.ParseMonitoringRequestParams(request)
|
||||
|
||||
status := metrics.MonitorComponentStatus(requestParams)
|
||||
response.WriteAsJson(status)
|
||||
}
|
||||
@@ -19,10 +19,9 @@
|
||||
package operations
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
"kubesphere.io/kubesphere/pkg/models/workloads"
|
||||
"net/http"
|
||||
|
||||
"github.com/emicklei/go-restful"
|
||||
|
||||
@@ -40,10 +39,11 @@ func RerunJob(req *restful.Request, resp *restful.Response) {
|
||||
case "rerun":
|
||||
err = workloads.JobReRun(namespace, job)
|
||||
default:
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.New(errors.InvalidArgument, fmt.Sprintf("invalid operation %s", action)))
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("invalid operation %s", action)))
|
||||
return
|
||||
}
|
||||
if errors.HandlerError(err, resp) {
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ package operations
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"net/http"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
"kubesphere.io/kubesphere/pkg/models/nodes"
|
||||
@@ -31,7 +32,8 @@ func DrainNode(request *restful.Request, response *restful.Response) {
|
||||
|
||||
err := nodes.DrainNode(nodeName)
|
||||
|
||||
if errors.HandlerError(err, response) {
|
||||
if err != nil {
|
||||
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -20,48 +20,30 @@ package quotas
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"github.com/emicklei/go-restful-openapi"
|
||||
"net/http"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/models/quotas"
|
||||
)
|
||||
|
||||
func V1Alpha2(ws *restful.WebService) {
|
||||
|
||||
tags := []string{"quotas"}
|
||||
|
||||
ws.Route(ws.GET("/quotas").
|
||||
To(getClusterQuotas).
|
||||
Doc("get whole cluster's resource usage").
|
||||
Writes(quotas.ResourceQuota{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/quotas").
|
||||
Doc("get specified namespace's resource quota and usage").
|
||||
Param(ws.PathParameter("namespace", "namespace's name").
|
||||
DataType("string")).
|
||||
Writes(quotas.ResourceQuota{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
To(getNamespaceQuotas))
|
||||
|
||||
}
|
||||
|
||||
func getNamespaceQuotas(req *restful.Request, resp *restful.Response) {
|
||||
func GetNamespaceQuotas(req *restful.Request, resp *restful.Response) {
|
||||
namespace := req.PathParameter("namespace")
|
||||
quota, err := quotas.GetNamespaceQuotas(namespace)
|
||||
|
||||
if errors.HandlerError(err, resp) {
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(quota)
|
||||
}
|
||||
|
||||
func getClusterQuotas(req *restful.Request, resp *restful.Response) {
|
||||
func GetClusterQuotas(req *restful.Request, resp *restful.Response) {
|
||||
quota, err := quotas.GetClusterQuotas()
|
||||
|
||||
if errors.HandlerError(err, resp) {
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -20,55 +20,29 @@ package registries
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"net/http"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
"kubesphere.io/kubesphere/pkg/models/registries"
|
||||
)
|
||||
|
||||
func V1Alpha2(ws *restful.WebService) {
|
||||
|
||||
ws.Route(ws.POST("registries/verify").To(registryVerify))
|
||||
|
||||
}
|
||||
|
||||
func registryVerify(request *restful.Request, response *restful.Response) {
|
||||
func RegistryVerify(request *restful.Request, response *restful.Response) {
|
||||
|
||||
authInfo := registries.AuthInfo{}
|
||||
|
||||
err := request.ReadEntity(&authInfo)
|
||||
|
||||
if errors.HandlerError(err, response) {
|
||||
if err != nil {
|
||||
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
err = registries.RegistryVerify(authInfo)
|
||||
|
||||
if errors.HandlerError(err, response) {
|
||||
if err != nil {
|
||||
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
response.WriteAsJson(errors.None)
|
||||
}
|
||||
|
||||
//func (c *registriesHandler) handlerImageSearch(request *restful.Request, response *restful.Response) {
|
||||
//
|
||||
// registry := request.PathParameter("name")
|
||||
// searchWord := request.PathParameter("searchWord")
|
||||
// namespace := request.PathParameter("namespace")
|
||||
//
|
||||
// res := c.registries.ImageSearch(namespace, registry, searchWord)
|
||||
//
|
||||
// response.WriteAsJson(res)
|
||||
//
|
||||
//}
|
||||
//
|
||||
//func (c *registriesHandler) handlerGetImageTags(request *restful.Request, response *restful.Response) {
|
||||
//
|
||||
// registry := request.PathParameter("name")
|
||||
// image := request.QueryParameter("image")
|
||||
// namespace := request.PathParameter("namespace")
|
||||
//
|
||||
// res := c.registries.GetImageTags(namespace, registry, image)
|
||||
//
|
||||
// response.WriteAsJson(res)
|
||||
//}
|
||||
|
||||
@@ -19,6 +19,7 @@ package resources
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"net/http"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
"kubesphere.io/kubesphere/pkg/models/resources"
|
||||
@@ -27,14 +28,15 @@ import (
|
||||
|
||||
func ClusterResourceHandler(req *restful.Request, resp *restful.Response) {
|
||||
resourceName := req.PathParameter("resources")
|
||||
conditions := req.QueryParameter(params.Conditions)
|
||||
orderBy := req.QueryParameter(params.OrderBy)
|
||||
limit, offset := params.ParsePaging(req.QueryParameter(params.Paging))
|
||||
reverse := params.ParseReserve(req.QueryParameter(params.Reserve))
|
||||
conditions, err := params.ParseConditions(req)
|
||||
orderBy := req.QueryParameter(params.OrderByParam)
|
||||
limit, offset := params.ParsePaging(req)
|
||||
reverse := params.ParseReverse(req)
|
||||
|
||||
result, err := resources.ListClusterResource(resourceName, conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if errors.HandlerError(err, resp) {
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ package resources
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"net/http"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
"kubesphere.io/kubesphere/pkg/models/resources"
|
||||
@@ -28,14 +29,15 @@ import (
|
||||
func NamespaceResourceHandler(req *restful.Request, resp *restful.Response) {
|
||||
namespace := req.PathParameter("namespace")
|
||||
resourceName := req.PathParameter("resources")
|
||||
conditions := req.QueryParameter(params.Conditions)
|
||||
orderBy := req.QueryParameter(params.OrderBy)
|
||||
limit, offset := params.ParsePaging(req.QueryParameter(params.Paging))
|
||||
reverse := params.ParseReserve(req.QueryParameter(params.Reserve))
|
||||
conditions, err := params.ParseConditions(req)
|
||||
orderBy := req.QueryParameter(params.OrderByParam)
|
||||
limit, offset := params.ParsePaging(req)
|
||||
reverse := params.ParseReverse(req)
|
||||
|
||||
result, err := resources.ListNamespaceResource(namespace, resourceName, conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if errors.HandlerError(err, resp) {
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ package resources
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"k8s.io/api/core/v1"
|
||||
"net/http"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
"kubesphere.io/kubesphere/pkg/models/storage"
|
||||
@@ -43,7 +44,8 @@ func GetPodListByPvc(request *restful.Request, response *restful.Response) {
|
||||
pvcName := request.PathParameter("pvc")
|
||||
nsName := request.PathParameter("namespace")
|
||||
pods, err := storage.GetPodListByPvc(pvcName, nsName)
|
||||
if errors.HandlerError(err, response) {
|
||||
if err != nil {
|
||||
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
result := podListByPvc{Name: pvcName, Namespace: nsName, Pods: pods}
|
||||
@@ -56,7 +58,8 @@ func GetPvcListBySc(request *restful.Request, response *restful.Response) {
|
||||
scName := request.PathParameter("storageclass")
|
||||
claims, err := storage.GetPvcListBySc(scName)
|
||||
|
||||
if errors.HandlerError(err, response) {
|
||||
if err != nil {
|
||||
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ package resources
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"net/http"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
"kubesphere.io/kubesphere/pkg/models/kubeconfig"
|
||||
@@ -31,7 +32,8 @@ func GetKubectl(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
kubectlPod, err := kubectl.GetKubectlPod(user)
|
||||
|
||||
if errors.HandlerError(err, resp) {
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -44,7 +46,8 @@ func GetKubeconfig(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
kubectlConfig, err := kubeconfig.GetKubeConfig(user)
|
||||
|
||||
if errors.HandlerError(err, resp) {
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -22,93 +22,59 @@ import (
|
||||
"strconv"
|
||||
|
||||
"github.com/emicklei/go-restful"
|
||||
"github.com/emicklei/go-restful-openapi"
|
||||
"k8s.io/api/apps/v1"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
"kubesphere.io/kubesphere/pkg/models/revisions"
|
||||
)
|
||||
|
||||
func V1Alpha2(ws *restful.WebService) {
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/daemonsets/{daemonset}/revisions/{revision}").
|
||||
To(getDaemonSetRevision).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{"daemonsets", "revision"}).
|
||||
Doc("Handle daemonset operation").
|
||||
Param(ws.PathParameter("daemonset", "daemonset's name").
|
||||
DataType("string")).
|
||||
Param(ws.PathParameter("namespace", "daemonset's namespace").
|
||||
DataType("string")).
|
||||
Param(ws.PathParameter("revision", "daemonset's revision")).
|
||||
Writes(v1.DaemonSet{}))
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/deployments/{deployment}/revisions/{revision}").
|
||||
To(getDeployRevision).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{"deployments", "revision"}).
|
||||
Doc("Handle deployment operation").
|
||||
Param(ws.PathParameter("deployment", "deployment's name").
|
||||
DataType("string")).
|
||||
Param(ws.PathParameter("namespace",
|
||||
"deployment's namespace").
|
||||
DataType("string")).
|
||||
Param(ws.PathParameter("deployment", "deployment's name")).
|
||||
Writes(v1.ReplicaSet{}))
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/statefulsets/{statefulset}/revisions/{revision}").
|
||||
To(getStatefulSetRevision).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{"statefulsets", "revisions"}).
|
||||
Doc("Handle statefulset operation").
|
||||
Param(ws.PathParameter("statefulset", "statefulset's name").
|
||||
DataType("string")).
|
||||
Param(ws.PathParameter("namespace", "statefulset's namespace").
|
||||
DataType("string")).
|
||||
Param(ws.PathParameter("revision", "statefulset's revision")).
|
||||
Writes(v1.StatefulSet{}))
|
||||
}
|
||||
|
||||
func getDaemonSetRevision(req *restful.Request, resp *restful.Response) {
|
||||
func GetDaemonSetRevision(req *restful.Request, resp *restful.Response) {
|
||||
daemonset := req.PathParameter("daemonset")
|
||||
namespace := req.PathParameter("namespace")
|
||||
revision, err := strconv.Atoi(req.PathParameter("revision"))
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.New(errors.InvalidArgument, err.Error()))
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
result, err := revisions.GetDaemonSetRevision(namespace, daemonset, revision)
|
||||
|
||||
if errors.HandlerError(err, resp) {
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(result)
|
||||
}
|
||||
|
||||
func getDeployRevision(req *restful.Request, resp *restful.Response) {
|
||||
func GetDeployRevision(req *restful.Request, resp *restful.Response) {
|
||||
deploy := req.PathParameter("deployment")
|
||||
namespace := req.PathParameter("namespace")
|
||||
revision := req.PathParameter("revision")
|
||||
|
||||
result, err := revisions.GetDeployRevision(namespace, deploy, revision)
|
||||
|
||||
if errors.HandlerError(err, resp) {
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(result)
|
||||
}
|
||||
|
||||
func getStatefulSetRevision(req *restful.Request, resp *restful.Response) {
|
||||
func GetStatefulSetRevision(req *restful.Request, resp *restful.Response) {
|
||||
statefulset := req.PathParameter("statefulset")
|
||||
namespace := req.PathParameter("namespace")
|
||||
revision, err := strconv.Atoi(req.PathParameter("revision"))
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.New(errors.InvalidArgument, err.Error()))
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
result, err := revisions.GetStatefulSetRevision(namespace, statefulset, revision)
|
||||
|
||||
if errors.HandlerError(err, resp) {
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -19,58 +19,31 @@
|
||||
package routers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/emicklei/go-restful"
|
||||
"net/http"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/api/core/v1"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/models/routers"
|
||||
)
|
||||
|
||||
func V1Alpha2(ws *restful.WebService) {
|
||||
ws.Route(ws.GET("/routers").To(getAllRouters).
|
||||
Doc("Get all routers"))
|
||||
|
||||
ws.Route(ws.GET("/users/{username}/routers").To(getAllRoutersOfUser).
|
||||
Doc("Get routers for user"))
|
||||
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/router").To(getRouter).
|
||||
Doc("Get router of a specified project").
|
||||
Param(ws.PathParameter("namespace", "name of the project").
|
||||
DataType("string")))
|
||||
|
||||
ws.Route(ws.DELETE("/namespaces/{namespace}/router").To(deleteRouter).
|
||||
Doc("Get router of a specified project").
|
||||
Param(ws.PathParameter("namespace", "name of the project").
|
||||
DataType("string")))
|
||||
|
||||
ws.Route(ws.POST("/namespaces/{namespace}/router").To(createRouter).
|
||||
Doc("Create a router for a specified project").
|
||||
Param(ws.PathParameter("namespace", "name of the project").
|
||||
DataType("string")))
|
||||
|
||||
ws.Route(ws.PUT("/namespaces/{namespace}/router").To(updateRouter).
|
||||
Doc("Update a router for a specified project").
|
||||
Param(ws.PathParameter("namespace", "name of the project").
|
||||
DataType("string")))
|
||||
}
|
||||
|
||||
type Router struct {
|
||||
RouterType string `json:"type"`
|
||||
Annotations map[string]string `json:"annotations"`
|
||||
}
|
||||
|
||||
// Get all namespace ingress controller services
|
||||
func getAllRouters(request *restful.Request, response *restful.Response) {
|
||||
func GetAllRouters(request *restful.Request, response *restful.Response) {
|
||||
|
||||
routers, err := routers.GetAllRouters()
|
||||
|
||||
if errors.HandlerError(err, response) {
|
||||
if err != nil {
|
||||
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -78,13 +51,14 @@ func getAllRouters(request *restful.Request, response *restful.Response) {
|
||||
}
|
||||
|
||||
// Get all namespace ingress controller services for user
|
||||
func getAllRoutersOfUser(request *restful.Request, response *restful.Response) {
|
||||
func GetAllRoutersOfUser(request *restful.Request, response *restful.Response) {
|
||||
|
||||
username := request.PathParameter("username")
|
||||
|
||||
routers, err := routers.GetAllRoutersOfUser(username)
|
||||
|
||||
if errors.HandlerError(err, response) {
|
||||
if err != nil {
|
||||
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -92,12 +66,13 @@ func getAllRoutersOfUser(request *restful.Request, response *restful.Response) {
|
||||
}
|
||||
|
||||
// Get ingress controller service for specified namespace
|
||||
func getRouter(request *restful.Request, response *restful.Response) {
|
||||
func GetRouter(request *restful.Request, response *restful.Response) {
|
||||
|
||||
namespace := request.PathParameter("namespace")
|
||||
router, err := routers.GetRouter(namespace)
|
||||
|
||||
if errors.HandlerError(err, response) {
|
||||
if err != nil {
|
||||
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -105,7 +80,7 @@ func getRouter(request *restful.Request, response *restful.Response) {
|
||||
}
|
||||
|
||||
// Create ingress controller and related services
|
||||
func createRouter(request *restful.Request, response *restful.Response) {
|
||||
func CreateRouter(request *restful.Request, response *restful.Response) {
|
||||
|
||||
namespace := request.PathParameter("namespace")
|
||||
|
||||
@@ -119,18 +94,17 @@ func createRouter(request *restful.Request, response *restful.Response) {
|
||||
|
||||
var router *v1.Service
|
||||
|
||||
serviceType, annotationMap, err := ParseParameter(newRouter)
|
||||
serviceType, annotationMap, err := parseParameter(newRouter)
|
||||
|
||||
if err != nil {
|
||||
glog.Error("Wrong annotations, missing key or value")
|
||||
response.WriteHeaderAndEntity(http.StatusBadRequest,
|
||||
errors.New(errors.InvalidArgument, "Wrong annotations, missing key or value"))
|
||||
response.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("wrong annotations, missing key or value")))
|
||||
return
|
||||
}
|
||||
|
||||
router, err = routers.CreateRouter(namespace, serviceType, annotationMap)
|
||||
|
||||
if errors.HandlerError(err, response) {
|
||||
if err != nil {
|
||||
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -138,19 +112,20 @@ func createRouter(request *restful.Request, response *restful.Response) {
|
||||
}
|
||||
|
||||
// Delete ingress controller and services
|
||||
func deleteRouter(request *restful.Request, response *restful.Response) {
|
||||
func DeleteRouter(request *restful.Request, response *restful.Response) {
|
||||
namespace := request.PathParameter("namespace")
|
||||
|
||||
router, err := routers.DeleteRouter(namespace)
|
||||
|
||||
if errors.HandlerError(err, response) {
|
||||
if err != nil {
|
||||
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
response.WriteAsJson(router)
|
||||
}
|
||||
|
||||
func updateRouter(request *restful.Request, response *restful.Response) {
|
||||
func UpdateRouter(request *restful.Request, response *restful.Response) {
|
||||
|
||||
namespace := request.PathParameter("namespace")
|
||||
|
||||
@@ -158,23 +133,23 @@ func updateRouter(request *restful.Request, response *restful.Response) {
|
||||
err := request.ReadEntity(&newRouter)
|
||||
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
response.WriteHeaderAndEntity(http.StatusBadRequest, errors.New(errors.InvalidArgument, err.Error()))
|
||||
response.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
serviceType, annotationMap, err := ParseParameter(newRouter)
|
||||
serviceType, annotationMap, err := parseParameter(newRouter)
|
||||
|
||||
router, err := routers.UpdateRouter(namespace, serviceType, annotationMap)
|
||||
|
||||
if errors.HandlerError(err, response) {
|
||||
if err != nil {
|
||||
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
response.WriteAsJson(router)
|
||||
}
|
||||
|
||||
func ParseParameter(router Router) (routerType v1.ServiceType, annotationMap map[string]string, err error) {
|
||||
func parseParameter(router Router) (routerType v1.ServiceType, annotationMap map[string]string, err error) {
|
||||
|
||||
routerType = v1.ServiceTypeNodePort
|
||||
|
||||
|
||||
@@ -35,7 +35,9 @@ type ContainerBuilder []func(c *restful.Container) error
|
||||
func NewWebService(gv schema.GroupVersion) *restful.WebService {
|
||||
webservice := restful.WebService{}
|
||||
|
||||
webservice.Path(ApiRootPath + "/" + gv.String())
|
||||
webservice.Path(ApiRootPath + "/" + gv.String()).
|
||||
Consumes(restful.MIME_JSON).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
return &webservice
|
||||
}
|
||||
|
||||
@@ -20,39 +20,25 @@ package workloadstatuses
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"github.com/emicklei/go-restful-openapi"
|
||||
"net/http"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
"kubesphere.io/kubesphere/pkg/models/status"
|
||||
)
|
||||
|
||||
func V1Alpha2(ws *restful.WebService) {
|
||||
tags := []string{"workloadStatus"}
|
||||
|
||||
ws.Route(ws.GET("/workloadstatuses").
|
||||
Doc("get abnormal workloads' count of whole cluster").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
To(getClusterResourceStatus))
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/workloadstatuses").
|
||||
Doc("get abnormal workloads' count of specified namespace").
|
||||
Param(ws.PathParameter("namespace", "the name of namespace").
|
||||
DataType("string")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
To(getNamespacesResourceStatus))
|
||||
|
||||
}
|
||||
|
||||
func getClusterResourceStatus(req *restful.Request, resp *restful.Response) {
|
||||
func GetClusterResourceStatus(req *restful.Request, resp *restful.Response) {
|
||||
res, err := status.GetClusterResourceStatus()
|
||||
if errors.HandlerError(err, resp) {
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
resp.WriteAsJson(res)
|
||||
}
|
||||
|
||||
func getNamespacesResourceStatus(req *restful.Request, resp *restful.Response) {
|
||||
func GetNamespacesResourceStatus(req *restful.Request, resp *restful.Response) {
|
||||
res, err := status.GetNamespacesResourceStatus(req.PathParameter("namespace"))
|
||||
if errors.HandlerError(err, resp) {
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
resp.WriteAsJson(res)
|
||||
|
||||
@@ -16,491 +16,3 @@
|
||||
|
||||
*/
|
||||
package workspaces
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"kubesphere.io/kubesphere/pkg/models/metrics"
|
||||
|
||||
"github.com/emicklei/go-restful"
|
||||
"k8s.io/api/core/v1"
|
||||
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"strconv"
|
||||
|
||||
"regexp"
|
||||
|
||||
"sort"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/models/iam"
|
||||
"kubesphere.io/kubesphere/pkg/models/workspaces"
|
||||
)
|
||||
|
||||
const UserNameHeader = "X-Token-Username"
|
||||
|
||||
func V1Alpha2(ws *restful.WebService) {
|
||||
ws.Route(ws.GET("/workspaces").To(UserWorkspaceListHandler))
|
||||
ws.Route(ws.POST("/workspaces").To(WorkspaceCreateHandler))
|
||||
ws.Route(ws.DELETE("/workspaces/{name}").To(DeleteWorkspaceHandler))
|
||||
ws.Route(ws.GET("/workspaces/{name}").To(WorkspaceDetailHandler))
|
||||
ws.Route(ws.PUT("/workspaces/{name}").To(WorkspaceEditHandler))
|
||||
ws.Route(ws.GET("/workspaces/{workspace}/namespaces").To(UserNamespaceListHandler))
|
||||
ws.Route(ws.GET("/workspaces/{workspace}/members/{username}/namespaces").To(UserNamespaceListHandler))
|
||||
ws.Route(ws.POST("/workspaces/{name}/namespaces").To(NamespaceCreateHandler))
|
||||
ws.Route(ws.DELETE("/workspaces/{name}/namespaces/{namespace}").To(NamespaceDeleteHandler))
|
||||
ws.Route(ws.GET("/workspaces/{name}/namespaces/{namespace}").To(NamespaceCheckHandler))
|
||||
ws.Route(ws.GET("/namespaces/{namespace}").To(NamespaceCheckHandler))
|
||||
ws.Route(ws.GET("/workspaces/{name}/devops").To(DevOpsProjectHandler))
|
||||
ws.Route(ws.GET("/workspaces/{name}/members/{username}/devops").To(DevOpsProjectHandler))
|
||||
ws.Route(ws.POST("/workspaces/{name}/devops").To(DevOpsProjectCreateHandler))
|
||||
ws.Route(ws.DELETE("/workspaces/{name}/devops/{id}").To(DevOpsProjectDeleteHandler))
|
||||
|
||||
ws.Route(ws.GET("/workspaces/{name}/members").To(MembersHandler))
|
||||
ws.Route(ws.GET("/workspaces/{name}/members/{member}").To(MemberHandler))
|
||||
ws.Route(ws.GET("/workspaces/{name}/roles").To(RolesHandler))
|
||||
// TODO /workspaces/{name}/roles/{role}
|
||||
ws.Route(ws.POST("/workspaces/{name}/members").To(MembersInviteHandler))
|
||||
ws.Route(ws.DELETE("/workspaces/{name}/members").To(MembersRemoveHandler))
|
||||
}
|
||||
|
||||
func RolesHandler(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
name := req.PathParameter("name")
|
||||
|
||||
workspace, err := workspaces.Detail(name)
|
||||
|
||||
if errors.HandlerError(err, resp) {
|
||||
return
|
||||
}
|
||||
|
||||
roles, err := workspaces.Roles(workspace)
|
||||
|
||||
if errors.HandlerError(err, resp) {
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(roles)
|
||||
}
|
||||
|
||||
func MembersHandler(req *restful.Request, resp *restful.Response) {
|
||||
workspace := req.PathParameter("name")
|
||||
keyword := req.QueryParameter("keyword")
|
||||
|
||||
users, err := workspaces.GetWorkspaceMembers(workspace, keyword)
|
||||
|
||||
if errors.HandlerError(err, resp) {
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(users)
|
||||
}
|
||||
|
||||
func MemberHandler(req *restful.Request, resp *restful.Response) {
|
||||
workspace := req.PathParameter("name")
|
||||
username := req.PathParameter("member")
|
||||
|
||||
user, err := iam.GetUser(username)
|
||||
if errors.HandlerError(err, resp) {
|
||||
return
|
||||
}
|
||||
|
||||
namespaces, err := workspaces.Namespaces(workspace)
|
||||
|
||||
if errors.HandlerError(err, resp) {
|
||||
return
|
||||
}
|
||||
|
||||
user.WorkspaceRole = user.WorkspaceRoles[workspace]
|
||||
|
||||
roles := make(map[string]string)
|
||||
|
||||
for _, namespace := range namespaces {
|
||||
if role := user.Roles[namespace.Name]; role != "" {
|
||||
roles[namespace.Name] = role
|
||||
}
|
||||
}
|
||||
|
||||
user.Roles = roles
|
||||
user.Rules = nil
|
||||
user.WorkspaceRules = nil
|
||||
user.WorkspaceRoles = nil
|
||||
user.ClusterRules = nil
|
||||
resp.WriteAsJson(user)
|
||||
}
|
||||
|
||||
func MembersInviteHandler(req *restful.Request, resp *restful.Response) {
|
||||
var users []workspaces.UserInvite
|
||||
workspace := req.PathParameter("name")
|
||||
err := req.ReadEntity(&users)
|
||||
|
||||
if errors.HandlerError(err, resp) {
|
||||
return
|
||||
}
|
||||
|
||||
err = workspaces.Invite(workspace, users)
|
||||
|
||||
if errors.HandlerError(err, resp) {
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(errors.None)
|
||||
}
|
||||
|
||||
func MembersRemoveHandler(req *restful.Request, resp *restful.Response) {
|
||||
query := req.QueryParameter("name")
|
||||
workspace := req.PathParameter("name")
|
||||
|
||||
names := strings.Split(query, ",")
|
||||
|
||||
err := workspaces.RemoveMembers(workspace, names)
|
||||
|
||||
if errors.HandlerError(err, resp) {
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(errors.None)
|
||||
}
|
||||
|
||||
func NamespaceCheckHandler(req *restful.Request, resp *restful.Response) {
|
||||
namespace := req.PathParameter("namespace")
|
||||
|
||||
exist, err := workspaces.NamespaceExistCheck(namespace)
|
||||
|
||||
if errors.HandlerError(err, resp) {
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(map[string]bool{"exist": exist})
|
||||
}
|
||||
|
||||
func NamespaceDeleteHandler(req *restful.Request, resp *restful.Response) {
|
||||
namespace := req.PathParameter("namespace")
|
||||
workspace := req.PathParameter("name")
|
||||
|
||||
err := workspaces.DeleteNamespace(workspace, namespace)
|
||||
|
||||
if errors.HandlerError(err, resp) {
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(errors.None)
|
||||
}
|
||||
|
||||
func DevOpsProjectDeleteHandler(req *restful.Request, resp *restful.Response) {
|
||||
devops := req.PathParameter("id")
|
||||
workspace := req.PathParameter("name")
|
||||
force := req.QueryParameter("force")
|
||||
username := req.HeaderParameter(UserNameHeader)
|
||||
|
||||
err := workspaces.UnBindDevopsProject(workspace, devops)
|
||||
|
||||
if err != nil && force != "true" {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.New(errors.Internal, err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
err = workspaces.DeleteDevopsProject(username, devops)
|
||||
|
||||
if errors.HandlerError(err, resp) {
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(errors.None)
|
||||
}
|
||||
|
||||
func DevOpsProjectCreateHandler(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
workspace := req.PathParameter("name")
|
||||
username := req.HeaderParameter(UserNameHeader)
|
||||
|
||||
var devops workspaces.DevopsProject
|
||||
|
||||
err := req.ReadEntity(&devops)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.New(errors.InvalidArgument, err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
project, err := workspaces.CreateDevopsProject(username, workspace, devops)
|
||||
|
||||
if errors.HandlerError(err, resp) {
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(project)
|
||||
|
||||
}
|
||||
|
||||
func NamespaceCreateHandler(req *restful.Request, resp *restful.Response) {
|
||||
workspace := req.PathParameter("name")
|
||||
username := req.HeaderParameter(UserNameHeader)
|
||||
|
||||
namespace := &v1.Namespace{}
|
||||
|
||||
err := req.ReadEntity(namespace)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.New(errors.InvalidArgument, err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
if namespace.Annotations == nil {
|
||||
namespace.Annotations = make(map[string]string, 0)
|
||||
}
|
||||
|
||||
namespace.Annotations["creator"] = username
|
||||
namespace.Annotations["workspace"] = workspace
|
||||
|
||||
if namespace.Labels == nil {
|
||||
namespace.Labels = make(map[string]string, 0)
|
||||
}
|
||||
|
||||
namespace.Labels["kubesphere.io/workspace"] = workspace
|
||||
|
||||
namespace, err = workspaces.CreateNamespace(namespace)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.New(errors.InvalidArgument, err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(namespace)
|
||||
}
|
||||
|
||||
func DevOpsProjectHandler(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
workspace := req.PathParameter("name")
|
||||
username := req.PathParameter("username")
|
||||
keyword := req.QueryParameter("keyword")
|
||||
|
||||
if username == "" {
|
||||
username = req.HeaderParameter(UserNameHeader)
|
||||
}
|
||||
|
||||
limit := 65535
|
||||
offset := 0
|
||||
orderBy := "createTime"
|
||||
reverse := true
|
||||
|
||||
if groups := regexp.MustCompile(`^limit=(\d+),page=(\d+)$`).FindStringSubmatch(req.QueryParameter("paging")); len(groups) == 3 {
|
||||
limit, _ = strconv.Atoi(groups[1])
|
||||
page, _ := strconv.Atoi(groups[2])
|
||||
offset = (page - 1) * limit
|
||||
}
|
||||
|
||||
if groups := regexp.MustCompile(`^(createTime|name)$`).FindStringSubmatch(req.QueryParameter("order")); len(groups) == 2 {
|
||||
orderBy = groups[1]
|
||||
reverse = false
|
||||
}
|
||||
|
||||
if q := req.QueryParameter("reverse"); q != "" {
|
||||
b, err := strconv.ParseBool(q)
|
||||
if err == nil {
|
||||
reverse = b
|
||||
}
|
||||
}
|
||||
|
||||
total, devOpsProjects, err := workspaces.ListDevopsProjectsByUser(username, workspace, keyword, orderBy, reverse, limit, offset)
|
||||
|
||||
if errors.HandlerError(err, resp) {
|
||||
return
|
||||
}
|
||||
|
||||
result := models.PageableResponse{}
|
||||
result.TotalCount = total
|
||||
result.Items = make([]interface{}, 0)
|
||||
for _, n := range devOpsProjects {
|
||||
result.Items = append(result.Items, n)
|
||||
}
|
||||
resp.WriteAsJson(result)
|
||||
}
|
||||
|
||||
func WorkspaceCreateHandler(req *restful.Request, resp *restful.Response) {
|
||||
var workspace workspaces.Workspace
|
||||
username := req.HeaderParameter(UserNameHeader)
|
||||
err := req.ReadEntity(&workspace)
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.New(errors.InvalidArgument, err.Error()))
|
||||
return
|
||||
}
|
||||
if workspace.Name == "" || strings.Contains(workspace.Name, ":") {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.New(errors.InvalidArgument, "invalid workspace name"))
|
||||
return
|
||||
}
|
||||
|
||||
workspace.Path = workspace.Name
|
||||
workspace.Members = nil
|
||||
|
||||
if workspace.Admin != "" {
|
||||
workspace.Creator = workspace.Admin
|
||||
} else {
|
||||
workspace.Creator = username
|
||||
}
|
||||
|
||||
created, err := workspaces.Create(&workspace)
|
||||
|
||||
if errors.HandlerError(err, resp) {
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(created)
|
||||
|
||||
}
|
||||
|
||||
func DeleteWorkspaceHandler(req *restful.Request, resp *restful.Response) {
|
||||
name := req.PathParameter("name")
|
||||
|
||||
if name == "" || strings.Contains(name, ":") {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.New(errors.InvalidArgument, "invalid workspace name"))
|
||||
return
|
||||
}
|
||||
|
||||
workspace, err := workspaces.Detail(name)
|
||||
|
||||
if errors.HandlerError(err, resp) {
|
||||
return
|
||||
}
|
||||
|
||||
err = workspaces.Delete(workspace)
|
||||
|
||||
if errors.HandlerError(err, resp) {
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(errors.None)
|
||||
}
|
||||
func WorkspaceEditHandler(req *restful.Request, resp *restful.Response) {
|
||||
var workspace workspaces.Workspace
|
||||
name := req.PathParameter("name")
|
||||
err := req.ReadEntity(&workspace)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.New(errors.InvalidArgument, err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
if name != workspace.Name {
|
||||
resp.WriteError(http.StatusBadRequest, fmt.Errorf("the name of workspace (%s) does not match the name on the URL (%s)", workspace.Name, name))
|
||||
return
|
||||
}
|
||||
|
||||
if workspace.Name == "" || strings.Contains(workspace.Name, ":") {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.New(errors.InvalidArgument, "invalid workspace name"))
|
||||
return
|
||||
}
|
||||
|
||||
workspace.Path = workspace.Name
|
||||
|
||||
workspace.Members = nil
|
||||
|
||||
edited, err := workspaces.Edit(&workspace)
|
||||
|
||||
if errors.HandlerError(err, resp) {
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(edited)
|
||||
}
|
||||
func WorkspaceDetailHandler(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
name := req.PathParameter("name")
|
||||
|
||||
workspace, err := workspaces.Detail(name)
|
||||
|
||||
if errors.HandlerError(err, resp) {
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(workspace)
|
||||
}
|
||||
|
||||
// List all workspaces for the current user
|
||||
func UserWorkspaceListHandler(req *restful.Request, resp *restful.Response) {
|
||||
keyword := req.QueryParameter("keyword")
|
||||
username := req.HeaderParameter(UserNameHeader)
|
||||
|
||||
ws, err := workspaces.ListWorkspaceByUser(username, keyword)
|
||||
|
||||
if errors.HandlerError(err, resp) {
|
||||
return
|
||||
}
|
||||
|
||||
sort.Slice(ws, func(i, j int) bool {
|
||||
t1, err := ws[i].GetCreateTime()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
t2, err := ws[j].GetCreateTime()
|
||||
if err != nil {
|
||||
return true
|
||||
}
|
||||
return t1.After(t2)
|
||||
})
|
||||
|
||||
resp.WriteAsJson(ws)
|
||||
}
|
||||
|
||||
func UserNamespaceListHandler(req *restful.Request, resp *restful.Response) {
|
||||
withMetrics, err := strconv.ParseBool(req.QueryParameter("metrics"))
|
||||
|
||||
if err != nil {
|
||||
withMetrics = false
|
||||
}
|
||||
|
||||
username := req.PathParameter("username")
|
||||
keyword := req.QueryParameter("keyword")
|
||||
if username == "" {
|
||||
username = req.HeaderParameter(UserNameHeader)
|
||||
}
|
||||
limit := 65535
|
||||
offset := 0
|
||||
orderBy := "createTime"
|
||||
reverse := true
|
||||
|
||||
if groups := regexp.MustCompile(`^limit=(\d+),page=(\d+)$`).FindStringSubmatch(req.QueryParameter("paging")); len(groups) == 3 {
|
||||
limit, _ = strconv.Atoi(groups[1])
|
||||
page, _ := strconv.Atoi(groups[2])
|
||||
if page < 0 {
|
||||
page = 1
|
||||
}
|
||||
offset = (page - 1) * limit
|
||||
}
|
||||
|
||||
if groups := regexp.MustCompile(`^(createTime|name)$`).FindStringSubmatch(req.QueryParameter("order")); len(groups) == 2 {
|
||||
orderBy = groups[1]
|
||||
reverse = false
|
||||
}
|
||||
|
||||
if q := req.QueryParameter("reverse"); q != "" {
|
||||
b, err := strconv.ParseBool(q)
|
||||
if err == nil {
|
||||
reverse = b
|
||||
}
|
||||
}
|
||||
|
||||
workspaceName := req.PathParameter("workspace")
|
||||
|
||||
total, namespaces, err := workspaces.ListNamespaceByUser(workspaceName, username, keyword, orderBy, reverse, limit, offset)
|
||||
|
||||
if withMetrics {
|
||||
namespaces = metrics.GetNamespacesWithMetrics(namespaces)
|
||||
}
|
||||
|
||||
if errors.HandlerError(err, resp) {
|
||||
return
|
||||
}
|
||||
|
||||
result := models.PageableResponse{}
|
||||
result.TotalCount = total
|
||||
result.Items = make([]interface{}, 0)
|
||||
for _, n := range namespaces {
|
||||
result.Items = append(result.Items, n)
|
||||
}
|
||||
|
||||
resp.WriteAsJson(result)
|
||||
}
|
||||
|
||||
@@ -1,51 +1,56 @@
|
||||
/*
|
||||
Copyright 2018 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 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 client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"flag"
|
||||
"log"
|
||||
"sync"
|
||||
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/golang/glog"
|
||||
"github.com/jinzhu/gorm"
|
||||
)
|
||||
|
||||
var dbClient *gorm.DB
|
||||
var (
|
||||
dbClientOnce sync.Once
|
||||
dbClient *gorm.DB
|
||||
dsn string
|
||||
)
|
||||
|
||||
func NewDBClient() *gorm.DB {
|
||||
conn := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", "", "", "", "")
|
||||
|
||||
db, err := gorm.Open("mysql", conn)
|
||||
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
panic(err)
|
||||
}
|
||||
return db
|
||||
func init() {
|
||||
flag.StringVar(&dsn, "database-connection", "root@tcp(localhost:3306)/kubesphere?charset=utf8&parseTime=True", "data source name")
|
||||
}
|
||||
|
||||
func NewSharedDBClient() *gorm.DB {
|
||||
func DBClient() *gorm.DB {
|
||||
dbClientOnce.Do(func() {
|
||||
var err error
|
||||
dbClient, err = gorm.Open("mysql", dsn)
|
||||
|
||||
if dbClient != nil {
|
||||
err := dbClient.DB().Ping()
|
||||
if err == nil {
|
||||
return dbClient
|
||||
} else {
|
||||
glog.Error(err)
|
||||
panic(err)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
}
|
||||
|
||||
return NewDBClient()
|
||||
if err := dbClient.DB().Ping(); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
})
|
||||
|
||||
return dbClient
|
||||
|
||||
}
|
||||
|
||||
@@ -19,25 +19,31 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
|
||||
"github.com/mitchellh/go-homedir"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
)
|
||||
|
||||
var (
|
||||
KubeConfigFile string
|
||||
kubeConfigFile string
|
||||
k8sClient *kubernetes.Clientset
|
||||
k8sClientOnce sync.Once
|
||||
KubeConfig *rest.Config
|
||||
)
|
||||
|
||||
func init() {
|
||||
flag.StringVar(&kubeConfigFile, "kubeconfig", fmt.Sprintf("%s/.kube/config", os.Getenv("HOME")), "path to kubeconfig file")
|
||||
}
|
||||
|
||||
func K8sClient() *kubernetes.Clientset {
|
||||
|
||||
k8sClientOnce.Do(func() {
|
||||
@@ -45,14 +51,10 @@ func K8sClient() *kubernetes.Clientset {
|
||||
config, err := getKubeConfig()
|
||||
|
||||
if err != nil {
|
||||
glog.Fatalf("cannot load kubeconfig: %v", err)
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
k8sClient, err = kubernetes.NewForConfig(config)
|
||||
|
||||
if err != nil {
|
||||
glog.Fatalf("cannot create k8s client: %v", err)
|
||||
}
|
||||
k8sClient = kubernetes.NewForConfigOrDie(config)
|
||||
|
||||
KubeConfig = config
|
||||
})
|
||||
@@ -62,36 +64,28 @@ func K8sClient() *kubernetes.Clientset {
|
||||
|
||||
func getKubeConfig() (kubeConfig *rest.Config, err error) {
|
||||
|
||||
if KubeConfigFile == "" {
|
||||
if kubeConfigFile == "" {
|
||||
if env := os.Getenv("KUBECONFIG"); env != "" {
|
||||
KubeConfigFile = env
|
||||
kubeConfigFile = env
|
||||
} else {
|
||||
if home, err := homedir.Dir(); err == nil {
|
||||
KubeConfigFile = fmt.Sprintf("%s/.kube/config", home)
|
||||
kubeConfigFile = fmt.Sprintf("%s/.kube/config", home)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if KubeConfigFile != "" {
|
||||
|
||||
kubeConfig, err = clientcmd.BuildConfigFromFlags("", KubeConfigFile)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err = os.Stat(kubeConfigFile); err == nil {
|
||||
kubeConfig, err = clientcmd.BuildConfigFromFlags("", kubeConfigFile)
|
||||
} else {
|
||||
|
||||
kubeConfig, err = rest.InClusterConfig()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
kubeConfig.QPS = 1e6
|
||||
kubeConfig.Burst = 1e6
|
||||
|
||||
return kubeConfig, nil
|
||||
|
||||
}
|
||||
|
||||
188
pkg/client/ldap/channel.go
Normal file
188
pkg/client/ldap/channel.go
Normal file
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
|
||||
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 ldap
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log"
|
||||
"sync"
|
||||
|
||||
"github.com/go-ldap/ldap"
|
||||
)
|
||||
|
||||
// channelPool implements the Pool interface based on buffered channels.
|
||||
type channelPool struct {
|
||||
// storage for our net.Conn connections
|
||||
mu sync.Mutex
|
||||
conns chan ldap.Client
|
||||
|
||||
name string
|
||||
aliveChecks bool
|
||||
|
||||
// net.Conn generator
|
||||
factory PoolFactory
|
||||
closeAt []uint16
|
||||
}
|
||||
|
||||
// PoolFactory is a function to create new connections.
|
||||
type PoolFactory func(string) (ldap.Client, error)
|
||||
|
||||
// NewChannelPool returns a new pool based on buffered channels with an initial
|
||||
// capacity and maximum capacity. Factory is used when initial capacity is
|
||||
// greater than zero to fill the pool. A zero initialCap doesn't fill the Pool
|
||||
// until a new Get() is called. During a Get(), If there is no new connection
|
||||
// available in the pool, a new connection will be created via the Factory()
|
||||
// method.
|
||||
//
|
||||
// closeAt will automagically mark the connection as unusable if the return code
|
||||
// of the call is one of those passed, most likely you want to set this to something
|
||||
// like
|
||||
// []uint8{ldap.LDAPResultTimeLimitExceeded, ldap.ErrorNetwork}
|
||||
func NewChannelPool(initialCap, maxCap int, name string, factory PoolFactory, closeAt []uint16) (Pool, error) {
|
||||
if initialCap < 0 || maxCap <= 0 || initialCap > maxCap {
|
||||
return nil, errors.New("invalid capacity settings")
|
||||
}
|
||||
|
||||
c := &channelPool{
|
||||
conns: make(chan ldap.Client, maxCap),
|
||||
name: name,
|
||||
factory: factory,
|
||||
closeAt: closeAt,
|
||||
aliveChecks: true,
|
||||
}
|
||||
|
||||
// create initial connections, if something goes wrong,
|
||||
// just close the pool error out.
|
||||
for i := 0; i < initialCap; i++ {
|
||||
conn, err := factory(c.name)
|
||||
if err != nil {
|
||||
c.Close()
|
||||
return nil, errors.New("factory is not able to fill the pool: " + err.Error())
|
||||
}
|
||||
c.conns <- conn
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (c *channelPool) AliveChecks(on bool) {
|
||||
c.mu.Lock()
|
||||
c.aliveChecks = on
|
||||
c.mu.Unlock()
|
||||
}
|
||||
|
||||
func (c *channelPool) getConns() chan ldap.Client {
|
||||
c.mu.Lock()
|
||||
conns := c.conns
|
||||
c.mu.Unlock()
|
||||
return conns
|
||||
}
|
||||
|
||||
// Get implements the Pool interfaces Get() method. If there is no new
|
||||
// connection available in the pool, a new connection will be created via the
|
||||
// Factory() method.
|
||||
func (c *channelPool) Get() (*PoolConn, error) {
|
||||
conns := c.getConns()
|
||||
if conns == nil {
|
||||
return nil, ErrClosed
|
||||
}
|
||||
|
||||
// wrap our connections with our ldap.Client implementation (wrapConn
|
||||
// method) that puts the connection back to the pool if it's closed.
|
||||
select {
|
||||
case conn := <-conns:
|
||||
if conn == nil {
|
||||
return nil, ErrClosed
|
||||
}
|
||||
if !c.aliveChecks || isAlive(conn) {
|
||||
return c.wrapConn(conn, c.closeAt), nil
|
||||
}
|
||||
conn.Close()
|
||||
return c.NewConn()
|
||||
default:
|
||||
return c.NewConn()
|
||||
}
|
||||
}
|
||||
|
||||
func isAlive(conn ldap.Client) bool {
|
||||
_, err := conn.Search(&ldap.SearchRequest{BaseDN: "", Scope: ldap.ScopeBaseObject, Filter: "(&)", Attributes: []string{"1.1"}})
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func (c *channelPool) NewConn() (*PoolConn, error) {
|
||||
conn, err := c.factory(c.name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.wrapConn(conn, c.closeAt), nil
|
||||
}
|
||||
|
||||
// put puts the connection back to the pool. If the pool is full or closed,
|
||||
// conn is simply closed. A nil conn will be rejected.
|
||||
func (c *channelPool) put(conn ldap.Client) {
|
||||
if conn == nil {
|
||||
log.Printf("connection is nil. rejecting")
|
||||
return
|
||||
}
|
||||
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
if c.conns == nil {
|
||||
// pool is closed, close passed connection
|
||||
conn.Close()
|
||||
return
|
||||
}
|
||||
|
||||
// put the resource back into the pool. If the pool is full, this will
|
||||
// block and the default case will be executed.
|
||||
select {
|
||||
case c.conns <- conn:
|
||||
return
|
||||
default:
|
||||
// pool is full, close passed connection
|
||||
conn.Close()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (c *channelPool) Close() {
|
||||
c.mu.Lock()
|
||||
conns := c.conns
|
||||
c.conns = nil
|
||||
c.factory = nil
|
||||
c.mu.Unlock()
|
||||
|
||||
if conns == nil {
|
||||
return
|
||||
}
|
||||
|
||||
close(conns)
|
||||
for conn := range conns {
|
||||
conn.Close()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (c *channelPool) Len() int { return len(c.getConns()) }
|
||||
|
||||
func (c *channelPool) wrapConn(conn ldap.Client, closeAt []uint16) *PoolConn {
|
||||
p := &PoolConn{c: c, closeAt: closeAt}
|
||||
p.Conn = conn
|
||||
return p
|
||||
}
|
||||
113
pkg/client/ldap/conn.go
Normal file
113
pkg/client/ldap/conn.go
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
|
||||
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 ldap
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/go-ldap/ldap"
|
||||
)
|
||||
|
||||
// PoolConn implements Client to override the Close() method
|
||||
type PoolConn struct {
|
||||
Conn ldap.Client
|
||||
c *channelPool
|
||||
unusable bool
|
||||
closeAt []uint16
|
||||
}
|
||||
|
||||
func (p *PoolConn) Start() {
|
||||
p.Conn.Start()
|
||||
}
|
||||
|
||||
func (p *PoolConn) StartTLS(config *tls.Config) error {
|
||||
// FIXME - check if already TLS and then ignore?
|
||||
return p.Conn.StartTLS(config)
|
||||
}
|
||||
|
||||
// Close() puts the given connects back to the pool instead of closing it.
|
||||
func (p *PoolConn) Close() {
|
||||
if p.unusable {
|
||||
log.Printf("Closing unusable connection")
|
||||
if p.Conn != nil {
|
||||
p.Conn.Close()
|
||||
}
|
||||
return
|
||||
}
|
||||
p.c.put(p.Conn)
|
||||
}
|
||||
|
||||
func (p *PoolConn) SimpleBind(simpleBindRequest *ldap.SimpleBindRequest) (*ldap.SimpleBindResult, error) {
|
||||
return p.Conn.SimpleBind(simpleBindRequest)
|
||||
}
|
||||
|
||||
func (p *PoolConn) Bind(username, password string) error {
|
||||
return p.Conn.Bind(username, password)
|
||||
}
|
||||
|
||||
func (p *PoolConn) ModifyDN(modifyDNRequest *ldap.ModifyDNRequest) error {
|
||||
return p.Conn.ModifyDN(modifyDNRequest)
|
||||
}
|
||||
|
||||
// MarkUnusable() marks the connection not usable any more, to let the pool close it
|
||||
// instead of returning it to pool.
|
||||
func (p *PoolConn) MarkUnusable() {
|
||||
p.unusable = true
|
||||
}
|
||||
|
||||
func (p *PoolConn) autoClose(err error) {
|
||||
for _, code := range p.closeAt {
|
||||
if ldap.IsErrorWithCode(err, code) {
|
||||
p.MarkUnusable()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PoolConn) SetTimeout(t time.Duration) {
|
||||
p.Conn.SetTimeout(t)
|
||||
}
|
||||
|
||||
func (p *PoolConn) Add(addRequest *ldap.AddRequest) error {
|
||||
return p.Conn.Add(addRequest)
|
||||
}
|
||||
|
||||
func (p *PoolConn) Del(delRequest *ldap.DelRequest) error {
|
||||
return p.Conn.Del(delRequest)
|
||||
}
|
||||
|
||||
func (p *PoolConn) Modify(modifyRequest *ldap.ModifyRequest) error {
|
||||
return p.Conn.Modify(modifyRequest)
|
||||
}
|
||||
|
||||
func (p *PoolConn) Compare(dn, attribute, value string) (bool, error) {
|
||||
return p.Conn.Compare(dn, attribute, value)
|
||||
}
|
||||
|
||||
func (p *PoolConn) PasswordModify(passwordModifyRequest *ldap.PasswordModifyRequest) (*ldap.PasswordModifyResult, error) {
|
||||
return p.Conn.PasswordModify(passwordModifyRequest)
|
||||
}
|
||||
|
||||
func (p *PoolConn) Search(searchRequest *ldap.SearchRequest) (*ldap.SearchResult, error) {
|
||||
return p.Conn.Search(searchRequest)
|
||||
}
|
||||
func (p *PoolConn) SearchWithPaging(searchRequest *ldap.SearchRequest, pagingSize uint32) (*ldap.SearchResult, error) {
|
||||
return p.Conn.SearchWithPaging(searchRequest, pagingSize)
|
||||
}
|
||||
43
pkg/client/ldap/pool.go
Normal file
43
pkg/client/ldap/pool.go
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
|
||||
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 ldap
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrClosed is the error resulting if the pool is closed via pool.Close().
|
||||
ErrClosed = errors.New("pool is closed")
|
||||
)
|
||||
|
||||
// Pool interface describes a pool implementation. A pool should have maximum
|
||||
// capacity. An ideal pool is threadsafe and easy to use.
|
||||
type Pool interface {
|
||||
// Get returns a new connection from the pool. Closing the connections puts
|
||||
// it back to the Pool. Closing it when the pool is destroyed or full will
|
||||
// be counted as an error.
|
||||
Get() (*PoolConn, error)
|
||||
|
||||
// Close closes the pool and all its connections. After Close() the pool is
|
||||
// no longer usable.
|
||||
Close()
|
||||
|
||||
// Len returns the current number of connections of the pool.
|
||||
Len() int
|
||||
}
|
||||
65
pkg/client/ldapclient.go
Normal file
65
pkg/client/ldapclient.go
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
|
||||
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 client
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"github.com/go-ldap/ldap"
|
||||
ldapPool "kubesphere.io/kubesphere/pkg/client/ldap"
|
||||
"os"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
once sync.Once
|
||||
pool ldapPool.Pool
|
||||
ldapHost string
|
||||
ManagerDN string
|
||||
ManagerPassword string
|
||||
UserSearchBase string
|
||||
GroupSearchBase string
|
||||
)
|
||||
|
||||
func init() {
|
||||
flag.StringVar(&ldapHost, "ldap-server", "localhost:389", "ldap server host")
|
||||
flag.StringVar(&ManagerDN, "ldap-manager-dn", "cn=admin,dc=example,dc=org", "ldap manager dn")
|
||||
flag.StringVar(&ManagerPassword, "ldap-manager-password", "admin", "ldap manager password")
|
||||
flag.StringVar(&UserSearchBase, "ldap-user-search-base", "ou=Users,dc=example,dc=org", "ldap user search base")
|
||||
flag.StringVar(&GroupSearchBase, "ldap-group-search-base", "ou=Groups,dc=example,dc=org", "ldap group search base")
|
||||
}
|
||||
|
||||
func LdapClient() ldapPool.Pool {
|
||||
|
||||
once.Do(func() {
|
||||
var err error
|
||||
pool, err = ldapPool.NewChannelPool(8, 96, "kubesphere", func(s string) (ldap.Client, error) {
|
||||
conn, err := ldap.Dial("tcp", ldapHost)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return conn, nil
|
||||
}, []uint16{ldap.LDAPResultTimeLimitExceeded, ldap.ErrorNetwork})
|
||||
|
||||
if err != nil {
|
||||
fmt.Fprint(os.Stderr, err.Error())
|
||||
panic(err)
|
||||
}
|
||||
})
|
||||
return pool
|
||||
}
|
||||
@@ -1,18 +1,24 @@
|
||||
/*
|
||||
Copyright 2018 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 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 client
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
@@ -20,31 +26,23 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"os"
|
||||
|
||||
"github.com/emicklei/go-restful"
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultScheme = "http"
|
||||
DefaultPrometheusPort = "9090"
|
||||
PrometheusApiPath = "/api/v1/"
|
||||
DefaultQueryStep = "10m"
|
||||
DefaultQueryTimeout = "10s"
|
||||
RangeQueryType = "query_range?"
|
||||
DefaultQueryType = "query?"
|
||||
PrometheusAPIServerEnv = "PROMETHEUS_API_SERVER"
|
||||
DefaultQueryStep = "10m"
|
||||
DefaultQueryTimeout = "10s"
|
||||
RangeQueryType = "query_range?"
|
||||
DefaultQueryType = "query?"
|
||||
)
|
||||
|
||||
var PrometheusAPIServer = "prometheus-k8s.kubesphere-monitoring-system.svc"
|
||||
var PrometheusEndpointUrl string
|
||||
var (
|
||||
prometheusAPIEndpoint string
|
||||
)
|
||||
|
||||
func init() {
|
||||
if env := os.Getenv(PrometheusAPIServerEnv); env != "" {
|
||||
PrometheusAPIServer = env
|
||||
}
|
||||
PrometheusEndpointUrl = DefaultScheme + "://" + PrometheusAPIServer + ":" + DefaultPrometheusPort + PrometheusApiPath
|
||||
flag.StringVar(&prometheusAPIEndpoint, "prometheus-endpoint", "http://prometheus-k8s.kubesphere-monitoring-system.svc:9090/api/v1/", "prometheus api endpoint")
|
||||
}
|
||||
|
||||
type MonitoringRequestParams struct {
|
||||
@@ -72,11 +70,10 @@ type MonitoringRequestParams struct {
|
||||
WorkloadKind string
|
||||
}
|
||||
|
||||
var client = &http.Client{}
|
||||
|
||||
func SendMonitoringRequest(queryType string, params string) string {
|
||||
epurl := PrometheusEndpointUrl + queryType + params
|
||||
response, err := client.Get(epurl)
|
||||
epurl := prometheusAPIEndpoint + queryType + params
|
||||
|
||||
response, err := http.DefaultClient.Get(epurl)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
} else {
|
||||
@@ -116,11 +113,11 @@ func ParseMonitoringRequestParams(request *restful.Request) *MonitoringRequestPa
|
||||
metricsName := strings.Trim(request.QueryParameter("metrics_name"), " ")
|
||||
workloadName := strings.Trim(request.QueryParameter("workload_name"), " ")
|
||||
|
||||
nodeId := strings.Trim(request.PathParameter("node_id"), " ")
|
||||
wsName := strings.Trim(request.PathParameter("workspace_name"), " ")
|
||||
nsName := strings.Trim(request.PathParameter("ns_name"), " ")
|
||||
podName := strings.Trim(request.PathParameter("pod_name"), " ")
|
||||
containerName := strings.Trim(request.PathParameter("container_name"), " ")
|
||||
nodeId := strings.Trim(request.PathParameter("node"), " ")
|
||||
wsName := strings.Trim(request.PathParameter("workspace"), " ")
|
||||
nsName := strings.Trim(request.PathParameter("namespace"), " ")
|
||||
podName := strings.Trim(request.PathParameter("pod"), " ")
|
||||
containerName := strings.Trim(request.PathParameter("container"), " ")
|
||||
workloadKind := strings.Trim(request.PathParameter("workload_kind"), " ")
|
||||
|
||||
var requestParams = MonitoringRequestParams{
|
||||
|
||||
56
pkg/client/redis.go
Normal file
56
pkg/client/redis.go
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
|
||||
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 client
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"log"
|
||||
"sync"
|
||||
|
||||
"github.com/go-redis/redis"
|
||||
)
|
||||
|
||||
var (
|
||||
redisHost string
|
||||
redisPassword string
|
||||
redisDB int
|
||||
redisClientOnce sync.Once
|
||||
redisClient *redis.Client
|
||||
)
|
||||
|
||||
func init() {
|
||||
flag.StringVar(&redisHost, "redis-server", "localhost:6379", "redis server host")
|
||||
flag.StringVar(&redisPassword, "redis-password", "", "redis password")
|
||||
flag.IntVar(&redisDB, "redis-db", 0, "redis db")
|
||||
}
|
||||
|
||||
func RedisClient() *redis.Client {
|
||||
|
||||
redisClientOnce.Do(func() {
|
||||
redisClient = redis.NewClient(&redis.Options{
|
||||
Addr: redisHost,
|
||||
Password: redisPassword,
|
||||
DB: redisDB,
|
||||
})
|
||||
if err := redisClient.Ping().Err(); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
})
|
||||
|
||||
return redisClient
|
||||
}
|
||||
@@ -1,6 +1,21 @@
|
||||
package constants
|
||||
/*
|
||||
|
||||
import "os"
|
||||
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 constants
|
||||
|
||||
const (
|
||||
APIVersion = "v1alpha1"
|
||||
@@ -24,32 +39,18 @@ const (
|
||||
DevopsOwner = "owner"
|
||||
DevopsReporter = "reporter"
|
||||
|
||||
DevopsAPIServerEnv = "DEVOPS_API_SERVER"
|
||||
AccountAPIServerEnv = "ACCOUNT_API_SERVER"
|
||||
DevopsProxyTokenEnv = "DEVOPS_PROXY_TOKEN"
|
||||
OpenPitrixProxyTokenEnv = "OPENPITRIX_PROXY_TOKEN"
|
||||
envDevopsAPIServer = "DEVOPS_API_SERVER"
|
||||
envAccountAPIServer = "ACCOUNT_API_SERVER"
|
||||
envDevopsProxyToken = "DEVOPS_PROXY_TOKEN"
|
||||
envOpenPitrixProxyToken = "OPENPITRIX_PROXY_TOKEN"
|
||||
|
||||
UserNameHeader = "X-Token-Username"
|
||||
)
|
||||
|
||||
var (
|
||||
WorkSpaceRoles = []string{WorkspaceAdmin, WorkspaceRegular, WorkspaceViewer}
|
||||
DevopsAPIServer = "ks-devops-apiserver.kubesphere-system.svc"
|
||||
AccountAPIServer = "ks-account.kubesphere-system.svc"
|
||||
DevopsProxyToken = ""
|
||||
OpenPitrixProxyToken = ""
|
||||
SystemNamespaces = []string{KubeSystemNamespace, OpenPitrixNamespace, KubeSystemNamespace}
|
||||
WorkSpaceRoles = []string{WorkspaceAdmin, WorkspaceRegular, WorkspaceViewer}
|
||||
SystemWorkspace = "system-workspace"
|
||||
DevopsAPIServer = "ks-devops-apiserver.kubesphere-system.svc"
|
||||
AccountAPIServer = "ks-account.kubesphere-system.svc"
|
||||
SystemNamespaces = []string{KubeSystemNamespace, OpenPitrixNamespace, KubeSystemNamespace}
|
||||
)
|
||||
|
||||
func init() {
|
||||
if env := os.Getenv(DevopsAPIServerEnv); env != "" {
|
||||
DevopsAPIServer = env
|
||||
}
|
||||
if env := os.Getenv(AccountAPIServerEnv); env != "" {
|
||||
AccountAPIServer = env
|
||||
}
|
||||
if env := os.Getenv(DevopsProxyTokenEnv); env != "" {
|
||||
DevopsProxyToken = env
|
||||
}
|
||||
if env := os.Getenv(OpenPitrixProxyTokenEnv); env != "" {
|
||||
OpenPitrixProxyToken = env
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
package errors
|
||||
|
||||
type Code int
|
||||
|
||||
const (
|
||||
OK Code = iota
|
||||
Canceled
|
||||
Unknown
|
||||
InvalidArgument
|
||||
Internal // 5
|
||||
Unavailable
|
||||
AlreadyExists
|
||||
NotFound
|
||||
NotImplement
|
||||
VerifyFailed
|
||||
Conflict
|
||||
)
|
||||
@@ -1,16 +0,0 @@
|
||||
// Code generated by "stringer -type=Code"; DO NOT EDIT.
|
||||
|
||||
package errors
|
||||
|
||||
import "strconv"
|
||||
|
||||
const _Code_name = "OKCanceledUnknownInvalidArgumentInternalUnavailableAlreadyExistsWTFNotFoundNotImplementVerifyFailed"
|
||||
|
||||
var _Code_index = [...]uint8{0, 2, 10, 17, 32, 40, 51, 64, 67, 75, 87, 99}
|
||||
|
||||
func (i Code) String() string {
|
||||
if i < 0 || i >= Code(len(_Code_index)-1) {
|
||||
return "Code(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _Code_name[_Code_index[i]:_Code_index[i+1]]
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package errors
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestCode_String(t *testing.T) {
|
||||
t.Log(Code(1).String())
|
||||
}
|
||||
@@ -1,105 +1,42 @@
|
||||
/*
|
||||
|
||||
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 errors
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"reflect"
|
||||
|
||||
k8sError "k8s.io/apimachinery/pkg/api/errors"
|
||||
|
||||
"github.com/emicklei/go-restful"
|
||||
"github.com/go-sql-driver/mysql"
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
type Error struct {
|
||||
Code Code `json:"code"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
var None = New(OK, "success")
|
||||
var None = Error{Message: "success"}
|
||||
|
||||
func (e *Error) Error() string {
|
||||
return fmt.Sprintf("error: %v,message: %v", e.Code.String(), e.Message)
|
||||
}
|
||||
func (e *Error) HttpStatusCode() int {
|
||||
switch e.Code {
|
||||
case OK:
|
||||
return http.StatusOK
|
||||
case InvalidArgument:
|
||||
return http.StatusBadRequest
|
||||
case AlreadyExists:
|
||||
return http.StatusConflict
|
||||
case Unavailable:
|
||||
return http.StatusServiceUnavailable
|
||||
case NotImplement:
|
||||
return http.StatusNotImplemented
|
||||
case VerifyFailed:
|
||||
return http.StatusBadRequest
|
||||
case Conflict:
|
||||
return http.StatusConflict
|
||||
case Internal:
|
||||
fallthrough
|
||||
case Unknown:
|
||||
fallthrough
|
||||
default:
|
||||
return http.StatusInternalServerError
|
||||
}
|
||||
return e.Message
|
||||
}
|
||||
|
||||
func New(code Code, message string) error {
|
||||
if message == "" {
|
||||
message = code.String()
|
||||
}
|
||||
return &Error{Code: code, Message: message}
|
||||
func Wrap(err error) Error {
|
||||
return Error{Message: err.Error()}
|
||||
}
|
||||
|
||||
func HandlerError(err error, resp *restful.Response) bool {
|
||||
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
glog.Errorln(reflect.TypeOf(err), err)
|
||||
|
||||
resp.WriteHeaderAndEntity(wrapper(err))
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func wrapper(err error) (int, interface{}) {
|
||||
switch err.(type) {
|
||||
case *Error:
|
||||
case *json.UnmarshalTypeError:
|
||||
err = New(InvalidArgument, err.Error())
|
||||
case *mysql.MySQLError:
|
||||
err = wrapperMysqlError(err.(*mysql.MySQLError))
|
||||
case *net.OpError:
|
||||
err = New(Internal, err.Error())
|
||||
default:
|
||||
if k8sError.IsNotFound(err) {
|
||||
err = New(NotFound, err.Error())
|
||||
} else {
|
||||
err = New(Unknown, err.Error())
|
||||
}
|
||||
|
||||
}
|
||||
return err.(*Error).HttpStatusCode(), err
|
||||
}
|
||||
|
||||
func wrapperMysqlError(sqlError *mysql.MySQLError) error {
|
||||
switch sqlError.Number {
|
||||
case 1062:
|
||||
return New(AlreadyExists, sqlError.Message)
|
||||
default:
|
||||
return New(Unknown, sqlError.Message)
|
||||
}
|
||||
}
|
||||
|
||||
func Wrap(data []byte) error {
|
||||
func Parse(data []byte) error {
|
||||
var j map[string]string
|
||||
err := json.Unmarshal(data, &j)
|
||||
if err != nil {
|
||||
|
||||
@@ -18,47 +18,27 @@
|
||||
package components
|
||||
|
||||
import (
|
||||
"time"
|
||||
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
|
||||
lister "k8s.io/client-go/listers/core/v1"
|
||||
"kubesphere.io/kubesphere/pkg/client"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
|
||||
"github.com/golang/glog"
|
||||
coreV1 "k8s.io/api/core/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
)
|
||||
|
||||
type Component struct {
|
||||
Name string `json:"name"`
|
||||
Namespace string `json:"namespace"`
|
||||
SelfLink string `json:"selfLink"`
|
||||
Label interface{} `json:"label"`
|
||||
StartedAt time.Time `json:"startedAt"`
|
||||
TotalBackends int `json:"totalBackends"`
|
||||
HealthyBackends int `json:"healthyBackends"`
|
||||
}
|
||||
|
||||
var (
|
||||
componentStatusLister lister.ComponentStatusLister
|
||||
serviceLister lister.ServiceLister
|
||||
podLister lister.PodLister
|
||||
nodeLister lister.NodeLister
|
||||
)
|
||||
|
||||
func init() {
|
||||
componentStatusLister = informers.SharedInformerFactory().Core().V1().ComponentStatuses().Lister()
|
||||
serviceLister = informers.SharedInformerFactory().Core().V1().Services().Lister()
|
||||
podLister = informers.SharedInformerFactory().Core().V1().Pods().Lister()
|
||||
nodeLister = informers.SharedInformerFactory().Core().V1().Nodes().Lister()
|
||||
}
|
||||
|
||||
func GetComponentStatus(name string) (interface{}, error) {
|
||||
|
||||
var service *coreV1.Service
|
||||
var service *corev1.Service
|
||||
var err error
|
||||
|
||||
serviceLister := informers.SharedInformerFactory().Core().V1().Services().Lister()
|
||||
|
||||
for _, ns := range constants.SystemNamespaces {
|
||||
service, err = serviceLister.Services(ns).Get(name)
|
||||
if err == nil {
|
||||
@@ -70,13 +50,15 @@ func GetComponentStatus(name string) (interface{}, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
podLister := informers.SharedInformerFactory().Core().V1().Pods().Lister()
|
||||
|
||||
pods, err := podLister.Pods(service.Namespace).List(labels.SelectorFromValidatedSet(service.Spec.Selector))
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
component := Component{
|
||||
component := models.Component{
|
||||
Name: service.Name,
|
||||
Namespace: service.Namespace,
|
||||
SelfLink: service.SelfLink,
|
||||
@@ -102,11 +84,11 @@ func GetSystemHealthStatus() (map[string]interface{}, error) {
|
||||
|
||||
status := make(map[string]interface{})
|
||||
|
||||
componentStatuses, err := componentStatusLister.List(labels.Everything())
|
||||
componentStatuses, err := client.K8sClient().CoreV1().ComponentStatuses().List(meta_v1.ListOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, cs := range componentStatuses {
|
||||
for _, cs := range componentStatuses.Items {
|
||||
status[cs.Name] = cs.Conditions[0]
|
||||
}
|
||||
|
||||
@@ -119,6 +101,8 @@ func GetSystemHealthStatus() (map[string]interface{}, error) {
|
||||
for k, v := range systemComponentStatus {
|
||||
status[k] = v
|
||||
}
|
||||
|
||||
nodeLister := informers.SharedInformerFactory().Core().V1().Nodes().Lister()
|
||||
// get node status
|
||||
nodes, err := nodeLister.List(labels.Everything())
|
||||
if err != nil {
|
||||
@@ -132,7 +116,7 @@ func GetSystemHealthStatus() (map[string]interface{}, error) {
|
||||
for _, nodes := range nodes {
|
||||
totalNodes++
|
||||
for _, condition := range nodes.Status.Conditions {
|
||||
if condition.Type == coreV1.NodeReady && condition.Status == coreV1.ConditionTrue {
|
||||
if condition.Type == corev1.NodeReady && condition.Status == corev1.ConditionTrue {
|
||||
healthyNodes++
|
||||
}
|
||||
}
|
||||
@@ -147,11 +131,12 @@ func GetSystemHealthStatus() (map[string]interface{}, error) {
|
||||
}
|
||||
|
||||
func GetAllComponentsStatus() (map[string]interface{}, error) {
|
||||
serviceLister := informers.SharedInformerFactory().Core().V1().Services().Lister()
|
||||
podLister := informers.SharedInformerFactory().Core().V1().Pods().Lister()
|
||||
|
||||
status := make(map[string]interface{})
|
||||
|
||||
var err error
|
||||
|
||||
for _, ns := range constants.SystemNamespaces {
|
||||
|
||||
nsStatus := make(map[string]interface{})
|
||||
@@ -164,7 +149,7 @@ func GetAllComponentsStatus() (map[string]interface{}, error) {
|
||||
}
|
||||
|
||||
for _, service := range services {
|
||||
component := Component{
|
||||
component := models.Component{
|
||||
Name: service.Name,
|
||||
Namespace: service.Namespace,
|
||||
SelfLink: service.SelfLink,
|
||||
|
||||
822
pkg/models/iam/am.go
Normal file
822
pkg/models/iam/am.go
Normal file
@@ -0,0 +1,822 @@
|
||||
/*
|
||||
|
||||
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
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"log"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/go-ldap/ldap"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/api/rbac/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/kubernetes/pkg/util/slice"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/client"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam/policy"
|
||||
)
|
||||
|
||||
func GetNamespaces(username string) ([]*corev1.Namespace, error) {
|
||||
|
||||
roles, err := GetRoles(username, "")
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
namespaces := make([]*corev1.Namespace, 0)
|
||||
namespaceLister := informers.SharedInformerFactory().Core().V1().Namespaces().Lister()
|
||||
for _, role := range roles {
|
||||
namespace, err := namespaceLister.Get(role.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
namespaces = append(namespaces, namespace)
|
||||
}
|
||||
|
||||
return namespaces, nil
|
||||
}
|
||||
|
||||
func GetNamespacesByWorkspace(workspace string) ([]*corev1.Namespace, error) {
|
||||
namespaceLister := informers.SharedInformerFactory().Core().V1().Namespaces().Lister()
|
||||
return namespaceLister.List(labels.SelectorFromSet(labels.Set{"kubesphere.io/workspace": workspace}))
|
||||
}
|
||||
|
||||
func GetDevopsRole(projectId string, username string) (string, error) {
|
||||
|
||||
//Hard fix
|
||||
if username == "admin" {
|
||||
return "owner", nil
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("http://%s/api/v1alpha/projects/%s/members", constants.DevopsAPIServer, projectId), nil)
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
req.Header.Set(constants.UserNameHeader, username)
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
data, err := ioutil.ReadAll(resp.Body)
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if resp.StatusCode > 200 {
|
||||
return "", errors.New(string(data))
|
||||
}
|
||||
|
||||
var result []map[string]string
|
||||
|
||||
err = json.Unmarshal(data, &result)
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for _, item := range result {
|
||||
if item["username"] == username {
|
||||
return item["role"], nil
|
||||
}
|
||||
}
|
||||
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func GetNamespace(namespaceName string) (*corev1.Namespace, error) {
|
||||
namespaceLister := informers.SharedInformerFactory().Core().V1().Namespaces().Lister()
|
||||
return namespaceLister.Get(namespaceName)
|
||||
}
|
||||
|
||||
func GetRoles(username string, namespace string) ([]*v1.Role, error) {
|
||||
clusterRoleLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoles().Lister()
|
||||
roleBindingLister := informers.SharedInformerFactory().Rbac().V1().RoleBindings().Lister()
|
||||
roleLister := informers.SharedInformerFactory().Rbac().V1().Roles().Lister()
|
||||
roleBindings, err := roleBindingLister.RoleBindings(namespace).List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
roles := make([]*v1.Role, 0)
|
||||
|
||||
for _, roleBinding := range roleBindings {
|
||||
|
||||
for _, subject := range roleBinding.Subjects {
|
||||
if subject.Kind == v1.UserKind && subject.Name == username {
|
||||
if roleBinding.RoleRef.Kind == ClusterRoleKind {
|
||||
clusterRole, err := clusterRoleLister.Get(roleBinding.RoleRef.Name)
|
||||
if err == nil {
|
||||
var role = v1.Role{TypeMeta: (*clusterRole).TypeMeta, ObjectMeta: (*clusterRole).ObjectMeta, Rules: (*clusterRole).Rules}
|
||||
role.Namespace = roleBinding.Namespace
|
||||
roles = append(roles, &role)
|
||||
break
|
||||
} else if apierrors.IsNotFound(err) {
|
||||
log.Println(err)
|
||||
break
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
if subject.Kind == v1.UserKind && subject.Name == username {
|
||||
rule, err := roleLister.Roles(roleBinding.Namespace).Get(roleBinding.RoleRef.Name)
|
||||
if err == nil {
|
||||
roles = append(roles, rule)
|
||||
break
|
||||
} else if apierrors.IsNotFound(err) {
|
||||
log.Println(err)
|
||||
break
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return roles, nil
|
||||
}
|
||||
|
||||
func GetClusterRoles(username string) ([]*v1.ClusterRole, error) {
|
||||
clusterRoleLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoles().Lister()
|
||||
clusterRoleBindingLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoleBindings().Lister()
|
||||
clusterRoleBindings, err := clusterRoleBindingLister.List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
roles := make([]*v1.ClusterRole, 0)
|
||||
|
||||
for _, rb := range clusterRoleBindings {
|
||||
if rb.RoleRef.Kind == ClusterRoleKind {
|
||||
for _, subject := range rb.Subjects {
|
||||
if subject.Kind == v1.UserKind && subject.Name == username {
|
||||
|
||||
role, err := clusterRoleLister.Get(rb.RoleRef.Name)
|
||||
role = role.DeepCopy()
|
||||
if err == nil {
|
||||
if role.Annotations == nil {
|
||||
role.Annotations = make(map[string]string, 0)
|
||||
}
|
||||
|
||||
role.Annotations["rbac.authorization.k8s.io/clusterrolebinding"] = rb.Name
|
||||
|
||||
if rb.Annotations != nil &&
|
||||
rb.Annotations["rbac.authorization.k8s.io/clusterrole"] == rb.RoleRef.Name {
|
||||
role.Annotations["rbac.authorization.k8s.io/clusterrole"] = "true"
|
||||
}
|
||||
|
||||
roles = append(roles, role)
|
||||
break
|
||||
} else if apierrors.IsNotFound(err) {
|
||||
log.Println(err)
|
||||
break
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return roles, nil
|
||||
}
|
||||
|
||||
func GetRoleBindings(namespace string, roleName string) ([]*v1.RoleBinding, error) {
|
||||
roleBindingLister := informers.SharedInformerFactory().Rbac().V1().RoleBindings().Lister()
|
||||
roleBindingList, err := roleBindingLister.List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
items := make([]*v1.RoleBinding, 0)
|
||||
|
||||
for _, roleBinding := range roleBindingList {
|
||||
if roleName == "" {
|
||||
items = append(items, roleBinding)
|
||||
} else if roleBinding.RoleRef.Name == roleName {
|
||||
items = append(items, roleBinding)
|
||||
}
|
||||
}
|
||||
|
||||
return items, nil
|
||||
}
|
||||
|
||||
func GetClusterRoleBindings(clusterRoleName string) ([]*v1.ClusterRoleBinding, error) {
|
||||
clusterRoleBindingLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoleBindings().Lister()
|
||||
roleBindingList, err := clusterRoleBindingLister.List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
items := make([]*v1.ClusterRoleBinding, 0)
|
||||
|
||||
for _, roleBinding := range roleBindingList {
|
||||
if roleBinding.RoleRef.Name == clusterRoleName {
|
||||
items = append(items, roleBinding)
|
||||
}
|
||||
}
|
||||
|
||||
return items, nil
|
||||
}
|
||||
|
||||
func ClusterRoleUsers(clusterRoleName string) ([]*models.User, error) {
|
||||
|
||||
roleBindings, err := GetClusterRoleBindings(clusterRoleName)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
conn, err := NewConnection()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer conn.Close()
|
||||
|
||||
names := make([]string, 0)
|
||||
users := make([]*models.User, 0)
|
||||
for _, roleBinding := range roleBindings {
|
||||
for _, subject := range roleBinding.Subjects {
|
||||
if subject.Kind == v1.UserKind && !strings.HasPrefix(subject.Name, "system") &&
|
||||
!slice.ContainsString(names, subject.Name, nil) {
|
||||
names = append(names, subject.Name)
|
||||
|
||||
user, err := UserDetail(subject.Name, conn)
|
||||
|
||||
if ldap.IsErrorWithCode(err, 32) {
|
||||
continue
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
users = append(users, user)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return users, nil
|
||||
|
||||
}
|
||||
|
||||
func RoleUsers(namespace string, roleName string) ([]*models.User, error) {
|
||||
roleBindings, err := GetRoleBindings(namespace, roleName)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
conn, err := NewConnection()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer conn.Close()
|
||||
|
||||
names := make([]string, 0)
|
||||
users := make([]*models.User, 0)
|
||||
for _, roleBinding := range roleBindings {
|
||||
for _, subject := range roleBinding.Subjects {
|
||||
if subject.Kind == v1.UserKind &&
|
||||
!strings.HasPrefix(subject.Name, "system") &&
|
||||
!slice.ContainsString(names, subject.Name, nil) {
|
||||
names = append(names, subject.Name)
|
||||
user, err := UserDetail(subject.Name, conn)
|
||||
if ldap.IsErrorWithCode(err, 32) {
|
||||
continue
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
users = append(users, user)
|
||||
}
|
||||
}
|
||||
}
|
||||
return users, nil
|
||||
}
|
||||
|
||||
func NamespaceUsers(namespaceName string) ([]*models.User, error) {
|
||||
roleBindings, err := GetRoleBindings(namespaceName, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conn, err := NewConnection()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer conn.Close()
|
||||
|
||||
names := make([]string, 0)
|
||||
users := make([]*models.User, 0)
|
||||
|
||||
for _, roleBinding := range roleBindings {
|
||||
|
||||
for _, subject := range roleBinding.Subjects {
|
||||
if subject.Kind == v1.UserKind &&
|
||||
!slice.ContainsString(names, subject.Name, nil) &&
|
||||
!strings.HasPrefix(subject.Name, "system") {
|
||||
if roleBinding.Name == "viewer" {
|
||||
continue
|
||||
}
|
||||
if roleBinding.Name == "admin" {
|
||||
continue
|
||||
}
|
||||
names = append(names, subject.Name)
|
||||
user, err := UserDetail(subject.Name, conn)
|
||||
if ldap.IsErrorWithCode(err, 32) {
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
user.Role = roleBinding.RoleRef.Name
|
||||
user.RoleBinding = roleBinding.Name
|
||||
users = append(users, user)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return users, nil
|
||||
}
|
||||
|
||||
func GetWorkspaceRoles(clusterRoles []*v1.ClusterRole) map[string]string {
|
||||
|
||||
workspaceRoles := make(map[string]string, 0)
|
||||
|
||||
for _, v := range clusterRoles {
|
||||
if groups := regexp.MustCompile(fmt.Sprintf(`^system:(\S+):(%s)$`, strings.Join(constants.WorkSpaceRoles, "|"))).FindStringSubmatch(v.Name); len(groups) == 3 {
|
||||
workspaceRoles[groups[1]] = groups[2]
|
||||
}
|
||||
}
|
||||
|
||||
return workspaceRoles
|
||||
}
|
||||
|
||||
func GetWorkspaceRole(clusterRoles []*v1.ClusterRole, workspace string) string {
|
||||
|
||||
for _, v := range clusterRoles {
|
||||
if groups := regexp.MustCompile(fmt.Sprintf(`^system:(\S+):(%s)$`, strings.Join(constants.WorkSpaceRoles, "|"))).FindStringSubmatch(v.Name); len(groups) == 3 {
|
||||
if groups[1] == workspace {
|
||||
return groups[2]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func GetWorkspaceSimpleRules(clusterRoles []*v1.ClusterRole, workspace string) map[string][]models.SimpleRule {
|
||||
|
||||
workspaceRules := make(map[string][]models.SimpleRule, 0)
|
||||
|
||||
clusterSimpleRules := make([]models.SimpleRule, 0)
|
||||
clusterRules := make([]v1.PolicyRule, 0)
|
||||
for _, clusterRole := range clusterRoles {
|
||||
clusterRules = append(clusterRules, clusterRole.Rules...)
|
||||
}
|
||||
|
||||
for i := 0; i < len(policy.WorkspaceRoleRuleMapping); i++ {
|
||||
rule := models.SimpleRule{Name: policy.WorkspaceRoleRuleMapping[i].Name}
|
||||
rule.Actions = make([]string, 0)
|
||||
for j := 0; j < (len(policy.WorkspaceRoleRuleMapping[i].Actions)); j++ {
|
||||
if RulesMatchesAction(clusterRules, policy.WorkspaceRoleRuleMapping[i].Actions[j]) {
|
||||
rule.Actions = append(rule.Actions, policy.WorkspaceRoleRuleMapping[i].Actions[j].Name)
|
||||
}
|
||||
}
|
||||
if len(rule.Actions) > 0 {
|
||||
clusterSimpleRules = append(clusterSimpleRules, rule)
|
||||
}
|
||||
}
|
||||
|
||||
if len(clusterRules) > 0 {
|
||||
workspaceRules["*"] = clusterSimpleRules
|
||||
}
|
||||
|
||||
for _, v := range clusterRoles {
|
||||
|
||||
if groups := regexp.MustCompile(fmt.Sprintf(`^system:(\S+):(%s)$`, strings.Join(constants.WorkSpaceRoles, "|"))).FindStringSubmatch(v.Name); len(groups) == 3 {
|
||||
|
||||
if workspace != "" && groups[1] != workspace {
|
||||
continue
|
||||
}
|
||||
|
||||
policyRules := make([]v1.PolicyRule, 0)
|
||||
|
||||
for _, rule := range v.Rules {
|
||||
rule.ResourceNames = nil
|
||||
policyRules = append(policyRules, rule)
|
||||
}
|
||||
|
||||
rules := make([]models.SimpleRule, 0)
|
||||
|
||||
for i := 0; i < len(policy.WorkspaceRoleRuleMapping); i++ {
|
||||
rule := models.SimpleRule{Name: policy.WorkspaceRoleRuleMapping[i].Name}
|
||||
rule.Actions = make([]string, 0)
|
||||
for j := 0; j < (len(policy.WorkspaceRoleRuleMapping[i].Actions)); j++ {
|
||||
action := policy.WorkspaceRoleRuleMapping[i].Actions[j]
|
||||
if RulesMatchesAction(policyRules, action) {
|
||||
rule.Actions = append(rule.Actions, action.Name)
|
||||
}
|
||||
}
|
||||
if len(rule.Actions) > 0 {
|
||||
rules = append(rules, rule)
|
||||
}
|
||||
}
|
||||
|
||||
workspaceRules[groups[1]] = merge(rules, clusterSimpleRules)
|
||||
}
|
||||
}
|
||||
|
||||
return workspaceRules
|
||||
}
|
||||
|
||||
func merge(clusterRules, rules []models.SimpleRule) []models.SimpleRule {
|
||||
for _, clusterRule := range clusterRules {
|
||||
exist := false
|
||||
|
||||
for i := 0; i < len(rules); i++ {
|
||||
if rules[i].Name == clusterRule.Name {
|
||||
exist = true
|
||||
|
||||
for _, action := range clusterRule.Actions {
|
||||
if !slice.ContainsString(rules[i].Actions, action, nil) {
|
||||
rules[i].Actions = append(rules[i].Actions, action)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !exist {
|
||||
rules = append(rules, clusterRule)
|
||||
}
|
||||
}
|
||||
return rules
|
||||
}
|
||||
|
||||
// Convert cluster roles to rules
|
||||
func GetClusterRoleSimpleRules(clusterRoles []*v1.ClusterRole) ([]models.SimpleRule, error) {
|
||||
|
||||
clusterRules := make([]v1.PolicyRule, 0)
|
||||
|
||||
for _, v := range clusterRoles {
|
||||
clusterRules = append(clusterRules, v.Rules...)
|
||||
}
|
||||
|
||||
rules := make([]models.SimpleRule, 0)
|
||||
|
||||
for i := 0; i < len(policy.ClusterRoleRuleMapping); i++ {
|
||||
validActions := make([]string, 0)
|
||||
for j := 0; j < (len(policy.ClusterRoleRuleMapping[i].Actions)); j++ {
|
||||
if RulesMatchesAction(clusterRules, policy.ClusterRoleRuleMapping[i].Actions[j]) {
|
||||
validActions = append(validActions, policy.ClusterRoleRuleMapping[i].Actions[j].Name)
|
||||
}
|
||||
}
|
||||
if len(validActions) > 0 {
|
||||
rules = append(rules, models.SimpleRule{Name: policy.ClusterRoleRuleMapping[i].Name, Actions: validActions})
|
||||
}
|
||||
}
|
||||
|
||||
return rules, nil
|
||||
}
|
||||
|
||||
// Convert roles to rules
|
||||
func GetRoleSimpleRules(roles []*v1.Role, namespace string) (map[string][]models.SimpleRule, error) {
|
||||
|
||||
rulesMapping := make(map[string][]models.SimpleRule, 0)
|
||||
|
||||
policyRulesMapping := make(map[string][]v1.PolicyRule, 0)
|
||||
|
||||
for _, v := range roles {
|
||||
|
||||
if namespace != "" && v.Namespace != namespace {
|
||||
continue
|
||||
}
|
||||
|
||||
policyRules := policyRulesMapping[v.Namespace]
|
||||
|
||||
if policyRules == nil {
|
||||
policyRules = make([]v1.PolicyRule, 0)
|
||||
}
|
||||
|
||||
policyRules = append(policyRules, v.Rules...)
|
||||
|
||||
policyRulesMapping[v.Namespace] = policyRules
|
||||
}
|
||||
|
||||
for namespace, policyRules := range policyRulesMapping {
|
||||
|
||||
rules := make([]models.SimpleRule, 0)
|
||||
|
||||
for i := 0; i < len(policy.RoleRuleMapping); i++ {
|
||||
rule := models.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]) {
|
||||
rule.Actions = append(rule.Actions, policy.RoleRuleMapping[i].Actions[j].Name)
|
||||
}
|
||||
}
|
||||
if len(rule.Actions) > 0 {
|
||||
rules = append(rules, rule)
|
||||
}
|
||||
}
|
||||
|
||||
rulesMapping[namespace] = rules
|
||||
}
|
||||
|
||||
return rulesMapping, nil
|
||||
}
|
||||
|
||||
func CreateClusterRoleBinding(username string, clusterRoleName string) error {
|
||||
clusterRoleLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoles().Lister()
|
||||
_, err := clusterRoleLister.Get(clusterRoleName)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
clusterRoles, err := GetClusterRoles(username)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, clusterRole := range clusterRoles {
|
||||
|
||||
if clusterRole.Annotations["rbac.authorization.k8s.io/clusterrole"] == "true" {
|
||||
|
||||
if clusterRole.Name == clusterRoleName {
|
||||
return nil
|
||||
}
|
||||
|
||||
clusterRoleBindingName := clusterRole.Annotations["rbac.authorization.k8s.io/clusterrolebinding"]
|
||||
clusterRoleBindingLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoleBindings().Lister()
|
||||
clusterRoleBinding, err := clusterRoleBindingLister.Get(clusterRoleBindingName)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i, v := range clusterRoleBinding.Subjects {
|
||||
if v.Kind == v1.UserKind && v.Name == username {
|
||||
clusterRoleBinding.Subjects = append(clusterRoleBinding.Subjects[:i], clusterRoleBinding.Subjects[i+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
_, err = client.K8sClient().RbacV1().ClusterRoleBindings().Update(clusterRoleBinding)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
clusterRoleBindingLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoleBindings().Lister()
|
||||
clusterRoleBindings, err := clusterRoleBindingLister.List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var clusterRoleBinding *v1.ClusterRoleBinding
|
||||
|
||||
for _, roleBinding := range clusterRoleBindings {
|
||||
if roleBinding.Annotations != nil && roleBinding.Annotations["rbac.authorization.k8s.io/clusterrole"] == clusterRoleName &&
|
||||
roleBinding.RoleRef.Name == clusterRoleName {
|
||||
clusterRoleBinding = roleBinding
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if clusterRoleBinding != nil {
|
||||
clusterRoleBinding.Subjects = append(clusterRoleBinding.Subjects, v1.Subject{Kind: v1.UserKind, Name: username})
|
||||
_, err := client.K8sClient().RbacV1().ClusterRoleBindings().Update(clusterRoleBinding)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
clusterRoleBinding = new(v1.ClusterRoleBinding)
|
||||
clusterRoleBinding.Annotations = map[string]string{"rbac.authorization.k8s.io/clusterrole": clusterRoleName}
|
||||
clusterRoleBinding.Name = clusterRoleName
|
||||
clusterRoleBinding.RoleRef = v1.RoleRef{Name: clusterRoleName, Kind: ClusterRoleKind}
|
||||
clusterRoleBinding.Subjects = []v1.Subject{{Kind: v1.UserKind, Name: username}}
|
||||
|
||||
_, err = client.K8sClient().RbacV1().ClusterRoleBindings().Create(clusterRoleBinding)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetRole(namespace string, roleName string) (*v1.Role, error) {
|
||||
return informers.SharedInformerFactory().Rbac().V1().Roles().Lister().Roles(namespace).Get(roleName)
|
||||
}
|
||||
func GetClusterRole(clusterRoleName string) (*v1.ClusterRole, error) {
|
||||
clusterRoleLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoles().Lister()
|
||||
return clusterRoleLister.Get(clusterRoleName)
|
||||
}
|
||||
|
||||
func RulesMatchesAction(rules []v1.PolicyRule, action models.Action) bool {
|
||||
|
||||
for _, required := range action.Rules {
|
||||
if !rulesMatchesRequired(rules, required) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func rulesMatchesRequired(rules []v1.PolicyRule, required v1.PolicyRule) bool {
|
||||
for _, rule := range rules {
|
||||
if ruleMatchesRequired(rule, required) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func ruleMatchesRequired(rule v1.PolicyRule, required v1.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 v1.PolicyRule, apiGroup string, resource string, subresource string, resourceName string) bool {
|
||||
|
||||
if resource == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
if !hasString(rule.APIGroups, apiGroup) && !hasString(rule.APIGroups, v1.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 == v1.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 v1.PolicyRule, apiGroup string, nonResourceURL string, resource string, subresource string, resourceName string, verb string) bool {
|
||||
|
||||
if !hasString(rule.Verbs, verb) && !hasString(rule.Verbs, v1.VerbAll) {
|
||||
return false
|
||||
}
|
||||
|
||||
if nonResourceURL == "" {
|
||||
return ruleMatchesResources(rule, apiGroup, resource, subresource, resourceName)
|
||||
} else {
|
||||
return ruleMatchesNonResource(rule, nonResourceURL)
|
||||
}
|
||||
}
|
||||
|
||||
func ruleMatchesNonResource(rule v1.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
|
||||
}
|
||||
@@ -15,15 +15,40 @@
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
package hpa
|
||||
package iam
|
||||
|
||||
import (
|
||||
"k8s.io/api/autoscaling/v1"
|
||||
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
import "sync"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/client"
|
||||
)
|
||||
|
||||
func GetHPA(namespace, hpa string) (*v1.HorizontalPodAutoscaler, error) {
|
||||
return client.K8sClient().AutoscalingV1().HorizontalPodAutoscalers(namespace).Get(hpa, metaV1.GetOptions{})
|
||||
type Counter struct {
|
||||
value int
|
||||
m *sync.Mutex
|
||||
}
|
||||
|
||||
func NewCounter(value int) Counter {
|
||||
c := Counter{}
|
||||
c.m = &sync.Mutex{}
|
||||
c.Set(value)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Counter) Set(value int) {
|
||||
c.m.Lock()
|
||||
c.value = value
|
||||
c.m.Unlock()
|
||||
}
|
||||
|
||||
func (c *Counter) Add(value int) {
|
||||
c.m.Lock()
|
||||
c.value += value
|
||||
c.m.Unlock()
|
||||
}
|
||||
|
||||
func (c *Counter) Sub(value int) {
|
||||
c.m.Lock()
|
||||
c.value -= value
|
||||
c.m.Unlock()
|
||||
}
|
||||
|
||||
func (c *Counter) Get() int {
|
||||
return c.value
|
||||
}
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
|
||||
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
|
||||
|
||||
import (
|
||||
@@ -7,38 +24,22 @@ import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
v12 "k8s.io/client-go/listers/rbac/v1"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/api/rbac/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/kubernetes/pkg/util/slice"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
ksErr "kubesphere.io/kubesphere/pkg/errors"
|
||||
kserr "kubesphere.io/kubesphere/pkg/errors"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
)
|
||||
|
||||
const ClusterRoleKind = "ClusterRole"
|
||||
|
||||
var (
|
||||
clusterRoleBindingLister v12.ClusterRoleBindingLister
|
||||
clusterRoleLister v12.ClusterRoleLister
|
||||
roleBindingLister v12.RoleBindingLister
|
||||
roleLister v12.RoleLister
|
||||
)
|
||||
|
||||
func init() {
|
||||
clusterRoleBindingLister = informers.SharedInformerFactory().Rbac().V1().ClusterRoleBindings().Lister()
|
||||
clusterRoleLister = informers.SharedInformerFactory().Rbac().V1().ClusterRoles().Lister()
|
||||
roleBindingLister = informers.SharedInformerFactory().Rbac().V1().RoleBindings().Lister()
|
||||
roleLister = informers.SharedInformerFactory().Rbac().V1().Roles().Lister()
|
||||
}
|
||||
|
||||
// Get user list based on workspace role
|
||||
func WorkspaceRoleUsers(workspace string, roleName string) ([]User, error) {
|
||||
func WorkspaceRoleUsers(workspace string, roleName string) ([]models.User, error) {
|
||||
|
||||
clusterRoleBindingLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoleBindings().Lister()
|
||||
|
||||
workspaceRoleBinding, err := clusterRoleBindingLister.Get(fmt.Sprintf("system:%s:%s", workspace, roleName))
|
||||
|
||||
@@ -67,11 +68,11 @@ func WorkspaceRoleUsers(workspace string, roleName string) ([]User, error) {
|
||||
return users, nil
|
||||
}
|
||||
|
||||
func GetUsers(names []string) ([]User, error) {
|
||||
var users []User
|
||||
func GetUsers(names []string) ([]models.User, error) {
|
||||
var users []models.User
|
||||
|
||||
if names == nil || len(names) == 0 {
|
||||
return make([]User, 0), nil
|
||||
return make([]models.User, 0), nil
|
||||
}
|
||||
|
||||
result, err := http.Get(fmt.Sprintf("http://%s/apis/account.kubesphere.io/v1alpha1/users?name=%s", constants.AccountAPIServer, strings.Join(names, ",")))
|
||||
@@ -88,7 +89,7 @@ func GetUsers(names []string) ([]User, error) {
|
||||
}
|
||||
|
||||
if result.StatusCode > 200 {
|
||||
return nil, ksErr.Wrap(data)
|
||||
return nil, kserr.Parse(data)
|
||||
}
|
||||
|
||||
err = json.Unmarshal(data, &users)
|
||||
@@ -100,7 +101,7 @@ func GetUsers(names []string) ([]User, error) {
|
||||
return users, nil
|
||||
}
|
||||
|
||||
func GetUser(name string) (*User, error) {
|
||||
func GetUser(name string) (*models.User, error) {
|
||||
|
||||
result, err := http.Get(fmt.Sprintf("http://%s/apis/account.kubesphere.io/v1alpha1/users/%s", constants.AccountAPIServer, name))
|
||||
|
||||
@@ -116,10 +117,10 @@ func GetUser(name string) (*User, error) {
|
||||
}
|
||||
|
||||
if result.StatusCode > 200 {
|
||||
return nil, ksErr.Wrap(data)
|
||||
return nil, kserr.Parse(data)
|
||||
}
|
||||
|
||||
var user User
|
||||
var user models.User
|
||||
|
||||
err = json.Unmarshal(data, &user)
|
||||
|
||||
@@ -187,16 +188,8 @@ func GetUserNamespaces(username string, requiredRule v1.PolicyRule) (allNamespac
|
||||
return false, namespaces, nil
|
||||
}
|
||||
|
||||
func GetRole(namespace string, name string) (*v1.Role, error) {
|
||||
role, err := roleLister.Roles(namespace).Get(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return role.DeepCopy(), nil
|
||||
}
|
||||
|
||||
func GetWorkspaceUsers(workspace string, workspaceRole string) ([]string, error) {
|
||||
clusterRoleBindingLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoleBindings().Lister()
|
||||
clusterRoleBinding, err := clusterRoleBindingLister.Get(fmt.Sprintf("system:%s:%s", workspace, workspaceRole))
|
||||
|
||||
if err != nil {
|
||||
@@ -213,108 +206,6 @@ func GetWorkspaceUsers(workspace string, workspaceRole string) ([]string, error)
|
||||
return users, nil
|
||||
}
|
||||
|
||||
func GetClusterRole(name string) (*v1.ClusterRole, error) {
|
||||
|
||||
role, err := clusterRoleLister.Get(name)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return role.DeepCopy(), nil
|
||||
}
|
||||
|
||||
func GetRoles(namespace string, username string) ([]v1.Role, error) {
|
||||
roleBindings, err := roleBindingLister.RoleBindings(namespace).List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
roles := make([]v1.Role, 0)
|
||||
|
||||
for _, roleBinding := range roleBindings {
|
||||
|
||||
for _, subject := range roleBinding.Subjects {
|
||||
if subject.Kind == v1.UserKind && subject.Name == username {
|
||||
if roleBinding.RoleRef.Kind == ClusterRoleKind {
|
||||
clusterRole, err := clusterRoleLister.Get(roleBinding.RoleRef.Name)
|
||||
if err == nil {
|
||||
var role = v1.Role{TypeMeta: (*clusterRole).TypeMeta, ObjectMeta: (*clusterRole).ObjectMeta, Rules: (*clusterRole).Rules}
|
||||
role.Namespace = roleBinding.Namespace
|
||||
roles = append(roles, role)
|
||||
break
|
||||
} else if apierrors.IsNotFound(err) {
|
||||
glog.Infoln(err.Error())
|
||||
break
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
} else {
|
||||
if subject.Kind == v1.UserKind && subject.Name == username {
|
||||
role, err := roleLister.Roles(roleBinding.Namespace).Get(roleBinding.RoleRef.Name)
|
||||
if err == nil {
|
||||
roles = append(roles, *role)
|
||||
break
|
||||
} else if apierrors.IsNotFound(err) {
|
||||
glog.Infoln(err.Error())
|
||||
break
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return roles, nil
|
||||
}
|
||||
|
||||
// Get cluster roles by username
|
||||
func GetClusterRoles(username string) ([]v1.ClusterRole, error) {
|
||||
clusterRoleBindings, err := clusterRoleBindingLister.List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
roles := make([]v1.ClusterRole, 0)
|
||||
|
||||
for _, roleBinding := range clusterRoleBindings {
|
||||
for _, subject := range roleBinding.Subjects {
|
||||
if subject.Kind == v1.UserKind && subject.Name == username {
|
||||
if roleBinding.RoleRef.Kind == ClusterRoleKind {
|
||||
role, err := clusterRoleLister.Get(roleBinding.RoleRef.Name)
|
||||
if err == nil {
|
||||
role = role.DeepCopy()
|
||||
if role.Annotations == nil {
|
||||
role.Annotations = make(map[string]string, 0)
|
||||
}
|
||||
role.Annotations["rbac.authorization.k8s.io/clusterrolebinding"] = roleBinding.Name
|
||||
if roleBinding.Annotations != nil &&
|
||||
roleBinding.Annotations["rbac.authorization.k8s.io/clusterrole"] == roleBinding.RoleRef.Name {
|
||||
role.Annotations["rbac.authorization.k8s.io/clusterrole"] = "true"
|
||||
}
|
||||
roles = append(roles, *role)
|
||||
break
|
||||
} else if apierrors.IsNotFound(err) {
|
||||
glog.Warning(err)
|
||||
break
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return roles, nil
|
||||
}
|
||||
|
||||
func RulesMatchesRequired(rules []v1.PolicyRule, required v1.PolicyRule) bool {
|
||||
for _, rule := range rules {
|
||||
if ruleMatchesRequired(rule, required) {
|
||||
@@ -323,139 +214,3 @@ func RulesMatchesRequired(rules []v1.PolicyRule, required v1.PolicyRule) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func ruleMatchesRequired(rule v1.PolicyRule, required v1.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 v1.PolicyRule, apiGroup string, resource string, subresource string, resourceName string) bool {
|
||||
|
||||
if resource == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
if !hasString(rule.APIGroups, apiGroup) && !hasString(rule.APIGroups, v1.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 == v1.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 v1.PolicyRule, apiGroup string, nonResourceURL string, resource string, subresource string, resourceName string, verb string) bool {
|
||||
|
||||
if !hasString(rule.Verbs, verb) && !hasString(rule.Verbs, v1.VerbAll) {
|
||||
return false
|
||||
}
|
||||
|
||||
if nonResourceURL == "" {
|
||||
return ruleMatchesResources(rule, apiGroup, resource, subresource, resourceName)
|
||||
} else {
|
||||
return ruleMatchesNonResource(rule, nonResourceURL)
|
||||
}
|
||||
}
|
||||
|
||||
func ruleMatchesNonResource(rule v1.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
|
||||
}
|
||||
|
||||
1155
pkg/models/iam/im.go
Normal file
1155
pkg/models/iam/im.go
Normal file
File diff suppressed because it is too large
Load Diff
76
pkg/models/iam/path.go
Normal file
76
pkg/models/iam/path.go
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
|
||||
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
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"kubesphere.io/kubesphere/pkg/client"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func convertDNToPath(dn string) string {
|
||||
|
||||
paths := regexp.MustCompile("cn=[a-z0-9]([-a-z0-9]*[a-z0-9])?").FindAllString(dn, -1)
|
||||
|
||||
if len(paths) > 1 {
|
||||
for i := 0; i < len(paths); i++ {
|
||||
paths[i] = strings.Replace(paths[i], "cn=", "", 1)
|
||||
}
|
||||
for i, j := 0, len(paths)-1; i < j; i, j = i+1, j-1 {
|
||||
paths[i], paths[j] = paths[j], paths[i]
|
||||
}
|
||||
return strings.Join(paths, ":")
|
||||
} else if len(paths) == 1 {
|
||||
return strings.Replace(paths[0], "cn=", "", -1)
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func splitPath(path string) (searchBase string, cn string) {
|
||||
|
||||
paths := strings.Split(path, ":")
|
||||
length := len(paths)
|
||||
if length > 2 {
|
||||
|
||||
cn = paths[length-1]
|
||||
basePath := paths[:length-1]
|
||||
|
||||
for i := 0; i < len(basePath); i++ {
|
||||
basePath[i] = fmt.Sprintf("cn=%s", basePath[i])
|
||||
}
|
||||
|
||||
for i, j := 0, length-2; i < j; i, j = i+1, j-1 {
|
||||
basePath[i], basePath[j] = basePath[j], basePath[i]
|
||||
}
|
||||
|
||||
searchBase = fmt.Sprintf("%s,%s", strings.Join(basePath, ","), client.GroupSearchBase)
|
||||
} else if length == 2 {
|
||||
searchBase = fmt.Sprintf("cn=%s,%s", paths[0], client.GroupSearchBase)
|
||||
cn = paths[1]
|
||||
} else {
|
||||
searchBase = client.GroupSearchBase
|
||||
if paths[0] == "" {
|
||||
cn = "*"
|
||||
} else {
|
||||
cn = paths[0]
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
1333
pkg/models/iam/policy/policy.go
Normal file
1333
pkg/models/iam/policy/policy.go
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,39 +0,0 @@
|
||||
package iam
|
||||
|
||||
import (
|
||||
"k8s.io/api/rbac/v1"
|
||||
)
|
||||
|
||||
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"`
|
||||
Actions []string `json:"actions"`
|
||||
}
|
||||
|
||||
type User struct {
|
||||
Username string `json:"username"`
|
||||
Groups []string `json:"groups"`
|
||||
Password string `json:"password,omitempty"`
|
||||
AvatarUrl string `json:"avatar_url"`
|
||||
Description string `json:"description"`
|
||||
Email string `json:"email"`
|
||||
LastLoginTime string `json:"last_login_time"`
|
||||
Status int `json:"status"`
|
||||
ClusterRole string `json:"cluster_role"`
|
||||
ClusterRules []SimpleRule `json:"cluster_rules,omitempty"`
|
||||
Roles map[string]string `json:"roles,omitempty"`
|
||||
Rules map[string][]SimpleRule `json:"rules,omitempty"`
|
||||
Role string `json:"role,omitempty"`
|
||||
WorkspaceRoles map[string]string `json:"workspace_roles,omitempty"`
|
||||
WorkspaceRole string `json:"workspace_role,omitempty"`
|
||||
WorkspaceRules map[string][]SimpleRule `json:"workspace_rules,omitempty"`
|
||||
}
|
||||
@@ -258,7 +258,7 @@ func CreateKubeConfig(user string) error {
|
||||
configMap := v1.ConfigMap{TypeMeta: metaV1.TypeMeta{Kind: "Configmap", APIVersion: "v1"}, ObjectMeta: metaV1.ObjectMeta{Name: user}, Data: data}
|
||||
_, err = k8sClient.CoreV1().ConfigMaps(constants.KubeSphereControlNamespace).Create(&configMap)
|
||||
if err != nil && !errors.IsAlreadyExists(err) {
|
||||
glog.Errorf("create user %s's kubeConfig failed, reason: %s", user, err)
|
||||
glog.Errorf("create user %s's kubeConfig failed, reason: %v", user, err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -271,7 +271,7 @@ func GetKubeConfig(user string) (string, error) {
|
||||
k8sClient := client.K8sClient()
|
||||
configMap, err := k8sClient.CoreV1().ConfigMaps(constants.KubeSphereControlNamespace).Get(user, metaV1.GetOptions{})
|
||||
if err != nil {
|
||||
glog.Errorf("cannot get user %s's kubeConfig, reason: %s", user, err)
|
||||
glog.Errorf("cannot get user %s's kubeConfig, reason: %v", user, err)
|
||||
return "", err
|
||||
}
|
||||
return configMap.Data[kubectlConfigKey], nil
|
||||
@@ -287,7 +287,7 @@ func DelKubeConfig(user string) error {
|
||||
deletePolicy := metaV1.DeletePropagationBackground
|
||||
err = k8sClient.CoreV1().ConfigMaps(constants.KubeSphereControlNamespace).Delete(user, &metaV1.DeleteOptions{PropagationPolicy: &deletePolicy})
|
||||
if err != nil {
|
||||
glog.Errorf("delete user %s's kubeConfig failed, reason: %s", user, err)
|
||||
glog.Errorf("delete user %s's kubeConfig failed, reason: %v", user, err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -20,6 +20,7 @@ package kubectl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"math/rand"
|
||||
|
||||
"github.com/golang/glog"
|
||||
@@ -38,18 +39,12 @@ const (
|
||||
namespace = constants.KubeSphereControlNamespace
|
||||
)
|
||||
|
||||
type PodInfo struct {
|
||||
Namespace string `json:"namespace"`
|
||||
Pod string `json:"pod"`
|
||||
Container string `json:"container"`
|
||||
}
|
||||
|
||||
func GetKubectlPod(username string) (PodInfo, error) {
|
||||
func GetKubectlPod(username string) (models.PodInfo, error) {
|
||||
k8sClient := client.K8sClient()
|
||||
deploy, err := k8sClient.AppsV1beta2().Deployments(namespace).Get(username, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
glog.Errorln(err)
|
||||
return PodInfo{}, err
|
||||
return models.PodInfo{}, err
|
||||
}
|
||||
|
||||
selectors := deploy.Spec.Selector.MatchLabels
|
||||
@@ -57,16 +52,16 @@ func GetKubectlPod(username string) (PodInfo, error) {
|
||||
podList, err := k8sClient.CoreV1().Pods(namespace).List(metav1.ListOptions{LabelSelector: labelSelector})
|
||||
if err != nil {
|
||||
glog.Errorln(err)
|
||||
return PodInfo{}, err
|
||||
return models.PodInfo{}, err
|
||||
}
|
||||
|
||||
pod, err := selectCorrectPod(namespace, podList.Items)
|
||||
if err != nil {
|
||||
glog.Errorln(err)
|
||||
return PodInfo{}, err
|
||||
return models.PodInfo{}, err
|
||||
}
|
||||
|
||||
info := PodInfo{Namespace: pod.Namespace, Pod: pod.Name, Container: pod.Status.ContainerStatuses[0].Name}
|
||||
info := models.PodInfo{Namespace: pod.Namespace, Pod: pod.Name, Container: pod.Status.ContainerStatuses[0].Name}
|
||||
|
||||
return info, nil
|
||||
|
||||
|
||||
@@ -20,14 +20,13 @@ package metrics
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
v12 "k8s.io/client-go/listers/core/v1"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/models/components"
|
||||
@@ -50,7 +49,6 @@ import (
|
||||
var (
|
||||
jsonIter = jsoniter.ConfigCompatibleWithStandardLibrary
|
||||
nodeStatusDelLabel = []string{"endpoint", "instance", "job", "namespace", "pod", "service"}
|
||||
nodeLister v12.NodeLister
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -126,10 +124,6 @@ type OneComponentStatus struct {
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
nodeLister = informers.SharedInformerFactory().Core().V1().Nodes().Lister()
|
||||
}
|
||||
|
||||
func getAllWorkspaceNames(formatedMetric *FormatedMetric) map[string]int {
|
||||
|
||||
var wsMap = make(map[string]int)
|
||||
@@ -197,12 +191,12 @@ func unifyMetricHistoryTimeRange(fmtMetrics *FormatedMetric) {
|
||||
var timestampMap = make(map[float64]bool)
|
||||
|
||||
if fmtMetrics.Data.ResultType == ResultTypeMatrix {
|
||||
for i, _ := range fmtMetrics.Data.Result {
|
||||
for i := range fmtMetrics.Data.Result {
|
||||
values, exist := fmtMetrics.Data.Result[i][ResultItemValues]
|
||||
if exist {
|
||||
valueArray, sure := values.([]interface{})
|
||||
if sure {
|
||||
for j, _ := range valueArray {
|
||||
for j := range valueArray {
|
||||
timeAndValue := valueArray[j].([]interface{})
|
||||
timestampMap[float64(timeAndValue[0].(uint64))] = true
|
||||
}
|
||||
@@ -213,7 +207,7 @@ func unifyMetricHistoryTimeRange(fmtMetrics *FormatedMetric) {
|
||||
|
||||
timestampArray := make([]float64, len(timestampMap))
|
||||
i := 0
|
||||
for timestamp, _ := range timestampMap {
|
||||
for timestamp := range timestampMap {
|
||||
timestampArray[i] = timestamp
|
||||
i++
|
||||
}
|
||||
@@ -230,7 +224,7 @@ func unifyMetricHistoryTimeRange(fmtMetrics *FormatedMetric) {
|
||||
formatValueArray := make([][]interface{}, len(timestampArray))
|
||||
j := 0
|
||||
|
||||
for k, _ := range timestampArray {
|
||||
for k := range timestampArray {
|
||||
valueItem, sure := valueArray[j].([]interface{})
|
||||
if sure && float64(valueItem[0].(uint64)) == timestampArray[k] {
|
||||
formatValueArray[k] = []interface{}{int64(timestampArray[k]), valueItem[1]}
|
||||
@@ -294,7 +288,7 @@ func GetMetric(queryType, params, metricName string) *FormatedMetric {
|
||||
}
|
||||
|
||||
func GetNodeAddressInfo() *map[string][]v1.NodeAddress {
|
||||
|
||||
nodeLister := informers.SharedInformerFactory().Core().V1().Nodes().Lister()
|
||||
nodes, err := nodeLister.List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
@@ -938,7 +932,7 @@ func MonitorComponentStatus(monitoringRequest *client.MonitoringRequestParams) *
|
||||
nsStatus, exist := Components[ns]
|
||||
if exist {
|
||||
for _, nsStatusItem := range nsStatus.(map[string]interface{}) {
|
||||
component := nsStatusItem.(components.Component)
|
||||
component := nsStatusItem.(models.Component)
|
||||
namespaceComponentTotalMap[ns] += 1
|
||||
if component.HealthyBackends != 0 && component.HealthyBackends == component.TotalBackends {
|
||||
namespaceComponentHealthyMap[ns] += 1
|
||||
|
||||
@@ -33,7 +33,6 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/client"
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
)
|
||||
|
||||
func DrainNode(nodename string) (err error) {
|
||||
@@ -45,7 +44,7 @@ func DrainNode(nodename string) (err error) {
|
||||
}
|
||||
|
||||
if node.Spec.Unschedulable {
|
||||
return errors.New(errors.Conflict, fmt.Sprintf("node %s have been drained", nodename))
|
||||
return fmt.Errorf("node %s have been drained", nodename)
|
||||
}
|
||||
|
||||
data := []byte(" {\"spec\":{\"unschedulable\":true}}")
|
||||
|
||||
@@ -23,10 +23,10 @@ import (
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
v12 "k8s.io/client-go/listers/core/v1"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"kubesphere.io/kubesphere/pkg/models/resources"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -51,27 +51,17 @@ var (
|
||||
statefulsetsKey: resources.StatefulSets, persistentvolumeclaimsKey: resources.PersistentVolumeClaims, podsKey: resources.Pods,
|
||||
namespaceKey: resources.Namespaces, storageClassesKey: resources.StorageClasses, clusterRolesKey: resources.ClusterRoles,
|
||||
jobsKey: resources.Jobs, cronJobsKey: resources.CronJobs}
|
||||
resouceQuotaLister v12.ResourceQuotaLister
|
||||
)
|
||||
|
||||
type ResourceQuota struct {
|
||||
Namespace string `json:"namespace"`
|
||||
Data v1.ResourceQuotaStatus `json:"data"`
|
||||
}
|
||||
|
||||
func getUsage(namespace, resource string) (int, error) {
|
||||
list, err := resources.ListNamespaceResource(namespace, resource, "", "", false, -1, 0)
|
||||
list, err := resources.ListNamespaceResource(namespace, resource, ¶ms.Conditions{}, "", false, -1, 0)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return list.TotalCount, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
resouceQuotaLister = informers.SharedInformerFactory().Core().V1().ResourceQuotas().Lister()
|
||||
}
|
||||
|
||||
func GetClusterQuotas() (*ResourceQuota, error) {
|
||||
func GetClusterQuotas() (*models.ResourceQuota, error) {
|
||||
|
||||
quota := v1.ResourceQuotaStatus{Hard: make(v1.ResourceList), Used: make(v1.ResourceList)}
|
||||
|
||||
@@ -85,11 +75,11 @@ func GetClusterQuotas() (*ResourceQuota, error) {
|
||||
quota.Used[v1.ResourceName(k)] = quantity
|
||||
}
|
||||
|
||||
return &ResourceQuota{Namespace: "\"\"", Data: quota}, nil
|
||||
return &models.ResourceQuota{Namespace: "\"\"", Data: quota}, nil
|
||||
|
||||
}
|
||||
|
||||
func GetNamespaceQuotas(namespace string) (*ResourceQuota, error) {
|
||||
func GetNamespaceQuotas(namespace string) (*models.ResourceQuota, error) {
|
||||
quota, err := getNamespaceResourceQuota(namespace)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
@@ -115,7 +105,7 @@ func GetNamespaceQuotas(namespace string) (*ResourceQuota, error) {
|
||||
}
|
||||
}
|
||||
|
||||
return &ResourceQuota{Namespace: namespace, Data: *quota}, nil
|
||||
return &models.ResourceQuota{Namespace: namespace, Data: *quota}, nil
|
||||
}
|
||||
|
||||
func updateNamespaceQuota(tmpResourceList, resourceList v1.ResourceList) {
|
||||
@@ -135,7 +125,8 @@ func updateNamespaceQuota(tmpResourceList, resourceList v1.ResourceList) {
|
||||
}
|
||||
|
||||
func getNamespaceResourceQuota(namespace string) (*v1.ResourceQuotaStatus, error) {
|
||||
quotaList, err := resouceQuotaLister.ResourceQuotas(namespace).List(labels.Everything())
|
||||
resourceQuotaLister := informers.SharedInformerFactory().Core().V1().ResourceQuotas().Lister()
|
||||
quotaList, err := resourceQuotaLister.ResourceQuotas(namespace).List(labels.Everything())
|
||||
if err != nil || len(quotaList) == 0 {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -20,12 +20,11 @@ package registries
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/golang/glog"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
)
|
||||
|
||||
type AuthInfo struct {
|
||||
@@ -62,6 +61,6 @@ func RegistryVerify(authInfo AuthInfo) error {
|
||||
if resp.Status == loginSuccess {
|
||||
return nil
|
||||
} else {
|
||||
return errors.New(errors.VerifyFailed, resp.Status)
|
||||
return fmt.Errorf(resp.Status)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,19 +18,19 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
rbac "k8s.io/api/rbac/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/client-go/listers/rbac/v1"
|
||||
)
|
||||
|
||||
type clusterRoleSearcher struct {
|
||||
clusterRoleLister v1.ClusterRoleLister
|
||||
}
|
||||
|
||||
// exactly match
|
||||
// exactly Match
|
||||
func (*clusterRoleSearcher) match(match map[string]string, item *rbac.ClusterRole) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
@@ -45,7 +45,7 @@ func (*clusterRoleSearcher) match(match map[string]string, item *rbac.ClusterRol
|
||||
return true
|
||||
}
|
||||
|
||||
// fuzzy searchInNamespace
|
||||
// Fuzzy searchInNamespace
|
||||
func (*clusterRoleSearcher) fuzzy(fuzzy map[string]string, item *rbac.ClusterRole) bool {
|
||||
for k, v := range fuzzy {
|
||||
switch k {
|
||||
@@ -86,8 +86,8 @@ func (*clusterRoleSearcher) compare(a, b *rbac.ClusterRole, orderBy string) bool
|
||||
}
|
||||
}
|
||||
|
||||
func (s *clusterRoleSearcher) search(conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
clusterRoles, err := s.clusterRoleLister.List(labels.Everything())
|
||||
func (s *clusterRoleSearcher) search(conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
clusterRoles, err := informers.SharedInformerFactory().Rbac().V1().ClusterRoles().Lister().List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -95,11 +95,11 @@ func (s *clusterRoleSearcher) search(conditions *conditions, orderBy string, rev
|
||||
|
||||
result := make([]*rbac.ClusterRole, 0)
|
||||
|
||||
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 {
|
||||
if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
|
||||
result = clusterRoles
|
||||
} else {
|
||||
for _, item := range clusterRoles {
|
||||
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) {
|
||||
if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
|
||||
result = append(result, item)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,20 +18,19 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
lister "k8s.io/client-go/listers/core/v1"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
type configMapSearcher struct {
|
||||
configMapLister lister.ConfigMapLister
|
||||
}
|
||||
|
||||
// exactly match
|
||||
// exactly Match
|
||||
func (*configMapSearcher) match(match map[string]string, item *v1.ConfigMap) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
@@ -46,7 +45,7 @@ func (*configMapSearcher) match(match map[string]string, item *v1.ConfigMap) boo
|
||||
return true
|
||||
}
|
||||
|
||||
// fuzzy searchInNamespace
|
||||
// Fuzzy searchInNamespace
|
||||
func (*configMapSearcher) fuzzy(fuzzy map[string]string, item *v1.ConfigMap) bool {
|
||||
for k, v := range fuzzy {
|
||||
switch k {
|
||||
@@ -91,8 +90,8 @@ func (*configMapSearcher) compare(a, b *v1.ConfigMap, orderBy string) bool {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *configMapSearcher) search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
configMaps, err := s.configMapLister.ConfigMaps(namespace).List(labels.Everything())
|
||||
func (s *configMapSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
configMaps, err := informers.SharedInformerFactory().Core().V1().ConfigMaps().Lister().ConfigMaps(namespace).List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -100,11 +99,11 @@ func (s *configMapSearcher) search(namespace string, conditions *conditions, ord
|
||||
|
||||
result := make([]*v1.ConfigMap, 0)
|
||||
|
||||
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 {
|
||||
if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
|
||||
result = configMaps
|
||||
} else {
|
||||
for _, item := range configMaps {
|
||||
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) {
|
||||
if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
|
||||
result = append(result, item)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,28 +18,28 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
lister "k8s.io/client-go/listers/batch/v2alpha1"
|
||||
"k8s.io/api/batch/v1beta1"
|
||||
|
||||
"k8s.io/api/batch/v2alpha1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
type cronJobSearcher struct {
|
||||
cronJobLister lister.CronJobLister
|
||||
}
|
||||
|
||||
func cronJobStatus(item *v2alpha1.CronJob) string {
|
||||
func cronJobStatus(item *v1beta1.CronJob) string {
|
||||
if item.Spec.Suspend != nil && *item.Spec.Suspend {
|
||||
return paused
|
||||
}
|
||||
return running
|
||||
}
|
||||
|
||||
// Exactly match
|
||||
func (*cronJobSearcher) match(match map[string]string, item *v2alpha1.CronJob) bool {
|
||||
// Exactly Match
|
||||
func (*cronJobSearcher) match(match map[string]string, item *v1beta1.CronJob) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
case status:
|
||||
@@ -53,7 +53,7 @@ func (*cronJobSearcher) match(match map[string]string, item *v2alpha1.CronJob) b
|
||||
return true
|
||||
}
|
||||
|
||||
func (*cronJobSearcher) fuzzy(fuzzy map[string]string, item *v2alpha1.CronJob) bool {
|
||||
func (*cronJobSearcher) fuzzy(fuzzy map[string]string, item *v1beta1.CronJob) bool {
|
||||
|
||||
for k, v := range fuzzy {
|
||||
switch k {
|
||||
@@ -88,7 +88,7 @@ func (*cronJobSearcher) fuzzy(fuzzy map[string]string, item *v2alpha1.CronJob) b
|
||||
return true
|
||||
}
|
||||
|
||||
func (*cronJobSearcher) compare(a, b *v2alpha1.CronJob, orderBy string) bool {
|
||||
func (*cronJobSearcher) compare(a, b *v1beta1.CronJob, orderBy string) bool {
|
||||
switch orderBy {
|
||||
case createTime:
|
||||
return a.CreationTimestamp.Time.After(b.CreationTimestamp.Time)
|
||||
@@ -99,20 +99,20 @@ func (*cronJobSearcher) compare(a, b *v2alpha1.CronJob, orderBy string) bool {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *cronJobSearcher) search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
cronJobs, err := s.cronJobLister.CronJobs(namespace).List(labels.Everything())
|
||||
func (s *cronJobSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
cronJobs, err := informers.SharedInformerFactory().Batch().V1beta1().CronJobs().Lister().CronJobs(namespace).List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make([]*v2alpha1.CronJob, 0)
|
||||
result := make([]*v1beta1.CronJob, 0)
|
||||
|
||||
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 {
|
||||
if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
|
||||
result = cronJobs
|
||||
} else {
|
||||
for _, item := range cronJobs {
|
||||
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) {
|
||||
if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
|
||||
result = append(result, item)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,17 +18,16 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
lister "k8s.io/client-go/listers/apps/v1"
|
||||
|
||||
"k8s.io/api/apps/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
type daemonSetSearcher struct {
|
||||
daemonSetLister lister.DaemonSetLister
|
||||
}
|
||||
|
||||
func daemonSetStatus(item *v1.DaemonSet) string {
|
||||
@@ -41,7 +40,7 @@ func daemonSetStatus(item *v1.DaemonSet) string {
|
||||
}
|
||||
}
|
||||
|
||||
// Exactly match
|
||||
// Exactly Match
|
||||
func (*daemonSetSearcher) match(match map[string]string, item *v1.DaemonSet) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
@@ -102,8 +101,8 @@ func (*daemonSetSearcher) compare(a, b *v1.DaemonSet, orderBy string) bool {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *daemonSetSearcher) search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
daemonSets, err := s.daemonSetLister.DaemonSets(namespace).List(labels.Everything())
|
||||
func (s *daemonSetSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
daemonSets, err := informers.SharedInformerFactory().Apps().V1().DaemonSets().Lister().DaemonSets(namespace).List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -111,11 +110,11 @@ func (s *daemonSetSearcher) search(namespace string, conditions *conditions, ord
|
||||
|
||||
result := make([]*v1.DaemonSet, 0)
|
||||
|
||||
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 {
|
||||
if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
|
||||
result = daemonSets
|
||||
} else {
|
||||
for _, item := range daemonSets {
|
||||
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) {
|
||||
if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
|
||||
result = append(result, item)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,18 +18,17 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
lister "k8s.io/client-go/listers/apps/v1"
|
||||
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
|
||||
"k8s.io/api/apps/v1"
|
||||
)
|
||||
|
||||
type deploymentSearcher struct {
|
||||
deploymentLister lister.DeploymentLister
|
||||
}
|
||||
|
||||
func deploymentStatus(item *v1.Deployment) string {
|
||||
@@ -45,7 +44,7 @@ func deploymentStatus(item *v1.Deployment) string {
|
||||
return stopped
|
||||
}
|
||||
|
||||
// Exactly match
|
||||
// Exactly Match
|
||||
func (*deploymentSearcher) match(match map[string]string, item *v1.Deployment) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
@@ -106,8 +105,8 @@ func (*deploymentSearcher) compare(a, b *v1.Deployment, orderBy string) bool {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *deploymentSearcher) search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
deployments, err := s.deploymentLister.Deployments(namespace).List(labels.Everything())
|
||||
func (s *deploymentSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
deployments, err := informers.SharedInformerFactory().Apps().V1().Deployments().Lister().Deployments(namespace).List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -115,11 +114,11 @@ func (s *deploymentSearcher) search(namespace string, conditions *conditions, or
|
||||
|
||||
result := make([]*v1.Deployment, 0)
|
||||
|
||||
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 {
|
||||
if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
|
||||
result = deployments
|
||||
} else {
|
||||
for _, item := range deployments {
|
||||
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) {
|
||||
if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
|
||||
result = append(result, item)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,21 +18,20 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
lister "k8s.io/client-go/listers/extensions/v1beta1"
|
||||
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
type ingressSearcher struct {
|
||||
ingressLister lister.IngressLister
|
||||
}
|
||||
|
||||
// exactly match
|
||||
// exactly Match
|
||||
func (*ingressSearcher) match(match map[string]string, item *extensions.Ingress) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
@@ -47,7 +46,7 @@ func (*ingressSearcher) match(match map[string]string, item *extensions.Ingress)
|
||||
return true
|
||||
}
|
||||
|
||||
// fuzzy searchInNamespace
|
||||
// Fuzzy searchInNamespace
|
||||
func (*ingressSearcher) fuzzy(fuzzy map[string]string, item *extensions.Ingress) bool {
|
||||
for k, v := range fuzzy {
|
||||
switch k {
|
||||
@@ -92,8 +91,8 @@ func (*ingressSearcher) compare(a, b *extensions.Ingress, orderBy string) bool {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ingressSearcher) search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
ingresses, err := s.ingressLister.Ingresses(namespace).List(labels.Everything())
|
||||
func (s *ingressSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
ingresses, err := informers.SharedInformerFactory().Extensions().V1beta1().Ingresses().Lister().Ingresses(namespace).List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -101,11 +100,11 @@ func (s *ingressSearcher) search(namespace string, conditions *conditions, order
|
||||
|
||||
result := make([]*extensions.Ingress, 0)
|
||||
|
||||
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 {
|
||||
if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
|
||||
result = ingresses
|
||||
} else {
|
||||
for _, item := range ingresses {
|
||||
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) {
|
||||
if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
|
||||
result = append(result, item)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,37 +18,36 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
lister "k8s.io/client-go/listers/batch/v1"
|
||||
|
||||
batchV1 "k8s.io/api/batch/v1"
|
||||
coreV1 "k8s.io/api/core/v1"
|
||||
batchv1 "k8s.io/api/batch/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
type jobSearcher struct {
|
||||
jobLister lister.JobLister
|
||||
}
|
||||
|
||||
func jobStatus(item *batchV1.Job) string {
|
||||
func jobStatus(item *batchv1.Job) string {
|
||||
status := ""
|
||||
|
||||
for _, condition := range item.Status.Conditions {
|
||||
if condition.Type == batchV1.JobFailed && condition.Status == coreV1.ConditionTrue {
|
||||
if condition.Type == batchv1.JobFailed && condition.Status == corev1.ConditionTrue {
|
||||
status = failed
|
||||
}
|
||||
if condition.Type == batchV1.JobComplete && condition.Status == coreV1.ConditionTrue {
|
||||
if condition.Type == batchv1.JobComplete && condition.Status == corev1.ConditionTrue {
|
||||
status = complete
|
||||
}
|
||||
}
|
||||
return status
|
||||
}
|
||||
|
||||
// Exactly match
|
||||
func (*jobSearcher) match(match map[string]string, item *batchV1.Job) bool {
|
||||
// Exactly Match
|
||||
func (*jobSearcher) match(match map[string]string, item *batchv1.Job) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
case status:
|
||||
@@ -62,7 +61,7 @@ func (*jobSearcher) match(match map[string]string, item *batchV1.Job) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (*jobSearcher) fuzzy(fuzzy map[string]string, item *batchV1.Job) bool {
|
||||
func (*jobSearcher) fuzzy(fuzzy map[string]string, item *batchv1.Job) bool {
|
||||
|
||||
for k, v := range fuzzy {
|
||||
switch k {
|
||||
@@ -97,7 +96,7 @@ func (*jobSearcher) fuzzy(fuzzy map[string]string, item *batchV1.Job) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func jobUpdateTime(item *batchV1.Job) time.Time {
|
||||
func jobUpdateTime(item *batchv1.Job) time.Time {
|
||||
updateTime := item.CreationTimestamp.Time
|
||||
for _, condition := range item.Status.Conditions {
|
||||
if updateTime.Before(condition.LastProbeTime.Time) {
|
||||
@@ -110,7 +109,7 @@ func jobUpdateTime(item *batchV1.Job) time.Time {
|
||||
return updateTime
|
||||
}
|
||||
|
||||
func (*jobSearcher) compare(a, b *batchV1.Job, orderBy string) bool {
|
||||
func (*jobSearcher) compare(a, b *batchv1.Job, orderBy string) bool {
|
||||
switch orderBy {
|
||||
case updateTime:
|
||||
return jobUpdateTime(a).After(jobUpdateTime(b))
|
||||
@@ -121,20 +120,20 @@ func (*jobSearcher) compare(a, b *batchV1.Job, orderBy string) bool {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *jobSearcher) search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
jobs, err := s.jobLister.Jobs(namespace).List(labels.Everything())
|
||||
func (s *jobSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
jobs, err := informers.SharedInformerFactory().Batch().V1().Jobs().Lister().Jobs(namespace).List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make([]*batchV1.Job, 0)
|
||||
result := make([]*batchv1.Job, 0)
|
||||
|
||||
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 {
|
||||
if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
|
||||
result = jobs
|
||||
} else {
|
||||
for _, item := range jobs {
|
||||
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) {
|
||||
if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
|
||||
result = append(result, item)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,19 +18,19 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
lister "k8s.io/client-go/listers/core/v1"
|
||||
)
|
||||
|
||||
type namespaceSearcher struct {
|
||||
namespaceLister lister.NamespaceLister
|
||||
}
|
||||
|
||||
// exactly match
|
||||
// exactly Match
|
||||
func (*namespaceSearcher) match(match map[string]string, item *v1.Namespace) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
@@ -45,7 +45,7 @@ func (*namespaceSearcher) match(match map[string]string, item *v1.Namespace) boo
|
||||
return true
|
||||
}
|
||||
|
||||
// fuzzy searchInNamespace
|
||||
// Fuzzy searchInNamespace
|
||||
func (*namespaceSearcher) fuzzy(fuzzy map[string]string, item *v1.Namespace) bool {
|
||||
for k, v := range fuzzy {
|
||||
switch k {
|
||||
@@ -90,8 +90,8 @@ func (*namespaceSearcher) compare(a, b *v1.Namespace, orderBy string) bool {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *namespaceSearcher) search(conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
namespaces, err := s.namespaceLister.List(labels.Everything())
|
||||
func (s *namespaceSearcher) search(conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
namespaces, err := informers.SharedInformerFactory().Core().V1().Namespaces().Lister().List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -99,11 +99,11 @@ func (s *namespaceSearcher) search(conditions *conditions, orderBy string, rever
|
||||
|
||||
result := make([]*v1.Namespace, 0)
|
||||
|
||||
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 {
|
||||
if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
|
||||
result = namespaces
|
||||
} else {
|
||||
for _, item := range namespaces {
|
||||
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) {
|
||||
if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
|
||||
result = append(result, item)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,19 +18,19 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
lister "k8s.io/client-go/listers/core/v1"
|
||||
)
|
||||
|
||||
type nodeSearcher struct {
|
||||
nodeLister lister.NodeLister
|
||||
}
|
||||
|
||||
// exactly match
|
||||
// exactly Match
|
||||
func (*nodeSearcher) match(match map[string]string, item *v1.Node) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
@@ -45,7 +45,7 @@ func (*nodeSearcher) match(match map[string]string, item *v1.Node) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// fuzzy searchInNamespace
|
||||
// Fuzzy searchInNamespace
|
||||
func (*nodeSearcher) fuzzy(fuzzy map[string]string, item *v1.Node) bool {
|
||||
for k, v := range fuzzy {
|
||||
switch k {
|
||||
@@ -90,8 +90,8 @@ func (*nodeSearcher) compare(a, b *v1.Node, orderBy string) bool {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *nodeSearcher) search(conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
nodes, err := s.nodeLister.List(labels.Everything())
|
||||
func (s *nodeSearcher) search(conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
nodes, err := informers.SharedInformerFactory().Core().V1().Nodes().Lister().List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -99,11 +99,11 @@ func (s *nodeSearcher) search(conditions *conditions, orderBy string, reverse bo
|
||||
|
||||
result := make([]*v1.Node, 0)
|
||||
|
||||
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 {
|
||||
if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
|
||||
result = nodes
|
||||
} else {
|
||||
for _, item := range nodes {
|
||||
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) {
|
||||
if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
|
||||
result = append(result, item)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,20 +18,19 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
lister "k8s.io/client-go/listers/core/v1"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
type persistentVolumeClaimSearcher struct {
|
||||
persistentVolumeClaimLister lister.PersistentVolumeClaimLister
|
||||
}
|
||||
|
||||
// exactly match
|
||||
// exactly Match
|
||||
func (*persistentVolumeClaimSearcher) match(match map[string]string, item *v1.PersistentVolumeClaim) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
@@ -46,7 +45,7 @@ func (*persistentVolumeClaimSearcher) match(match map[string]string, item *v1.Pe
|
||||
return true
|
||||
}
|
||||
|
||||
// fuzzy searchInNamespace
|
||||
// Fuzzy searchInNamespace
|
||||
func (*persistentVolumeClaimSearcher) fuzzy(fuzzy map[string]string, item *v1.PersistentVolumeClaim) bool {
|
||||
for k, v := range fuzzy {
|
||||
switch k {
|
||||
@@ -91,8 +90,8 @@ func (*persistentVolumeClaimSearcher) compare(a, b *v1.PersistentVolumeClaim, or
|
||||
}
|
||||
}
|
||||
|
||||
func (s *persistentVolumeClaimSearcher) search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
persistentVolumeClaims, err := s.persistentVolumeClaimLister.PersistentVolumeClaims(namespace).List(labels.Everything())
|
||||
func (s *persistentVolumeClaimSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
persistentVolumeClaims, err := informers.SharedInformerFactory().Core().V1().PersistentVolumeClaims().Lister().PersistentVolumeClaims(namespace).List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -100,11 +99,11 @@ func (s *persistentVolumeClaimSearcher) search(namespace string, conditions *con
|
||||
|
||||
result := make([]*v1.PersistentVolumeClaim, 0)
|
||||
|
||||
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 {
|
||||
if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
|
||||
result = persistentVolumeClaims
|
||||
} else {
|
||||
for _, item := range persistentVolumeClaims {
|
||||
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) {
|
||||
if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
|
||||
result = append(result, item)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,20 +18,19 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
v12 "k8s.io/client-go/listers/core/v1"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
type podSearcher struct {
|
||||
podLister v12.PodLister
|
||||
}
|
||||
|
||||
// exactly match
|
||||
// exactly Match
|
||||
func (*podSearcher) match(match map[string]string, item *v1.Pod) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
@@ -46,7 +45,7 @@ func (*podSearcher) match(match map[string]string, item *v1.Pod) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// fuzzy searchInNamespace
|
||||
// Fuzzy searchInNamespace
|
||||
func (*podSearcher) fuzzy(fuzzy map[string]string, item *v1.Pod) bool {
|
||||
for k, v := range fuzzy {
|
||||
switch k {
|
||||
@@ -91,9 +90,9 @@ func (*podSearcher) compare(a, b *v1.Pod, orderBy string) bool {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *podSearcher) search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
func (s *podSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
|
||||
pods, err := s.podLister.Pods(namespace).List(labels.Everything())
|
||||
pods, err := informers.SharedInformerFactory().Core().V1().Pods().Lister().Pods(namespace).List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -101,11 +100,11 @@ func (s *podSearcher) search(namespace string, conditions *conditions, orderBy s
|
||||
|
||||
result := make([]*v1.Pod, 0)
|
||||
|
||||
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 {
|
||||
if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
|
||||
result = pods
|
||||
} else {
|
||||
for _, item := range pods {
|
||||
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) {
|
||||
if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
|
||||
result = append(result, item)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,74 +18,35 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"fmt"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
"strings"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
)
|
||||
|
||||
func init() {
|
||||
namespacedResources[ConfigMaps] = &configMapSearcher{
|
||||
configMapLister: informers.SharedInformerFactory().Core().V1().ConfigMaps().Lister(),
|
||||
}
|
||||
namespacedResources[CronJobs] = &cronJobSearcher{
|
||||
cronJobLister: informers.SharedInformerFactory().Batch().V2alpha1().CronJobs().Lister(),
|
||||
}
|
||||
namespacedResources[DaemonSets] = &daemonSetSearcher{
|
||||
daemonSetLister: informers.SharedInformerFactory().Apps().V1().DaemonSets().Lister(),
|
||||
}
|
||||
namespacedResources[Deployments] = &deploymentSearcher{
|
||||
deploymentLister: informers.SharedInformerFactory().Apps().V1().Deployments().Lister(),
|
||||
}
|
||||
namespacedResources[Ingresses] = &ingressSearcher{
|
||||
ingressLister: informers.SharedInformerFactory().Extensions().V1beta1().Ingresses().Lister(),
|
||||
}
|
||||
namespacedResources[Jobs] = &jobSearcher{
|
||||
jobLister: informers.SharedInformerFactory().Batch().V1().Jobs().Lister(),
|
||||
}
|
||||
namespacedResources[PersistentVolumeClaims] = &persistentVolumeClaimSearcher{
|
||||
persistentVolumeClaimLister: informers.SharedInformerFactory().Core().V1().PersistentVolumeClaims().Lister(),
|
||||
}
|
||||
namespacedResources[Secrets] = &secretSearcher{
|
||||
secretLister: informers.SharedInformerFactory().Core().V1().Secrets().Lister(),
|
||||
}
|
||||
namespacedResources[Services] = &serviceSearcher{
|
||||
serviceLister: informers.SharedInformerFactory().Core().V1().Services().Lister(),
|
||||
}
|
||||
namespacedResources[StatefulSets] = &statefulSetSearcher{
|
||||
statefulSetLister: informers.SharedInformerFactory().Apps().V1().StatefulSets().Lister(),
|
||||
}
|
||||
namespacedResources[Pods] = &podSearcher{
|
||||
podLister: informers.SharedInformerFactory().Core().V1().Pods().Lister(),
|
||||
}
|
||||
namespacedResources[Roles] = &roleSearcher{
|
||||
roleLister: informers.SharedInformerFactory().Rbac().V1().Roles().Lister(),
|
||||
}
|
||||
namespacedResources[ConfigMaps] = &configMapSearcher{}
|
||||
namespacedResources[CronJobs] = &cronJobSearcher{}
|
||||
namespacedResources[DaemonSets] = &daemonSetSearcher{}
|
||||
namespacedResources[Deployments] = &deploymentSearcher{}
|
||||
namespacedResources[Ingresses] = &ingressSearcher{}
|
||||
namespacedResources[Jobs] = &jobSearcher{}
|
||||
namespacedResources[PersistentVolumeClaims] = &persistentVolumeClaimSearcher{}
|
||||
namespacedResources[Secrets] = &secretSearcher{}
|
||||
namespacedResources[Services] = &serviceSearcher{}
|
||||
namespacedResources[StatefulSets] = &statefulSetSearcher{}
|
||||
namespacedResources[Pods] = &podSearcher{}
|
||||
namespacedResources[Roles] = &roleSearcher{}
|
||||
|
||||
clusterResources[Nodes] = &nodeSearcher{
|
||||
nodeLister: informers.SharedInformerFactory().Core().V1().Nodes().Lister(),
|
||||
}
|
||||
clusterResources[Namespaces] = &namespaceSearcher{
|
||||
namespaceLister: informers.SharedInformerFactory().Core().V1().Namespaces().Lister(),
|
||||
}
|
||||
clusterResources[ClusterRoles] = &clusterRoleSearcher{
|
||||
clusterRoleLister: informers.SharedInformerFactory().Rbac().V1().ClusterRoles().Lister(),
|
||||
}
|
||||
clusterResources[StorageClasses] = &storageClassesSearcher{
|
||||
storageClassesLister: informers.SharedInformerFactory().Storage().V1().StorageClasses().Lister(),
|
||||
}
|
||||
clusterResources[Nodes] = &nodeSearcher{}
|
||||
clusterResources[Namespaces] = &namespaceSearcher{}
|
||||
clusterResources[ClusterRoles] = &clusterRoleSearcher{}
|
||||
clusterResources[StorageClasses] = &storageClassesSearcher{}
|
||||
}
|
||||
|
||||
var namespacedResources = make(map[string]namespacedSearcherInterface)
|
||||
var clusterResources = make(map[string]clusterSearcherInterface)
|
||||
|
||||
type conditions struct {
|
||||
match map[string]string
|
||||
fuzzy map[string]string
|
||||
}
|
||||
|
||||
const (
|
||||
name = "name"
|
||||
label = "label"
|
||||
@@ -123,33 +84,26 @@ const (
|
||||
)
|
||||
|
||||
type namespacedSearcherInterface interface {
|
||||
search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error)
|
||||
search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error)
|
||||
}
|
||||
type clusterSearcherInterface interface {
|
||||
search(conditions *conditions, orderBy string, reverse bool) ([]interface{}, error)
|
||||
search(conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error)
|
||||
}
|
||||
|
||||
func ListNamespaceResource(namespace, resource, conditionStr, orderBy string, reverse bool, limit, offset int) (*ResourceList, error) {
|
||||
func ListNamespaceResource(namespace, resource string, conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
|
||||
items := make([]interface{}, 0)
|
||||
total := 0
|
||||
var err error
|
||||
|
||||
conditions, err := parseToConditions(conditionStr)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var result []interface{}
|
||||
|
||||
if searcher, ok := namespacedResources[resource]; ok {
|
||||
result, err = searcher.search(namespace, conditions, orderBy, reverse)
|
||||
} else {
|
||||
return nil, errors.New(errors.NotImplement, "not support")
|
||||
return nil, fmt.Errorf("not support")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.New(errors.Internal, err.Error())
|
||||
return nil, err
|
||||
}
|
||||
|
||||
total = len(result)
|
||||
@@ -160,16 +114,14 @@ func ListNamespaceResource(namespace, resource, conditionStr, orderBy string, re
|
||||
}
|
||||
}
|
||||
|
||||
return &ResourceList{TotalCount: total, Items: items}, nil
|
||||
return &models.PageableResponse{TotalCount: total, Items: items}, nil
|
||||
}
|
||||
|
||||
func ListClusterResource(resource, conditionStr, orderBy string, reverse bool, limit, offset int) (*ResourceList, error) {
|
||||
func ListClusterResource(resource string, conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
|
||||
items := make([]interface{}, 0)
|
||||
total := 0
|
||||
var err error
|
||||
|
||||
conditions, err := parseToConditions(conditionStr)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -179,11 +131,11 @@ func ListClusterResource(resource, conditionStr, orderBy string, reverse bool, l
|
||||
if searcher, ok := clusterResources[resource]; ok {
|
||||
result, err = searcher.search(conditions, orderBy, reverse)
|
||||
} else {
|
||||
return nil, errors.New(errors.NotImplement, "not support")
|
||||
return nil, fmt.Errorf("not support")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.New(errors.Internal, err.Error())
|
||||
return nil, err
|
||||
}
|
||||
|
||||
total = len(result)
|
||||
@@ -194,36 +146,7 @@ func ListClusterResource(resource, conditionStr, orderBy string, reverse bool, l
|
||||
}
|
||||
}
|
||||
|
||||
return &ResourceList{TotalCount: total, Items: items}, nil
|
||||
}
|
||||
|
||||
func parseToConditions(str string) (*conditions, error) {
|
||||
conditions := &conditions{match: make(map[string]string, 0), fuzzy: make(map[string]string, 0)}
|
||||
|
||||
if str == "" {
|
||||
return conditions, nil
|
||||
}
|
||||
|
||||
for _, item := range strings.Split(str, ",") {
|
||||
if strings.Count(item, "=") > 1 || strings.Count(item, "~") > 1 {
|
||||
return nil, errors.New(errors.InvalidArgument, "invalid condition")
|
||||
}
|
||||
if groups := regexp.MustCompile(`(\S+)([=~])(\S+)`).FindStringSubmatch(item); len(groups) == 4 {
|
||||
if groups[2] == "=" {
|
||||
conditions.match[groups[1]] = groups[3]
|
||||
} else {
|
||||
conditions.fuzzy[groups[1]] = groups[3]
|
||||
}
|
||||
} else {
|
||||
return nil, errors.New(errors.InvalidArgument, "invalid condition")
|
||||
}
|
||||
}
|
||||
return conditions, nil
|
||||
}
|
||||
|
||||
type ResourceList struct {
|
||||
TotalCount int `json:"total_count"`
|
||||
Items []interface{} `json:"items"`
|
||||
return &models.PageableResponse{TotalCount: total, Items: items}, nil
|
||||
}
|
||||
|
||||
func searchFuzzy(m map[string]string, key, value string) bool {
|
||||
|
||||
@@ -18,20 +18,19 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
rbac "k8s.io/api/rbac/v1"
|
||||
lister "k8s.io/client-go/listers/rbac/v1"
|
||||
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
type roleSearcher struct {
|
||||
roleLister lister.RoleLister
|
||||
}
|
||||
|
||||
// exactly match
|
||||
// exactly Match
|
||||
func (*roleSearcher) match(match map[string]string, item *rbac.Role) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
@@ -46,7 +45,7 @@ func (*roleSearcher) match(match map[string]string, item *rbac.Role) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// fuzzy searchInNamespace
|
||||
// Fuzzy searchInNamespace
|
||||
func (*roleSearcher) fuzzy(fuzzy map[string]string, item *rbac.Role) bool {
|
||||
for k, v := range fuzzy {
|
||||
switch k {
|
||||
@@ -87,8 +86,8 @@ func (*roleSearcher) compare(a, b *rbac.Role, orderBy string) bool {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *roleSearcher) search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
roles, err := s.roleLister.Roles(namespace).List(labels.Everything())
|
||||
func (s *roleSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
roles, err := informers.SharedInformerFactory().Rbac().V1().Roles().Lister().Roles(namespace).List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -96,11 +95,11 @@ func (s *roleSearcher) search(namespace string, conditions *conditions, orderBy
|
||||
|
||||
result := make([]*rbac.Role, 0)
|
||||
|
||||
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 {
|
||||
if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
|
||||
result = roles
|
||||
} else {
|
||||
for _, item := range roles {
|
||||
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) {
|
||||
if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
|
||||
result = append(result, item)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,20 +18,19 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
lister "k8s.io/client-go/listers/core/v1"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
type secretSearcher struct {
|
||||
secretLister lister.SecretLister
|
||||
}
|
||||
|
||||
// exactly match
|
||||
// exactly Match
|
||||
func (*secretSearcher) match(match map[string]string, item *v1.Secret) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
@@ -50,7 +49,7 @@ func (*secretSearcher) match(match map[string]string, item *v1.Secret) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// fuzzy searchInNamespace
|
||||
// Fuzzy searchInNamespace
|
||||
func (*secretSearcher) fuzzy(fuzzy map[string]string, item *v1.Secret) bool {
|
||||
for k, v := range fuzzy {
|
||||
switch k {
|
||||
@@ -95,8 +94,8 @@ func (*secretSearcher) compare(a, b *v1.Secret, orderBy string) bool {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *secretSearcher) search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
secrets, err := s.secretLister.Secrets(namespace).List(labels.Everything())
|
||||
func (s *secretSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
secrets, err := informers.SharedInformerFactory().Core().V1().Secrets().Lister().Secrets(namespace).List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -104,11 +103,11 @@ func (s *secretSearcher) search(namespace string, conditions *conditions, orderB
|
||||
|
||||
result := make([]*v1.Secret, 0)
|
||||
|
||||
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 {
|
||||
if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
|
||||
result = secrets
|
||||
} else {
|
||||
for _, item := range secrets {
|
||||
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) {
|
||||
if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
|
||||
result = append(result, item)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,20 +18,19 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
lister "k8s.io/client-go/listers/core/v1"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
type serviceSearcher struct {
|
||||
serviceLister lister.ServiceLister
|
||||
}
|
||||
|
||||
// exactly match
|
||||
// exactly Match
|
||||
func (*serviceSearcher) match(match map[string]string, item *v1.Service) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
@@ -46,7 +45,7 @@ func (*serviceSearcher) match(match map[string]string, item *v1.Service) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// fuzzy searchInNamespace
|
||||
// Fuzzy searchInNamespace
|
||||
func (*serviceSearcher) fuzzy(fuzzy map[string]string, item *v1.Service) bool {
|
||||
for k, v := range fuzzy {
|
||||
switch k {
|
||||
@@ -91,8 +90,8 @@ func (*serviceSearcher) compare(a, b *v1.Service, orderBy string) bool {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *serviceSearcher) search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
services, err := s.serviceLister.Services(namespace).List(labels.Everything())
|
||||
func (s *serviceSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
services, err := informers.SharedInformerFactory().Core().V1().Services().Lister().Services(namespace).List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -100,11 +99,11 @@ func (s *serviceSearcher) search(namespace string, conditions *conditions, order
|
||||
|
||||
result := make([]*v1.Service, 0)
|
||||
|
||||
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 {
|
||||
if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
|
||||
result = services
|
||||
} else {
|
||||
for _, item := range services {
|
||||
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) {
|
||||
if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
|
||||
result = append(result, item)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,17 +18,16 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
lister "k8s.io/client-go/listers/apps/v1"
|
||||
|
||||
"k8s.io/api/apps/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
type statefulSetSearcher struct {
|
||||
statefulSetLister lister.StatefulSetLister
|
||||
}
|
||||
|
||||
func statefulSetStatus(item *v1.StatefulSet) string {
|
||||
@@ -44,7 +43,7 @@ func statefulSetStatus(item *v1.StatefulSet) string {
|
||||
return stopped
|
||||
}
|
||||
|
||||
// Exactly match
|
||||
// Exactly Match
|
||||
func (*statefulSetSearcher) match(match map[string]string, item *v1.StatefulSet) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
@@ -105,8 +104,8 @@ func (*statefulSetSearcher) compare(a, b *v1.StatefulSet, orderBy string) bool {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *statefulSetSearcher) search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
statefulSets, err := s.statefulSetLister.StatefulSets(namespace).List(labels.Everything())
|
||||
func (s *statefulSetSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
statefulSets, err := informers.SharedInformerFactory().Apps().V1().StatefulSets().Lister().StatefulSets(namespace).List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -114,11 +113,11 @@ func (s *statefulSetSearcher) search(namespace string, conditions *conditions, o
|
||||
|
||||
result := make([]*v1.StatefulSet, 0)
|
||||
|
||||
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 {
|
||||
if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
|
||||
result = statefulSets
|
||||
} else {
|
||||
for _, item := range statefulSets {
|
||||
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) {
|
||||
if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
|
||||
result = append(result, item)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,19 +18,19 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"k8s.io/api/storage/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
lister "k8s.io/client-go/listers/storage/v1"
|
||||
)
|
||||
|
||||
type storageClassesSearcher struct {
|
||||
storageClassesLister lister.StorageClassLister
|
||||
}
|
||||
|
||||
// exactly match
|
||||
// exactly Match
|
||||
func (*storageClassesSearcher) match(match map[string]string, item *v1.StorageClass) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
@@ -45,7 +45,7 @@ func (*storageClassesSearcher) match(match map[string]string, item *v1.StorageCl
|
||||
return true
|
||||
}
|
||||
|
||||
// fuzzy searchInNamespace
|
||||
// Fuzzy searchInNamespace
|
||||
func (*storageClassesSearcher) fuzzy(fuzzy map[string]string, item *v1.StorageClass) bool {
|
||||
for k, v := range fuzzy {
|
||||
switch k {
|
||||
@@ -86,8 +86,8 @@ func (*storageClassesSearcher) compare(a, b *v1.StorageClass, orderBy string) bo
|
||||
}
|
||||
}
|
||||
|
||||
func (s *storageClassesSearcher) search(conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
storageClasses, err := s.storageClassesLister.List(labels.Everything())
|
||||
func (s *storageClassesSearcher) search(conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
storageClasses, err := informers.SharedInformerFactory().Storage().V1().StorageClasses().Lister().List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -95,11 +95,11 @@ func (s *storageClassesSearcher) search(conditions *conditions, orderBy string,
|
||||
|
||||
result := make([]*v1.StorageClass, 0)
|
||||
|
||||
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 {
|
||||
if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
|
||||
result = storageClasses
|
||||
} else {
|
||||
for _, item := range storageClasses {
|
||||
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) {
|
||||
if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
|
||||
result = append(result, item)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,29 +24,11 @@ import (
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/api/apps/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
lister "k8s.io/client-go/listers/apps/v1"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
)
|
||||
|
||||
var (
|
||||
daemonSetLister lister.DaemonSetLister
|
||||
deploymentLister lister.DeploymentLister
|
||||
replicaSetLister lister.ReplicaSetLister
|
||||
statefulSetLister lister.StatefulSetLister
|
||||
controllerRevisionLister lister.ControllerRevisionLister
|
||||
)
|
||||
|
||||
func init() {
|
||||
daemonSetLister = informers.SharedInformerFactory().Apps().V1().DaemonSets().Lister()
|
||||
deploymentLister = informers.SharedInformerFactory().Apps().V1().Deployments().Lister()
|
||||
replicaSetLister = informers.SharedInformerFactory().Apps().V1().ReplicaSets().Lister()
|
||||
statefulSetLister = informers.SharedInformerFactory().Apps().V1().StatefulSets().Lister()
|
||||
controllerRevisionLister = informers.SharedInformerFactory().Apps().V1().ControllerRevisions().Lister()
|
||||
}
|
||||
|
||||
func GetDeployRevision(namespace, name, revision string) (*v1.ReplicaSet, error) {
|
||||
deploymentLister := informers.SharedInformerFactory().Apps().V1().Deployments().Lister()
|
||||
deploy, err := deploymentLister.Deployments(namespace).Get(name)
|
||||
if err != nil {
|
||||
glog.Errorf("get deployment %s failed, reason: %s", name, err)
|
||||
@@ -56,6 +38,7 @@ func GetDeployRevision(namespace, name, revision string) (*v1.ReplicaSet, error)
|
||||
labelMap := deploy.Spec.Template.Labels
|
||||
labelSelector := labels.Set(labelMap).AsSelector()
|
||||
|
||||
replicaSetLister := informers.SharedInformerFactory().Apps().V1().ReplicaSets().Lister()
|
||||
rsList, err := replicaSetLister.ReplicaSets(namespace).List(labelSelector)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -67,11 +50,11 @@ func GetDeployRevision(namespace, name, revision string) (*v1.ReplicaSet, error)
|
||||
}
|
||||
}
|
||||
|
||||
return nil, errors.New(errors.NotFound, fmt.Sprintf("revision not found %v#%v", name, revision))
|
||||
return nil, fmt.Errorf("revision not found %v#%v", name, revision)
|
||||
}
|
||||
|
||||
func GetDaemonSetRevision(namespace, name string, revisionInt int) (*v1.ControllerRevision, error) {
|
||||
|
||||
daemonSetLister := informers.SharedInformerFactory().Apps().V1().DaemonSets().Lister()
|
||||
ds, err := daemonSetLister.DaemonSets(namespace).Get(name)
|
||||
|
||||
if err != nil {
|
||||
@@ -84,7 +67,7 @@ func GetDaemonSetRevision(namespace, name string, revisionInt int) (*v1.Controll
|
||||
}
|
||||
|
||||
func GetStatefulSetRevision(namespace, name string, revisionInt int) (*v1.ControllerRevision, error) {
|
||||
|
||||
statefulSetLister := informers.SharedInformerFactory().Apps().V1().StatefulSets().Lister()
|
||||
st, err := statefulSetLister.StatefulSets(namespace).Get(name)
|
||||
|
||||
if err != nil {
|
||||
@@ -97,7 +80,7 @@ func GetStatefulSetRevision(namespace, name string, revisionInt int) (*v1.Contro
|
||||
func getControllerRevision(namespace, name string, labelMap map[string]string, revision int) (*v1.ControllerRevision, error) {
|
||||
|
||||
labelSelector := labels.Set(labelMap).AsSelector()
|
||||
|
||||
controllerRevisionLister := informers.SharedInformerFactory().Apps().V1().ControllerRevisions().Lister()
|
||||
revisions, err := controllerRevisionLister.ControllerRevisions(namespace).List(labelSelector)
|
||||
|
||||
if err != nil {
|
||||
@@ -110,5 +93,5 @@ func getControllerRevision(namespace, name string, labelMap map[string]string, r
|
||||
}
|
||||
}
|
||||
|
||||
return nil, errors.New(errors.NotFound, fmt.Sprintf("revision not found %v#%v", name, revision))
|
||||
return nil, fmt.Errorf("revision not found %v#%v", name, revision)
|
||||
}
|
||||
|
||||
@@ -23,15 +23,12 @@ import (
|
||||
"io/ioutil"
|
||||
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
v12 "k8s.io/client-go/listers/core/v1"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
|
||||
"github.com/golang/glog"
|
||||
coreV1 "k8s.io/api/core/v1"
|
||||
extensionsV1beta1 "k8s.io/api/extensions/v1beta1"
|
||||
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
|
||||
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
|
||||
"k8s.io/api/rbac/v1"
|
||||
@@ -43,18 +40,10 @@ import (
|
||||
"kubesphere.io/kubesphere/pkg/models/iam"
|
||||
)
|
||||
|
||||
var (
|
||||
serviceLister v12.ServiceLister
|
||||
)
|
||||
|
||||
func init() {
|
||||
serviceLister = informers.SharedInformerFactory().Core().V1().Services().Lister()
|
||||
}
|
||||
|
||||
func GetAllRouters() ([]*coreV1.Service, error) {
|
||||
func GetAllRouters() ([]*corev1.Service, error) {
|
||||
|
||||
selector := labels.SelectorFromSet(labels.Set{"app": "kubesphere", "component": "ks-router", "tier": "backend"})
|
||||
|
||||
serviceLister := informers.SharedInformerFactory().Core().V1().Services().Lister()
|
||||
services, err := serviceLister.Services(constants.IngressControllerNamespace).List(selector)
|
||||
|
||||
if err != nil {
|
||||
@@ -65,7 +54,7 @@ func GetAllRouters() ([]*coreV1.Service, error) {
|
||||
return services, nil
|
||||
}
|
||||
|
||||
func GetAllRoutersOfUser(username string) ([]*coreV1.Service, error) {
|
||||
func GetAllRoutersOfUser(username string) ([]*corev1.Service, error) {
|
||||
allNamespace, namespaces, err := iam.GetUserNamespaces(username, v1.PolicyRule{
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{""},
|
||||
@@ -82,7 +71,7 @@ func GetAllRoutersOfUser(username string) ([]*coreV1.Service, error) {
|
||||
return GetAllRouters()
|
||||
}
|
||||
|
||||
routers := make([]*coreV1.Service, 0)
|
||||
routers := make([]*corev1.Service, 0)
|
||||
|
||||
for _, namespace := range namespaces {
|
||||
router, err := GetRouter(namespace)
|
||||
@@ -99,11 +88,11 @@ func GetAllRoutersOfUser(username string) ([]*coreV1.Service, error) {
|
||||
}
|
||||
|
||||
// Get router from a namespace
|
||||
func GetRouter(namespace string) (*coreV1.Service, error) {
|
||||
func GetRouter(namespace string) (*corev1.Service, error) {
|
||||
serviceName := constants.IngressControllerPrefix + namespace
|
||||
|
||||
selector := labels.SelectorFromSet(labels.Set{"app": "kubesphere", "component": "ks-router", "tier": "backend", "project": namespace})
|
||||
|
||||
serviceLister := informers.SharedInformerFactory().Core().V1().Services().Lister()
|
||||
services, err := serviceLister.Services(constants.IngressControllerNamespace).List(selector)
|
||||
|
||||
if err != nil {
|
||||
@@ -116,7 +105,7 @@ func GetRouter(namespace string) (*coreV1.Service, error) {
|
||||
}
|
||||
}
|
||||
|
||||
return nil, errors.New(errors.NotFound, fmt.Sprintf("resources not found %s", serviceName))
|
||||
return nil, fmt.Errorf("resources not found %s", serviceName)
|
||||
}
|
||||
|
||||
// Load all resource yamls
|
||||
@@ -148,11 +137,11 @@ func LoadYamls() ([]string, error) {
|
||||
}
|
||||
|
||||
// Create a ingress controller in a namespace
|
||||
func CreateRouter(namespace string, routerType coreV1.ServiceType, annotations map[string]string) (*coreV1.Service, error) {
|
||||
func CreateRouter(namespace string, routerType corev1.ServiceType, annotations map[string]string) (*corev1.Service, error) {
|
||||
|
||||
k8sClient := client.K8sClient()
|
||||
|
||||
var router *coreV1.Service
|
||||
var router *corev1.Service
|
||||
|
||||
yamls, err := LoadYamls()
|
||||
|
||||
@@ -170,8 +159,8 @@ func CreateRouter(namespace string, routerType coreV1.ServiceType, annotations m
|
||||
}
|
||||
|
||||
switch obj.(type) {
|
||||
case *coreV1.Service:
|
||||
service := obj.(*coreV1.Service)
|
||||
case *corev1.Service:
|
||||
service := obj.(*corev1.Service)
|
||||
|
||||
service.SetAnnotations(annotations)
|
||||
service.Spec.Type = routerType
|
||||
@@ -190,8 +179,8 @@ func CreateRouter(namespace string, routerType coreV1.ServiceType, annotations m
|
||||
|
||||
router = service
|
||||
|
||||
case *extensionsV1beta1.Deployment:
|
||||
deployment := obj.(*extensionsV1beta1.Deployment)
|
||||
case *extensionsv1beta1.Deployment:
|
||||
deployment := obj.(*extensionsv1beta1.Deployment)
|
||||
deployment.Name = constants.IngressControllerPrefix + namespace
|
||||
|
||||
// Add project label
|
||||
@@ -204,7 +193,7 @@ func CreateRouter(namespace string, routerType coreV1.ServiceType, annotations m
|
||||
// Choose self as master
|
||||
deployment.Spec.Template.Spec.Containers[0].Args = append(deployment.Spec.Template.Spec.Containers[0].Args, "--election-id="+deployment.Name)
|
||||
|
||||
if routerType == coreV1.ServiceTypeLoadBalancer {
|
||||
if routerType == corev1.ServiceTypeLoadBalancer {
|
||||
deployment.Spec.Template.Spec.Containers[0].Args = append(deployment.Spec.Template.Spec.Containers[0].Args, "--publish-service="+constants.IngressControllerNamespace+"/"+constants.IngressControllerPrefix+namespace)
|
||||
} else {
|
||||
deployment.Spec.Template.Spec.Containers[0].Args = append(deployment.Spec.Template.Spec.Containers[0].Args, "--report-node-internal-ip-address")
|
||||
@@ -224,11 +213,11 @@ func CreateRouter(namespace string, routerType coreV1.ServiceType, annotations m
|
||||
|
||||
// DeleteRouter is used to delete ingress controller related resources in namespace
|
||||
// It will not delete ClusterRole resource cause it maybe used by other controllers
|
||||
func DeleteRouter(namespace string) (*coreV1.Service, error) {
|
||||
func DeleteRouter(namespace string) (*corev1.Service, error) {
|
||||
k8sClient := client.K8sClient()
|
||||
|
||||
var err error
|
||||
var router *coreV1.Service
|
||||
var router *corev1.Service
|
||||
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
@@ -236,9 +225,9 @@ func DeleteRouter(namespace string) (*coreV1.Service, error) {
|
||||
|
||||
// delete controller service
|
||||
serviceName := constants.IngressControllerPrefix + namespace
|
||||
deleteOptions := metaV1.DeleteOptions{}
|
||||
deleteOptions := meta_v1.DeleteOptions{}
|
||||
|
||||
listOptions := metaV1.ListOptions{
|
||||
listOptions := meta_v1.ListOptions{
|
||||
LabelSelector: "app=kubesphere,component=ks-router,tier=backend,project=" + namespace,
|
||||
FieldSelector: "metadata.name=" + serviceName}
|
||||
|
||||
@@ -259,7 +248,7 @@ func DeleteRouter(namespace string) (*coreV1.Service, error) {
|
||||
// delete controller deployment
|
||||
deploymentName := constants.IngressControllerPrefix + namespace
|
||||
|
||||
listOptions = metaV1.ListOptions{
|
||||
listOptions = meta_v1.ListOptions{
|
||||
LabelSelector: "app=kubesphere,component=ks-router,tier=backend,project=" + namespace,
|
||||
}
|
||||
deployments, err := k8sClient.ExtensionsV1beta1().Deployments(constants.IngressControllerNamespace).List(listOptions)
|
||||
@@ -279,10 +268,10 @@ func DeleteRouter(namespace string) (*coreV1.Service, error) {
|
||||
}
|
||||
|
||||
// Update Ingress Controller Service, change type from NodePort to Loadbalancer or vice versa.
|
||||
func UpdateRouter(namespace string, routerType coreV1.ServiceType, annotations map[string]string) (*coreV1.Service, error) {
|
||||
func UpdateRouter(namespace string, routerType corev1.ServiceType, annotations map[string]string) (*corev1.Service, error) {
|
||||
k8sClient := client.K8sClient()
|
||||
|
||||
var router *coreV1.Service
|
||||
var router *corev1.Service
|
||||
|
||||
router, err := GetRouter(namespace)
|
||||
|
||||
@@ -293,7 +282,7 @@ func UpdateRouter(namespace string, routerType coreV1.ServiceType, annotations m
|
||||
|
||||
if router == nil {
|
||||
glog.Error("Trying to update a non-existed router")
|
||||
return nil, errors.New(errors.Internal, "router not created yet")
|
||||
return nil, fmt.Errorf("router not created yet")
|
||||
}
|
||||
|
||||
// from LoadBalancer to NodePort, or vice-versa
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
package status
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/models/resources"
|
||||
)
|
||||
@@ -31,7 +32,7 @@ type workLoadStatus struct {
|
||||
|
||||
func GetNamespacesResourceStatus(namespace string) (*workLoadStatus, error) {
|
||||
res := workLoadStatus{Count: make(map[string]int), Namespace: namespace, Items: make(map[string]interface{})}
|
||||
var notReadyList *resources.ResourceList
|
||||
var notReadyList *models.PageableResponse
|
||||
var err error
|
||||
for _, resource := range []string{resources.Deployments, resources.StatefulSets, resources.DaemonSets, resources.PersistentVolumeClaims} {
|
||||
notReadyStatus := "updating"
|
||||
@@ -39,7 +40,7 @@ func GetNamespacesResourceStatus(namespace string) (*workLoadStatus, error) {
|
||||
notReadyStatus = "pending"
|
||||
}
|
||||
|
||||
notReadyList, err = resources.ListNamespaceResource(namespace, resource, fmt.Sprintf("status=%s", notReadyStatus), "", false, -1, 0)
|
||||
notReadyList, err = resources.ListNamespaceResource(namespace, resource, ¶ms.Conditions{Match: map[string]string{"status": notReadyStatus}}, "", false, -1, 0)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -24,9 +24,6 @@ import (
|
||||
storageV1 "k8s.io/api/storage/v1"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
lister "k8s.io/client-go/listers/core/v1"
|
||||
lister2 "k8s.io/client-go/listers/storage/v1"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
)
|
||||
|
||||
@@ -36,18 +33,12 @@ type ScMetrics struct {
|
||||
PvcNumber string `json:"pvcNumber"`
|
||||
}
|
||||
|
||||
var (
|
||||
persistentVolumeClaimLister lister.PersistentVolumeClaimLister
|
||||
persistentVolumeLister lister.PersistentVolumeLister
|
||||
sotrageClassesLister lister2.StorageClassLister
|
||||
)
|
||||
|
||||
func init() {
|
||||
persistentVolumeClaimLister = informers.SharedInformerFactory().Core().V1().PersistentVolumeClaims().Lister()
|
||||
persistentVolumeLister = informers.SharedInformerFactory().Core().V1().PersistentVolumes().Lister()
|
||||
|
||||
}
|
||||
|
||||
func GetPvcListBySc(scName string) ([]*v1.PersistentVolumeClaim, error) {
|
||||
persistentVolumeClaimLister := informers.SharedInformerFactory().Core().V1().PersistentVolumeClaims().Lister()
|
||||
all, err := persistentVolumeClaimLister.List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
@@ -70,6 +61,7 @@ func GetPvcListBySc(scName string) ([]*v1.PersistentVolumeClaim, error) {
|
||||
|
||||
// Get info of metrics
|
||||
func GetScMetrics(scName string) (*ScMetrics, error) {
|
||||
persistentVolumeLister := informers.SharedInformerFactory().Core().V1().PersistentVolumes().Lister()
|
||||
pvList, err := persistentVolumeLister.List(labels.Everything())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -102,7 +94,7 @@ func GetScMetrics(scName string) (*ScMetrics, error) {
|
||||
func GetScList() ([]*storageV1.StorageClass, error) {
|
||||
|
||||
// Get StorageClass list
|
||||
scList, err := sotrageClassesLister.List(labels.Everything())
|
||||
scList, err := informers.SharedInformerFactory().Storage().V1().StorageClasses().Lister().List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -20,19 +20,12 @@ package storage
|
||||
import (
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
v12 "k8s.io/client-go/listers/core/v1"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
)
|
||||
|
||||
var podLister v12.PodLister
|
||||
|
||||
func init() {
|
||||
podLister = informers.SharedInformerFactory().Core().V1().Pods().Lister()
|
||||
}
|
||||
|
||||
// List pods of a specific persistent volume claims
|
||||
func GetPodListByPvc(pvc string, ns string) (res []*v1.Pod, err error) {
|
||||
podLister := informers.SharedInformerFactory().Core().V1().Pods().Lister()
|
||||
podList, err := podLister.Pods(ns).List(labels.Everything())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -17,11 +17,121 @@
|
||||
*/
|
||||
package models
|
||||
|
||||
type MessageResponse struct {
|
||||
Message string `json:"message"`
|
||||
}
|
||||
import (
|
||||
v12 "k8s.io/api/core/v1"
|
||||
"time"
|
||||
|
||||
"k8s.io/api/rbac/v1"
|
||||
)
|
||||
|
||||
type PageableResponse struct {
|
||||
Items []interface{} `json:"items"`
|
||||
TotalCount int `json:"total_count"`
|
||||
}
|
||||
|
||||
type Workspace struct {
|
||||
Group `json:",inline"`
|
||||
Admin string `json:"admin,omitempty"`
|
||||
Namespaces []string `json:"namespaces"`
|
||||
DevopsProjects []string `json:"devops_projects"`
|
||||
}
|
||||
|
||||
type UserInvite struct {
|
||||
Username string `json:"username"`
|
||||
Role string `json:"role"`
|
||||
}
|
||||
|
||||
func (g Group) GetCreateTime() (time.Time, error) {
|
||||
return time.Parse("2006-01-02T15:04:05Z", g.CreateTime)
|
||||
}
|
||||
|
||||
type WorkspaceDPBinding struct {
|
||||
Workspace string `gorm:"primary_key"`
|
||||
DevOpsProject string `gorm:"primary_key"`
|
||||
}
|
||||
|
||||
type DevopsProject struct {
|
||||
ProjectId *string `json:"project_id,omitempty"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Creator string `json:"creator"`
|
||||
CreateTime *time.Time `json:"create_time,omitempty"`
|
||||
Status *string `json:"status"`
|
||||
Visibility *string `json:"visibility,omitempty"`
|
||||
}
|
||||
|
||||
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"`
|
||||
Actions []string `json:"actions"`
|
||||
}
|
||||
|
||||
type User struct {
|
||||
Username string `json:"username"`
|
||||
//UID string `json:"uid"`
|
||||
Groups []string `json:"groups,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
CurrentPassword string `json:"current_password,omitempty"`
|
||||
//Extra map[string]interface{} `json:"extra"`
|
||||
AvatarUrl string `json:"avatar_url"`
|
||||
Description string `json:"description"`
|
||||
Email string `json:"email"`
|
||||
LastLoginTime string `json:"last_login_time"`
|
||||
Status int `json:"status"`
|
||||
ClusterRole string `json:"cluster_role"`
|
||||
ClusterRules []SimpleRule `json:"cluster_rules"`
|
||||
Roles map[string]string `json:"roles,omitempty"`
|
||||
Rules map[string][]SimpleRule `json:"rules,omitempty"`
|
||||
Role string `json:"role,omitempty"`
|
||||
RoleBinding string `json:"role_binding,omitempty"`
|
||||
Lang string `json:"lang,omitempty"`
|
||||
WorkspaceRoles map[string]string `json:"workspace_roles,omitempty"`
|
||||
WorkspaceRole string `json:"workspace_role,omitempty"`
|
||||
WorkspaceRules map[string][]SimpleRule `json:"workspace_rules,omitempty"`
|
||||
}
|
||||
|
||||
type Group struct {
|
||||
Path string `json:"path"`
|
||||
Name string `json:"name"`
|
||||
Gid string `json:"gid"`
|
||||
Members []string `json:"members"`
|
||||
Logo string `json:"logo"`
|
||||
Creator string `json:"creator"`
|
||||
CreateTime string `json:"create_time"`
|
||||
ChildGroups []string `json:"child_groups"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
type Component struct {
|
||||
Name string `json:"name"`
|
||||
Namespace string `json:"namespace"`
|
||||
SelfLink string `json:"selfLink"`
|
||||
Label interface{} `json:"label"`
|
||||
StartedAt time.Time `json:"startedAt"`
|
||||
TotalBackends int `json:"totalBackends"`
|
||||
HealthyBackends int `json:"healthyBackends"`
|
||||
}
|
||||
|
||||
type PodInfo struct {
|
||||
Namespace string `json:"namespace"`
|
||||
Pod string `json:"pod"`
|
||||
Container string `json:"container"`
|
||||
}
|
||||
|
||||
type Token struct {
|
||||
Token string `json:"access_token"`
|
||||
}
|
||||
|
||||
type ResourceQuota struct {
|
||||
Namespace string `json:"namespace"`
|
||||
Data v12.ResourceQuotaStatus `json:"data"`
|
||||
}
|
||||
|
||||
@@ -1,63 +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 "time"
|
||||
|
||||
type Workspace struct {
|
||||
Group `json:",inline"`
|
||||
Admin string `json:"admin,omitempty"`
|
||||
Namespaces []string `json:"namespaces"`
|
||||
DevopsProjects []string `json:"devops_projects"`
|
||||
}
|
||||
|
||||
type UserInvite struct {
|
||||
Username string `json:"username"`
|
||||
Role string `json:"role"`
|
||||
}
|
||||
|
||||
type Group struct {
|
||||
Path string `json:"path"`
|
||||
Name string `json:"name"`
|
||||
Gid string `json:"gid"`
|
||||
Members []string `json:"members"`
|
||||
Logo string `json:"logo"`
|
||||
Creator string `json:"creator"`
|
||||
CreateTime string `json:"create_time"`
|
||||
ChildGroups []string `json:"child_groups,omitempty"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
func (g Group) GetCreateTime() (time.Time, error) {
|
||||
return time.Parse("2006-01-02T15:04:05Z", g.CreateTime)
|
||||
}
|
||||
|
||||
type WorkspaceDPBinding struct {
|
||||
Workspace string `gorm:"primary_key"`
|
||||
DevOpsProject string `gorm:"primary_key"`
|
||||
}
|
||||
|
||||
type DevopsProject struct {
|
||||
ProjectId *string `json:"project_id,omitempty"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Creator string `json:"creator"`
|
||||
CreateTime *time.Time `json:"create_time,omitempty"`
|
||||
Status *string `json:"status"`
|
||||
Visibility *string `json:"visibility,omitempty"`
|
||||
}
|
||||
@@ -24,10 +24,9 @@ import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
lister "k8s.io/client-go/listers/core/v1"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam"
|
||||
|
||||
"log"
|
||||
@@ -50,26 +49,14 @@ import (
|
||||
|
||||
"sort"
|
||||
|
||||
lister2 "k8s.io/client-go/listers/rbac/v1"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/client"
|
||||
ksErr "kubesphere.io/kubesphere/pkg/errors"
|
||||
kserr "kubesphere.io/kubesphere/pkg/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
namespaceLister lister.NamespaceLister
|
||||
clusterRoleLister lister2.ClusterRoleLister
|
||||
)
|
||||
|
||||
func init() {
|
||||
namespaceLister = informers.SharedInformerFactory().Core().V1().Namespaces().Lister()
|
||||
clusterRoleLister = informers.SharedInformerFactory().Rbac().V1().ClusterRoles().Lister()
|
||||
}
|
||||
|
||||
func UnBindDevopsProject(workspace string, devops string) error {
|
||||
db := client.NewSharedDBClient()
|
||||
db := client.DBClient()
|
||||
defer db.Close()
|
||||
return db.Delete(&WorkspaceDPBinding{Workspace: workspace, DevOpsProject: devops}).Error
|
||||
return db.Delete(&models.WorkspaceDPBinding{Workspace: workspace, DevOpsProject: devops}).Error
|
||||
}
|
||||
|
||||
func DeleteDevopsProject(username string, devops string) error {
|
||||
@@ -87,12 +74,12 @@ func DeleteDevopsProject(username string, devops string) error {
|
||||
return err
|
||||
}
|
||||
if result.StatusCode > 200 {
|
||||
return ksErr.Wrap(data)
|
||||
return kserr.Parse(data)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func CreateDevopsProject(username string, workspace string, devops DevopsProject) (*DevopsProject, error) {
|
||||
func CreateDevopsProject(username string, workspace string, devops models.DevopsProject) (*models.DevopsProject, error) {
|
||||
|
||||
data, err := json.Marshal(devops)
|
||||
|
||||
@@ -117,10 +104,10 @@ func CreateDevopsProject(username string, workspace string, devops DevopsProject
|
||||
}
|
||||
|
||||
if result.StatusCode > 200 {
|
||||
return nil, ksErr.Wrap(data)
|
||||
return nil, kserr.Parse(data)
|
||||
}
|
||||
|
||||
var project DevopsProject
|
||||
var project models.DevopsProject
|
||||
|
||||
err = json.Unmarshal(data, &project)
|
||||
|
||||
@@ -140,7 +127,7 @@ func CreateDevopsProject(username string, workspace string, devops DevopsProject
|
||||
return &project, nil
|
||||
}
|
||||
|
||||
func createDefaultDevopsRoleBinding(workspace string, project DevopsProject) error {
|
||||
func createDefaultDevopsRoleBinding(workspace string, project models.DevopsProject) error {
|
||||
admins, err := iam.GetWorkspaceUsers(workspace, constants.WorkspaceAdmin)
|
||||
|
||||
if err != nil {
|
||||
@@ -296,7 +283,7 @@ func ListNamespaceByUser(workspaceName string, username string, keyword string,
|
||||
}
|
||||
|
||||
func Namespaces(workspaceName string) ([]*core.Namespace, error) {
|
||||
|
||||
namespaceLister := informers.SharedInformerFactory().Core().V1().Namespaces().Lister()
|
||||
namespaces, err := namespaceLister.List(labels.SelectorFromSet(labels.Set{"kubesphere.io/workspace": workspaceName}))
|
||||
|
||||
if err != nil {
|
||||
@@ -317,11 +304,9 @@ func Namespaces(workspaceName string) ([]*core.Namespace, error) {
|
||||
}
|
||||
|
||||
func BindingDevopsProject(workspace string, devops string) error {
|
||||
//db := client.NewSharedDBClient()
|
||||
//defer db.Close()
|
||||
//return db.Create(&WorkspaceDPBinding{Workspace: workspace, DevOpsProject: devops}).Error
|
||||
// TODO FIX
|
||||
return nil
|
||||
db := client.DBClient()
|
||||
defer db.Close()
|
||||
return db.Create(&models.WorkspaceDPBinding{Workspace: workspace, DevOpsProject: devops}).Error
|
||||
}
|
||||
|
||||
func DeleteNamespace(workspace string, namespaceName string) error {
|
||||
@@ -338,7 +323,7 @@ func DeleteNamespace(workspace string, namespaceName string) error {
|
||||
|
||||
}
|
||||
|
||||
func Delete(workspace *Workspace) error {
|
||||
func Delete(workspace *models.Workspace) error {
|
||||
|
||||
err := release(workspace)
|
||||
|
||||
@@ -365,13 +350,13 @@ func Delete(workspace *Workspace) error {
|
||||
}
|
||||
|
||||
if result.StatusCode > 200 {
|
||||
return ksErr.Wrap(data)
|
||||
return kserr.Parse(data)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func release(workspace *Workspace) error {
|
||||
func release(workspace *models.Workspace) error {
|
||||
for _, namespace := range workspace.Namespaces {
|
||||
err := DeleteNamespace(workspace.Name, namespace)
|
||||
if err != nil && !apierrors.IsNotFound(err) {
|
||||
@@ -413,7 +398,7 @@ func workspaceRoleRelease(workspace string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func Create(workspace *Workspace) (*Workspace, error) {
|
||||
func Create(workspace *models.Workspace) (*models.Workspace, error) {
|
||||
|
||||
data, err := json.Marshal(workspace)
|
||||
|
||||
@@ -434,10 +419,10 @@ func Create(workspace *Workspace) (*Workspace, error) {
|
||||
}
|
||||
|
||||
if result.StatusCode > 200 {
|
||||
return nil, ksErr.Wrap(data)
|
||||
return nil, kserr.Parse(data)
|
||||
}
|
||||
|
||||
var created Workspace
|
||||
var created models.Workspace
|
||||
|
||||
err = json.Unmarshal(data, &created)
|
||||
|
||||
@@ -458,7 +443,7 @@ func Create(workspace *Workspace) (*Workspace, error) {
|
||||
return &created, nil
|
||||
}
|
||||
|
||||
func Edit(workspace *Workspace) (*Workspace, error) {
|
||||
func Edit(workspace *models.Workspace) (*models.Workspace, error) {
|
||||
|
||||
data, err := json.Marshal(workspace)
|
||||
|
||||
@@ -487,10 +472,10 @@ func Edit(workspace *Workspace) (*Workspace, error) {
|
||||
}
|
||||
|
||||
if result.StatusCode > 200 {
|
||||
return nil, ksErr.Wrap(data)
|
||||
return nil, kserr.Parse(data)
|
||||
}
|
||||
|
||||
var edited Workspace
|
||||
var edited models.Workspace
|
||||
|
||||
err = json.Unmarshal(data, &edited)
|
||||
|
||||
@@ -501,7 +486,7 @@ func Edit(workspace *Workspace) (*Workspace, error) {
|
||||
return &edited, nil
|
||||
}
|
||||
|
||||
func Detail(name string) (*Workspace, error) {
|
||||
func Detail(name string) (*models.Workspace, error) {
|
||||
|
||||
result, err := http.Get(fmt.Sprintf("http://%s/apis/account.kubesphere.io/v1alpha1/groups/%s", constants.AccountAPIServer, name))
|
||||
|
||||
@@ -517,10 +502,10 @@ func Detail(name string) (*Workspace, error) {
|
||||
}
|
||||
|
||||
if result.StatusCode > 200 {
|
||||
return nil, ksErr.Wrap(data)
|
||||
return nil, kserr.Parse(data)
|
||||
}
|
||||
|
||||
var group Group
|
||||
var group models.Group
|
||||
|
||||
err = json.Unmarshal(data, &group)
|
||||
|
||||
@@ -528,7 +513,7 @@ func Detail(name string) (*Workspace, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
db := client.NewSharedDBClient()
|
||||
db := client.DBClient()
|
||||
defer db.Close()
|
||||
|
||||
workspace, err := convertGroupToWorkspace(db, group)
|
||||
@@ -541,7 +526,7 @@ func Detail(name string) (*Workspace, error) {
|
||||
}
|
||||
|
||||
// List all workspaces for the current user
|
||||
func ListWorkspaceByUser(username string, keyword string) ([]*Workspace, error) {
|
||||
func ListWorkspaceByUser(username string, keyword string) ([]*models.Workspace, error) {
|
||||
clusterRoles, err := iam.GetClusterRoles(username)
|
||||
|
||||
if err != nil {
|
||||
@@ -556,7 +541,7 @@ func ListWorkspaceByUser(username string, keyword string) ([]*Workspace, error)
|
||||
|
||||
workspacesManager := v1.PolicyRule{APIGroups: []string{"kubesphere.io"}, Verbs: []string{"list", "get"}, Resources: []string{"workspaces"}}
|
||||
|
||||
var workspaces []*Workspace
|
||||
var workspaces []*models.Workspace
|
||||
if iam.RulesMatchesRequired(rules, workspacesManager) {
|
||||
workspaces, err = fetch(nil)
|
||||
} else {
|
||||
@@ -582,13 +567,13 @@ func ListWorkspaceByUser(username string, keyword string) ([]*Workspace, error)
|
||||
return workspaces, err
|
||||
}
|
||||
|
||||
func fetch(names []string) ([]*Workspace, error) {
|
||||
func fetch(names []string) ([]*models.Workspace, error) {
|
||||
|
||||
url := fmt.Sprintf("http://%s/apis/account.kubesphere.io/v1alpha1/groups", constants.AccountAPIServer)
|
||||
|
||||
if names != nil {
|
||||
if len(names) == 0 {
|
||||
return make([]*Workspace, 0), nil
|
||||
return make([]*models.Workspace, 0), nil
|
||||
} else {
|
||||
url = url + "?path=" + strings.Join(names, ",")
|
||||
}
|
||||
@@ -608,10 +593,10 @@ func fetch(names []string) ([]*Workspace, error) {
|
||||
}
|
||||
|
||||
if result.StatusCode > 200 {
|
||||
return nil, ksErr.Wrap(data)
|
||||
return nil, kserr.Parse(data)
|
||||
}
|
||||
|
||||
var groups []Group
|
||||
var groups []models.Group
|
||||
|
||||
err = json.Unmarshal(data, &groups)
|
||||
|
||||
@@ -619,11 +604,11 @@ func fetch(names []string) ([]*Workspace, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
db := client.NewSharedDBClient()
|
||||
db := client.DBClient()
|
||||
|
||||
defer db.Close()
|
||||
|
||||
workspaces := make([]*Workspace, 0)
|
||||
workspaces := make([]*models.Workspace, 0)
|
||||
for _, group := range groups {
|
||||
workspace, err := convertGroupToWorkspace(db, group)
|
||||
if err != nil {
|
||||
@@ -635,21 +620,21 @@ func fetch(names []string) ([]*Workspace, error) {
|
||||
return workspaces, nil
|
||||
}
|
||||
|
||||
func ListDevopsProjectsByUser(username string, workspace string, keyword string, orderBy string, reverse bool, limit int, offset int) (int, []DevopsProject, error) {
|
||||
func ListDevopsProjectsByUser(username string, workspace string, keyword string, orderBy string, reverse bool, limit int, offset int) (int, []models.DevopsProject, error) {
|
||||
|
||||
db := client.NewSharedDBClient()
|
||||
db := client.DBClient()
|
||||
defer db.Close()
|
||||
|
||||
var workspaceDOPBindings []WorkspaceDPBinding
|
||||
var workspaceDOPBindings []models.WorkspaceDPBinding
|
||||
|
||||
if err := db.Where("workspace = ?", workspace).Find(&workspaceDOPBindings).Error; err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
devOpsProjects := make([]DevopsProject, 0)
|
||||
devOpsProjects := make([]models.DevopsProject, 0)
|
||||
|
||||
request, _ := http.NewRequest(http.MethodGet, fmt.Sprintf("http://%s/api/v1alpha/projects", constants.DevopsAPIServer), nil)
|
||||
request.Header.Add("X-Token-Username", username)
|
||||
request.Header.Add(constants.UserNameHeader, username)
|
||||
|
||||
result, err := http.DefaultClient.Do(request)
|
||||
if err != nil {
|
||||
@@ -662,15 +647,8 @@ func ListDevopsProjectsByUser(username string, workspace string, keyword string,
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
//if result.StatusCode == 403 || result.StatusCode == 404 {
|
||||
// if err := db.Delete(&workspaceDOPBinding).Error; err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// continue
|
||||
//}
|
||||
|
||||
if result.StatusCode > 200 {
|
||||
return 0, nil, ksErr.Wrap(data)
|
||||
return 0, nil, kserr.Parse(data)
|
||||
}
|
||||
|
||||
err = json.Unmarshal(data, &devOpsProjects)
|
||||
@@ -720,14 +698,14 @@ func ListDevopsProjectsByUser(username string, workspace string, keyword string,
|
||||
}
|
||||
|
||||
if len(devOpsProjects) < offset {
|
||||
return len(devOpsProjects), make([]DevopsProject, 0), nil
|
||||
return len(devOpsProjects), make([]models.DevopsProject, 0), nil
|
||||
} else if len(devOpsProjects) < limit+offset {
|
||||
return len(devOpsProjects), devOpsProjects[offset:], nil
|
||||
} else {
|
||||
return len(devOpsProjects), devOpsProjects[offset : limit+offset], nil
|
||||
}
|
||||
}
|
||||
func convertGroupToWorkspace(db *gorm.DB, group Group) (*Workspace, error) {
|
||||
func convertGroupToWorkspace(db *gorm.DB, group models.Group) (*models.Workspace, error) {
|
||||
namespaces, err := Namespaces(group.Name)
|
||||
|
||||
if err != nil {
|
||||
@@ -740,7 +718,7 @@ func convertGroupToWorkspace(db *gorm.DB, group Group) (*Workspace, error) {
|
||||
namespacesNames = append(namespacesNames, namespace.Name)
|
||||
}
|
||||
|
||||
var workspaceDOPBindings []WorkspaceDPBinding
|
||||
var workspaceDOPBindings []models.WorkspaceDPBinding
|
||||
|
||||
if err := db.Where("workspace = ?", group.Name).Find(&workspaceDOPBindings).Error; err != nil {
|
||||
return nil, err
|
||||
@@ -752,7 +730,7 @@ func convertGroupToWorkspace(db *gorm.DB, group Group) (*Workspace, error) {
|
||||
devOpsProjects = append(devOpsProjects, workspaceDOPBinding.DevOpsProject)
|
||||
}
|
||||
|
||||
workspace := Workspace{Group: group}
|
||||
workspace := models.Workspace{Group: group}
|
||||
workspace.Namespaces = namespacesNames
|
||||
workspace.DevopsProjects = devOpsProjects
|
||||
return &workspace, nil
|
||||
@@ -769,7 +747,7 @@ func CreateNamespace(namespace *core.Namespace) (*core.Namespace, error) {
|
||||
return ns, nil
|
||||
}
|
||||
|
||||
func Invite(workspaceName string, users []UserInvite) error {
|
||||
func Invite(workspaceName string, users []models.UserInvite) error {
|
||||
for _, user := range users {
|
||||
if !slice.ContainsString(constants.WorkSpaceRoles, user.Role, nil) {
|
||||
return fmt.Errorf("role %s not exist", user.Role)
|
||||
@@ -848,9 +826,9 @@ func RemoveMembers(workspaceName string, users []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func Roles(workspace *Workspace) ([]*v1.ClusterRole, error) {
|
||||
func Roles(workspace *models.Workspace) ([]*v1.ClusterRole, error) {
|
||||
roles := make([]*v1.ClusterRole, 0)
|
||||
|
||||
clusterRoleLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoles().Lister()
|
||||
for _, name := range constants.WorkSpaceRoles {
|
||||
|
||||
clusterRole, err := clusterRoleLister.Get(fmt.Sprintf("system:%s:%s", workspace.Name, name))
|
||||
@@ -871,7 +849,7 @@ func Roles(workspace *Workspace) ([]*v1.ClusterRole, error) {
|
||||
return roles, nil
|
||||
}
|
||||
|
||||
func GetWorkspaceMembers(workspace string, keyword string) ([]iam.User, error) {
|
||||
func GetWorkspaceMembers(workspace string, keyword string) ([]models.User, error) {
|
||||
|
||||
url := fmt.Sprintf("http://%s/apis/account.kubesphere.io/v1alpha1/workspaces/%s/members", constants.AccountAPIServer, workspace)
|
||||
|
||||
@@ -893,10 +871,10 @@ func GetWorkspaceMembers(workspace string, keyword string) ([]iam.User, error) {
|
||||
}
|
||||
|
||||
if result.StatusCode > 200 {
|
||||
return nil, ksErr.Wrap(data)
|
||||
return nil, kserr.Parse(data)
|
||||
}
|
||||
|
||||
var users []iam.User
|
||||
var users []models.User
|
||||
|
||||
err = json.Unmarshal(data, &users)
|
||||
|
||||
@@ -908,7 +886,7 @@ func GetWorkspaceMembers(workspace string, keyword string) ([]iam.User, error) {
|
||||
|
||||
}
|
||||
|
||||
func WorkspaceRoleInit(workspace *Workspace) error {
|
||||
func WorkspaceRoleInit(workspace *models.Workspace) error {
|
||||
k8sClient := client.K8sClient()
|
||||
|
||||
admin := new(v1.ClusterRole)
|
||||
@@ -1169,7 +1147,7 @@ func unbindNamespacesRole(namespaces []string, users []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func UnbindWorkspace(workspace *Workspace, users []string) error {
|
||||
func UnbindWorkspace(workspace *models.Workspace, users []string) error {
|
||||
|
||||
err := unbindNamespacesRole(workspace.Namespaces, users)
|
||||
|
||||
@@ -1186,7 +1164,7 @@ func UnbindWorkspace(workspace *Workspace, users []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func CreateWorkspaceRoleBinding(workspace *Workspace, username string, role string) error {
|
||||
func CreateWorkspaceRoleBinding(workspace *models.Workspace, username string, role string) error {
|
||||
|
||||
k8sClient := client.K8sClient()
|
||||
|
||||
@@ -1242,10 +1220,10 @@ func CreateWorkspaceRoleBinding(workspace *Workspace, username string, role stri
|
||||
|
||||
func GetDevOpsProjects(workspaceName string) ([]string, error) {
|
||||
|
||||
db := client.NewSharedDBClient()
|
||||
db := client.DBClient()
|
||||
defer db.Close()
|
||||
|
||||
var workspaceDOPBindings []WorkspaceDPBinding
|
||||
var workspaceDOPBindings []models.WorkspaceDPBinding
|
||||
|
||||
if err := db.Where("workspace = ?", workspaceName).Find(&workspaceDOPBindings).Error; err != nil {
|
||||
return nil, err
|
||||
@@ -1304,7 +1282,7 @@ func Count() (int, error) {
|
||||
}
|
||||
|
||||
if result.StatusCode > 200 {
|
||||
return 0, ksErr.Wrap(data)
|
||||
return 0, kserr.Parse(data)
|
||||
}
|
||||
var count map[string]json.Number
|
||||
|
||||
@@ -1319,13 +1297,14 @@ func Count() (int, error) {
|
||||
v, err := value.Int64()
|
||||
|
||||
if err != nil {
|
||||
return 0, ksErr.New(ksErr.Internal, err.Error())
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return int(v), nil
|
||||
}
|
||||
|
||||
func GetAllProjectNums() (int, error) {
|
||||
namespaceLister := informers.SharedInformerFactory().Core().V1().Namespaces().Lister()
|
||||
list, err := namespaceLister.List(labels.Everything())
|
||||
if err != nil {
|
||||
return 0, err
|
||||
@@ -1334,11 +1313,11 @@ func GetAllProjectNums() (int, error) {
|
||||
}
|
||||
|
||||
func GetAllDevOpsProjectsNums() (int, error) {
|
||||
db := client.NewSharedDBClient()
|
||||
db := client.DBClient()
|
||||
defer db.Close()
|
||||
|
||||
var count int
|
||||
if err := db.Model(&WorkspaceDPBinding{}).Count(&count).Error; err != nil {
|
||||
if err := db.Model(&models.WorkspaceDPBinding{}).Count(&count).Error; err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return count, nil
|
||||
@@ -1357,7 +1336,7 @@ func GetAllAccountNums() (int, error) {
|
||||
return 0, err
|
||||
}
|
||||
if result.StatusCode > 200 {
|
||||
return 0, ksErr.Wrap(data)
|
||||
return 0, kserr.Parse(data)
|
||||
}
|
||||
var count map[string]json.Number
|
||||
|
||||
|
||||
@@ -1,397 +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 monitoring
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"github.com/emicklei/go-restful-openapi"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/client"
|
||||
"kubesphere.io/kubesphere/pkg/models/metrics"
|
||||
)
|
||||
|
||||
func Route(ws *restful.WebService) {
|
||||
u := Monitor{}
|
||||
|
||||
ws.Route(ws.GET("/clusters").To(u.monitorCluster).
|
||||
Doc("monitor cluster level metrics").
|
||||
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("cluster_cpu_utilisation")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{"monitoring", "cluster"}))
|
||||
|
||||
ws.Route(ws.GET("/nodes").To(u.monitorNode).
|
||||
Doc("monitor nodes level metrics").
|
||||
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("node_cpu_utilisation")).
|
||||
Param(ws.QueryParameter("nodes_filter", "node re2 expression filter").DataType("string").Required(false).DefaultValue("")).
|
||||
Param(ws.QueryParameter("sort_metric", "sort metric").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("sort_type", "ascending descending order").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("page", "page number").DataType("string").Required(false).DefaultValue("1")).
|
||||
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("4")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{"monitoring", "node"}))
|
||||
|
||||
ws.Route(ws.GET("/nodes/{node_id}").To(u.monitorNode).
|
||||
Doc("monitor specific node level metrics").
|
||||
Param(ws.PathParameter("node_id", "specific node").DataType("string").Required(true).DefaultValue("")).
|
||||
Param(ws.QueryParameter("metrics_name", "metrics name cpu memory...").DataType("string").Required(true).DefaultValue("node_cpu_utilisation")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{"monitoring", "node"}))
|
||||
|
||||
ws.Route(ws.GET("/namespaces").To(u.monitorNamespace).
|
||||
Doc("monitor namespaces level metrics").
|
||||
Param(ws.QueryParameter("namespaces_filter", "namespaces re2 expression filter").DataType("string").Required(false).DefaultValue("")).
|
||||
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("namespace_memory_utilisation")).
|
||||
Param(ws.QueryParameter("sort_metric", "sort metric").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("sort_type", "ascending descending order").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("page", "page number").DataType("string").Required(false).DefaultValue("1")).
|
||||
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("4")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{"monitoring", "namespace"}))
|
||||
|
||||
ws.Route(ws.GET("/namespaces/{ns_name}").To(u.monitorNamespace).
|
||||
Doc("monitor specific namespace level metrics").
|
||||
Param(ws.PathParameter("ns_name", "specific namespace").DataType("string").Required(true).DefaultValue("monitoring")).
|
||||
Param(ws.QueryParameter("metrics_name", "metrics name cpu memory...").DataType("string").Required(true).DefaultValue("namespace_memory_utilisation")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{"monitoring", "namespace"}))
|
||||
|
||||
ws.Route(ws.GET("/namespaces/{ns_name}/pods").To(u.monitorPod).
|
||||
Doc("monitor pods level metrics").
|
||||
Param(ws.PathParameter("ns_name", "specific namespace").DataType("string").Required(true).DefaultValue("monitoring")).
|
||||
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("pod_memory_utilisation_wo_cache")).
|
||||
Param(ws.QueryParameter("pods_filter", "pod re2 expression filter").DataType("string").Required(false).DefaultValue("")).
|
||||
Param(ws.QueryParameter("sort_metric", "sort metric").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("sort_type", "ascending descending order").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("page", "page number").DataType("string").Required(false).DefaultValue("1")).
|
||||
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("4")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{"monitoring", "pod"}))
|
||||
|
||||
ws.Route(ws.GET("/namespaces/{ns_name}/pods/{pod_name}").To(u.monitorPod).
|
||||
Doc("monitor specific pod level metrics").
|
||||
Param(ws.PathParameter("ns_name", "specific namespace").DataType("string").Required(true).DefaultValue("monitoring")).
|
||||
Param(ws.PathParameter("pod_name", "specific pod").DataType("string").Required(true).DefaultValue("")).
|
||||
Param(ws.QueryParameter("metrics_name", "metrics name cpu memory...").DataType("string").Required(true).DefaultValue("pod_memory_utilisation_wo_cache")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{"monitoring", "pod"}))
|
||||
|
||||
ws.Route(ws.GET("/nodes/{node_id}/pods").To(u.monitorPod).
|
||||
Doc("monitor pods level metrics by nodeid").
|
||||
Param(ws.PathParameter("node_id", "specific node").DataType("string").Required(true).DefaultValue("i-k89a62il")).
|
||||
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("pod_memory_utilisation_wo_cache")).
|
||||
Param(ws.QueryParameter("pods_filter", "pod re2 expression filter").DataType("string").Required(false).DefaultValue("openpitrix.*")).
|
||||
Param(ws.QueryParameter("sort_metric", "sort metric").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("sort_type", "ascending descending order").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("page", "page number").DataType("string").Required(false).DefaultValue("1")).
|
||||
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("4")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{"monitoring", "pod"}))
|
||||
|
||||
ws.Route(ws.GET("/nodes/{node_id}/pods/{pod_name}").To(u.monitorPod).
|
||||
Doc("monitor specific pod level metrics by nodeid").
|
||||
Param(ws.PathParameter("node_id", "specific node").DataType("string").Required(true).DefaultValue("i-k89a62il")).
|
||||
Param(ws.PathParameter("pod_name", "specific pod").DataType("string").Required(true).DefaultValue("")).
|
||||
Param(ws.QueryParameter("metrics_name", "metrics name cpu memory...").DataType("string").Required(true).DefaultValue("pod_memory_utilisation_wo_cache")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{"monitoring", "pod"}))
|
||||
|
||||
ws.Route(ws.GET("/nodes/{node_id}/pods/{pod_name}/containers").To(u.monitorContainer).
|
||||
Doc("monitor specific pod level metrics by nodeid").
|
||||
Param(ws.PathParameter("node_id", "specific node").DataType("string").Required(true)).
|
||||
Param(ws.PathParameter("pod_name", "specific pod").DataType("string").Required(true)).
|
||||
Param(ws.QueryParameter("containers_filter", "container re2 expression filter").DataType("string").Required(false).DefaultValue("")).
|
||||
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("metrics_name", "metrics name cpu memory...").DataType("string").Required(true).DefaultValue("pod_memory_utilisation_wo_cache")).
|
||||
Param(ws.QueryParameter("sort_metric", "sort metric").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("sort_type", "ascending descending order").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("page", "page number").DataType("string").Required(false).DefaultValue("1")).
|
||||
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("4")).
|
||||
Param(ws.QueryParameter("type", "rank, statistic").DataType("string").Required(false).DefaultValue("rank")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{"monitoring", "container"}))
|
||||
|
||||
ws.Route(ws.GET("/namespaces/{ns_name}/pods/{pod_name}/containers").To(u.monitorContainer).
|
||||
Doc("monitor containers level metrics").
|
||||
Param(ws.PathParameter("ns_name", "specific namespace").DataType("string").Required(true).DefaultValue("monitoring")).
|
||||
Param(ws.PathParameter("pod_name", "specific pod").DataType("string").Required(true).DefaultValue("")).
|
||||
Param(ws.QueryParameter("containers_filter", "container re2 expression filter").DataType("string").Required(false).DefaultValue("")).
|
||||
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("metrics_name", "metrics name cpu memory...").DataType("string").Required(true).DefaultValue("container_memory_utilisation_wo_cache")).
|
||||
Param(ws.QueryParameter("sort_metric", "sort metric").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("sort_type", "ascending descending order").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("page", "page number").DataType("string").Required(false).DefaultValue("1")).
|
||||
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("4")).
|
||||
Param(ws.QueryParameter("type", "rank, statistic").DataType("string").Required(false).DefaultValue("rank")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{"monitoring", "container"})).
|
||||
Consumes(restful.MIME_JSON, restful.MIME_XML).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
ws.Route(ws.GET("/namespaces/{ns_name}/pods/{pod_name}/containers/{container_name}").To(u.monitorContainer).
|
||||
Doc("monitor specific container level metrics").
|
||||
Param(ws.PathParameter("ns_name", "specific namespace").DataType("string").Required(true).DefaultValue("monitoring")).
|
||||
Param(ws.PathParameter("pod_name", "specific pod").DataType("string").Required(true).DefaultValue("")).
|
||||
Param(ws.PathParameter("container_name", "specific container").DataType("string").Required(true).DefaultValue("")).
|
||||
Param(ws.QueryParameter("metrics_name", "metrics name cpu memory...").DataType("string").Required(true).DefaultValue("container_memory_utilisation_wo_cache")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{"monitoring", "container"})).
|
||||
Consumes(restful.MIME_JSON, restful.MIME_XML).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
ws.Route(ws.GET("/namespaces/{ns_name}/workloads/{workload_kind}").To(u.monitorWorkload).
|
||||
Doc("monitor specific workload level metrics").
|
||||
Param(ws.PathParameter("ns_name", "namespace").DataType("string").Required(true).DefaultValue("kube-system")).
|
||||
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...").DataType("string").Required(false)).
|
||||
Param(ws.PathParameter("workload_kind", "workload kind").DataType("string").Required(false).DefaultValue("daemonset")).
|
||||
Param(ws.QueryParameter("workload_name", "workload name").DataType("string").Required(true).DefaultValue("")).
|
||||
Param(ws.QueryParameter("pods_filter", "pod re2 expression filter").DataType("string").Required(false).DefaultValue("openpitrix.*")).
|
||||
Param(ws.QueryParameter("sort_metric", "sort metric").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("sort_type", "ascending descending order").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("page", "page number").DataType("string").Required(false).DefaultValue("1")).
|
||||
Param(ws.QueryParameter("limit", "max metric items in a page").DataType("string").Required(false).DefaultValue("4")).
|
||||
Param(ws.QueryParameter("type", "rank, statistic").DataType("string").Required(false).DefaultValue("rank")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{"monitoring", "workload"}))
|
||||
|
||||
ws.Route(ws.GET("/namespaces/{ns_name}/workloads").To(u.monitorWorkload).
|
||||
Doc("monitor all workload level metrics").
|
||||
Param(ws.PathParameter("ns_name", "namespace").DataType("string").Required(true).DefaultValue("kube-system")).
|
||||
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("workloads_filter", "pod re2 expression filter").DataType("string").Required(false).DefaultValue("")).
|
||||
Param(ws.QueryParameter("sort_metric", "sort metric").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("sort_type", "ascending descending order").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("page", "page number").DataType("string").Required(false).DefaultValue("1")).
|
||||
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("4")).
|
||||
Param(ws.QueryParameter("type", "rank, statistic").DataType("string").Required(false).DefaultValue("rank")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{"monitoring", "workload"}))
|
||||
|
||||
// list all namespace in this workspace by selected metrics
|
||||
ws.Route(ws.GET("/workspaces/{workspace_name}").To(u.monitorOneWorkspace).
|
||||
Doc("monitor workspaces level metrics").
|
||||
Param(ws.PathParameter("workspace_name", "workspace name").DataType("string").Required(true)).
|
||||
Param(ws.QueryParameter("namespaces_filter", "namespaces filter").DataType("string").Required(false).DefaultValue("k.*")).
|
||||
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("namespace_memory_utilisation_wo_cache")).
|
||||
Param(ws.QueryParameter("sort_metric", "sort metric").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("sort_type", "ascending descending order").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("page", "page number").DataType("string").Required(false).DefaultValue("1")).
|
||||
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("4")).
|
||||
Param(ws.QueryParameter("type", "rank, statistic").DataType("string").Required(false).DefaultValue("rank")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{"monitoring", "workspace"}))
|
||||
|
||||
ws.Route(ws.GET("/workspaces").To(u.monitorAllWorkspaces).
|
||||
Doc("monitor workspaces level metrics").
|
||||
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("workspace_memory_utilisation")).
|
||||
Param(ws.QueryParameter("workspaces_filter", "workspaces re2 expression filter").DataType("string").Required(false).DefaultValue(".*")).
|
||||
Param(ws.QueryParameter("sort_metric", "sort metric").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("sort_type", "ascending descending order").DataType("string").Required(false)).
|
||||
Param(ws.QueryParameter("page", "page number").DataType("string").Required(false).DefaultValue("1")).
|
||||
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("4")).
|
||||
Param(ws.QueryParameter("type", "rank, statistic").DataType("string").Required(false).DefaultValue("rank")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{"monitoring", "workspace"}))
|
||||
|
||||
ws.Route(ws.GET("/components").To(u.monitorComponentStatus).
|
||||
Doc("monitor k8s components status").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{"monitoring", "components"}))
|
||||
|
||||
}
|
||||
|
||||
func (u Monitor) monitorPod(request *restful.Request, response *restful.Response) {
|
||||
requestParams := client.ParseMonitoringRequestParams(request)
|
||||
podName := requestParams.PodName
|
||||
metricName := requestParams.MetricsName
|
||||
if podName != "" {
|
||||
// single pod single metric
|
||||
queryType, params, nullRule := metrics.AssemblePodMetricRequestInfo(requestParams, metricName)
|
||||
var res *metrics.FormatedMetric
|
||||
if !nullRule {
|
||||
res = metrics.GetMetric(queryType, params, metricName)
|
||||
}
|
||||
response.WriteAsJson(res)
|
||||
|
||||
} else {
|
||||
// multiple
|
||||
rawMetrics := metrics.MonitorAllMetrics(requestParams, metrics.MetricLevelPod)
|
||||
// sorting
|
||||
sortedMetrics, maxMetricCount := metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics, metrics.MetricLevelPodName)
|
||||
// paging
|
||||
pagedMetrics := metrics.Page(requestParams.PageNum, requestParams.LimitNum, sortedMetrics, maxMetricCount)
|
||||
|
||||
response.WriteAsJson(pagedMetrics)
|
||||
}
|
||||
}
|
||||
|
||||
func (u Monitor) monitorContainer(request *restful.Request, response *restful.Response) {
|
||||
requestParams := client.ParseMonitoringRequestParams(request)
|
||||
metricName := requestParams.MetricsName
|
||||
if requestParams.MetricsFilter != "" {
|
||||
rawMetrics := metrics.MonitorAllMetrics(requestParams, metrics.MetricLevelContainer)
|
||||
// sorting
|
||||
sortedMetrics, maxMetricCount := metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics, metrics.MetricLevelContainerName)
|
||||
// paging
|
||||
pagedMetrics := metrics.Page(requestParams.PageNum, requestParams.LimitNum, sortedMetrics, maxMetricCount)
|
||||
|
||||
response.WriteAsJson(pagedMetrics)
|
||||
|
||||
} else {
|
||||
res := metrics.MonitorContainer(requestParams, metricName)
|
||||
response.WriteAsJson(res)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (u Monitor) monitorWorkload(request *restful.Request, response *restful.Response) {
|
||||
requestParams := client.ParseMonitoringRequestParams(request)
|
||||
|
||||
rawMetrics := metrics.MonitorAllMetrics(requestParams, metrics.MetricLevelWorkload)
|
||||
|
||||
var sortedMetrics *metrics.FormatedLevelMetric
|
||||
var maxMetricCount int
|
||||
|
||||
wlKind := requestParams.WorkloadKind
|
||||
|
||||
// sorting
|
||||
if wlKind == "" {
|
||||
|
||||
sortedMetrics, maxMetricCount = metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics, metrics.MetricLevelWorkload)
|
||||
} else {
|
||||
|
||||
sortedMetrics, maxMetricCount = metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics, metrics.MetricLevelPodName)
|
||||
}
|
||||
|
||||
// paging
|
||||
pagedMetrics := metrics.Page(requestParams.PageNum, requestParams.LimitNum, sortedMetrics, maxMetricCount)
|
||||
|
||||
response.WriteAsJson(pagedMetrics)
|
||||
|
||||
}
|
||||
|
||||
func (u Monitor) monitorAllWorkspaces(request *restful.Request, response *restful.Response) {
|
||||
|
||||
requestParams := client.ParseMonitoringRequestParams(request)
|
||||
|
||||
tp := requestParams.Tp
|
||||
if tp == "_statistics" {
|
||||
// merge multiple metric: all-devops, all-roles, all-projects...this api is designed for admin
|
||||
res := metrics.MonitorAllWorkspacesStatistics()
|
||||
|
||||
response.WriteAsJson(res)
|
||||
|
||||
} else if tp == "rank" {
|
||||
rawMetrics := metrics.MonitorAllWorkspaces(requestParams)
|
||||
// sorting
|
||||
sortedMetrics, maxMetricCount := metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics, metrics.MetricLevelWorkspace)
|
||||
// paging
|
||||
pagedMetrics := metrics.Page(requestParams.PageNum, requestParams.LimitNum, sortedMetrics, maxMetricCount)
|
||||
|
||||
response.WriteAsJson(pagedMetrics)
|
||||
} else {
|
||||
res := metrics.MonitorAllMetrics(requestParams, metrics.MetricLevelWorkspace)
|
||||
response.WriteAsJson(res)
|
||||
}
|
||||
}
|
||||
|
||||
func (u Monitor) monitorOneWorkspace(request *restful.Request, response *restful.Response) {
|
||||
requestParams := client.ParseMonitoringRequestParams(request)
|
||||
|
||||
tp := requestParams.Tp
|
||||
if tp == "rank" {
|
||||
// multiple
|
||||
rawMetrics := metrics.MonitorAllMetrics(requestParams, metrics.MetricLevelWorkspace)
|
||||
// sorting
|
||||
sortedMetrics, maxMetricCount := metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics, metrics.MetricLevelNamespace)
|
||||
// paging
|
||||
pagedMetrics := metrics.Page(requestParams.PageNum, requestParams.LimitNum, sortedMetrics, maxMetricCount)
|
||||
|
||||
response.WriteAsJson(pagedMetrics)
|
||||
|
||||
} else if tp == "_statistics" {
|
||||
wsName := requestParams.WsName
|
||||
|
||||
// merge multiple metric: devops, roles, projects...
|
||||
res := metrics.MonitorOneWorkspaceStatistics(wsName)
|
||||
response.WriteAsJson(res)
|
||||
} else {
|
||||
res := metrics.MonitorAllMetrics(requestParams, metrics.MetricLevelWorkspace)
|
||||
response.WriteAsJson(res)
|
||||
}
|
||||
}
|
||||
|
||||
func (u Monitor) monitorNamespace(request *restful.Request, response *restful.Response) {
|
||||
requestParams := client.ParseMonitoringRequestParams(request)
|
||||
metricName := requestParams.MetricsName
|
||||
nsName := requestParams.NsName
|
||||
if nsName != "" {
|
||||
// single
|
||||
queryType, params := metrics.AssembleNamespaceMetricRequestInfo(requestParams, metricName)
|
||||
res := metrics.GetMetric(queryType, params, metricName)
|
||||
response.WriteAsJson(res)
|
||||
} else {
|
||||
// multiple
|
||||
rawMetrics := metrics.MonitorAllMetrics(requestParams, metrics.MetricLevelNamespace)
|
||||
// sorting
|
||||
sortedMetrics, maxMetricCount := metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics, metrics.MetricLevelNamespace)
|
||||
// paging
|
||||
pagedMetrics := metrics.Page(requestParams.PageNum, requestParams.LimitNum, sortedMetrics, maxMetricCount)
|
||||
|
||||
response.WriteAsJson(pagedMetrics)
|
||||
}
|
||||
}
|
||||
|
||||
func (u Monitor) monitorCluster(request *restful.Request, response *restful.Response) {
|
||||
requestParams := client.ParseMonitoringRequestParams(request)
|
||||
|
||||
metricName := requestParams.MetricsName
|
||||
if metricName != "" {
|
||||
// single
|
||||
queryType, params := metrics.AssembleClusterMetricRequestInfo(requestParams, metricName)
|
||||
res := metrics.GetMetric(queryType, params, metricName)
|
||||
|
||||
response.WriteAsJson(res)
|
||||
} else {
|
||||
// multiple
|
||||
res := metrics.MonitorAllMetrics(requestParams, metrics.MetricLevelCluster)
|
||||
response.WriteAsJson(res)
|
||||
}
|
||||
}
|
||||
|
||||
func (u Monitor) monitorNode(request *restful.Request, response *restful.Response) {
|
||||
requestParams := client.ParseMonitoringRequestParams(request)
|
||||
|
||||
metricName := requestParams.MetricsName
|
||||
if metricName != "" {
|
||||
// single
|
||||
queryType, params := metrics.AssembleNodeMetricRequestInfo(requestParams, metricName)
|
||||
res := metrics.GetMetric(queryType, params, metricName)
|
||||
nodeAddress := metrics.GetNodeAddressInfo()
|
||||
metrics.AddNodeAddressMetric(res, nodeAddress)
|
||||
response.WriteAsJson(res)
|
||||
} else {
|
||||
// multiple
|
||||
rawMetrics := metrics.MonitorAllMetrics(requestParams, metrics.MetricLevelNode)
|
||||
nodeAddress := metrics.GetNodeAddressInfo()
|
||||
|
||||
for i := 0; i < len(rawMetrics.Results); i++ {
|
||||
metrics.AddNodeAddressMetric(&rawMetrics.Results[i], nodeAddress)
|
||||
}
|
||||
|
||||
// sorting
|
||||
sortedMetrics, maxMetricCount := metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics, metrics.MetricLevelNode)
|
||||
// paging
|
||||
pagedMetrics := metrics.Page(requestParams.PageNum, requestParams.LimitNum, sortedMetrics, maxMetricCount)
|
||||
|
||||
response.WriteAsJson(pagedMetrics)
|
||||
}
|
||||
}
|
||||
|
||||
// k8s component(controller, scheduler, etcd) status
|
||||
func (u Monitor) monitorComponentStatus(request *restful.Request, response *restful.Response) {
|
||||
requestParams := client.ParseMonitoringRequestParams(request)
|
||||
|
||||
status := metrics.MonitorComponentStatus(requestParams)
|
||||
response.WriteAsJson(status)
|
||||
}
|
||||
|
||||
type Monitor struct {
|
||||
}
|
||||
63
pkg/options/options.go
Normal file
63
pkg/options/options.go
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
|
||||
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 options
|
||||
|
||||
import (
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
var SharedOptions = NewServerRunOptions()
|
||||
|
||||
type ServerRunOptions struct {
|
||||
// server bind address
|
||||
BindAddress string
|
||||
|
||||
// insecure port number
|
||||
InsecurePort int
|
||||
|
||||
// secure port number
|
||||
SecurePort int
|
||||
|
||||
// tls cert file
|
||||
TlsCertFile string
|
||||
|
||||
// tls private key file
|
||||
TlsPrivateKey string
|
||||
|
||||
CommandLine *pflag.FlagSet
|
||||
}
|
||||
|
||||
func NewServerRunOptions() *ServerRunOptions {
|
||||
// create default server run options
|
||||
s := ServerRunOptions{
|
||||
BindAddress: "0.0.0.0",
|
||||
InsecurePort: 9090,
|
||||
SecurePort: 0,
|
||||
TlsCertFile: "",
|
||||
TlsPrivateKey: "",
|
||||
CommandLine: &pflag.FlagSet{},
|
||||
}
|
||||
|
||||
s.CommandLine.StringVar(&s.BindAddress, "bind-address", "0.0.0.0", "server bind address")
|
||||
s.CommandLine.IntVar(&s.InsecurePort, "insecure-port", 9090, "insecure port number")
|
||||
s.CommandLine.IntVar(&s.SecurePort, "secure-port", 0, "secure port number")
|
||||
s.CommandLine.StringVar(&s.TlsCertFile, "tls-cert-file", "", "tls cert file")
|
||||
s.CommandLine.StringVar(&s.TlsPrivateKey, "tls-private-key", "", "tls private key")
|
||||
|
||||
return &s
|
||||
}
|
||||
@@ -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 params
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strconv"
|
||||
|
||||
"golang.org/x/tools/container/intsets"
|
||||
)
|
||||
|
||||
const (
|
||||
Paging = "paging"
|
||||
OrderBy = "orderBy"
|
||||
Conditions = "conditions"
|
||||
Reserve = "reserve"
|
||||
)
|
||||
|
||||
func ParsePaging(paging string) (limit, offset int) {
|
||||
limit = intsets.MaxInt
|
||||
offset = 0
|
||||
if groups := regexp.MustCompile(`^limit=(\d+),page=(\d+)$`).FindStringSubmatch(paging); len(groups) == 3 {
|
||||
limit, _ = strconv.Atoi(groups[1])
|
||||
page, _ := strconv.Atoi(groups[2])
|
||||
if page < 0 {
|
||||
page = 1
|
||||
}
|
||||
offset = (page - 1) * limit
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func ParseReserve(reserve string) bool {
|
||||
b, err := strconv.ParseBool(reserve)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return b
|
||||
}
|
||||
89
pkg/params/params.go
Normal file
89
pkg/params/params.go
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
|
||||
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 params
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/emicklei/go-restful"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/tools/container/intsets"
|
||||
)
|
||||
|
||||
const (
|
||||
PagingParam = "paging"
|
||||
OrderByParam = "orderBy"
|
||||
ConditionsParam = "conditions"
|
||||
ReverseParam = "reverse"
|
||||
)
|
||||
|
||||
func ParsePaging(req *restful.Request) (limit, offset int) {
|
||||
paging := req.QueryParameter(PagingParam)
|
||||
limit = intsets.MaxInt
|
||||
offset = 0
|
||||
if groups := regexp.MustCompile(`^limit=(\d+),page=(\d+)$`).FindStringSubmatch(paging); len(groups) == 3 {
|
||||
limit, _ = strconv.Atoi(groups[1])
|
||||
page, _ := strconv.Atoi(groups[2])
|
||||
if page < 0 {
|
||||
page = 1
|
||||
}
|
||||
offset = (page - 1) * limit
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
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)}
|
||||
|
||||
if conditionsStr == "" {
|
||||
return conditions, nil
|
||||
}
|
||||
|
||||
for _, item := range strings.Split(conditionsStr, ",") {
|
||||
if strings.Count(item, "=") > 1 || strings.Count(item, "~") > 1 {
|
||||
return nil, fmt.Errorf("invalid conditions")
|
||||
}
|
||||
if groups := regexp.MustCompile(`(\S+)([=~])(\S+)`).FindStringSubmatch(item); len(groups) == 4 {
|
||||
if groups[2] == "=" {
|
||||
conditions.Match[groups[1]] = groups[3]
|
||||
} else {
|
||||
conditions.Fuzzy[groups[1]] = groups[3]
|
||||
}
|
||||
} else {
|
||||
return nil, fmt.Errorf("invalid conditions")
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
48
pkg/utils/iputils.go
Normal file
48
pkg/utils/iputils.go
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
|
||||
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 utils
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
const (
|
||||
XForwardedFor = "X-Forwarded-For"
|
||||
XRealIP = "X-Real-IP"
|
||||
XClientIP = "x-client-ip"
|
||||
)
|
||||
|
||||
func RemoteIp(req *http.Request) string {
|
||||
remoteAddr := req.RemoteAddr
|
||||
if ip := req.Header.Get(XClientIP); ip != "" {
|
||||
remoteAddr = ip
|
||||
} else if ip := req.Header.Get(XRealIP); ip != "" {
|
||||
remoteAddr = ip
|
||||
} else if ip = req.Header.Get(XForwardedFor); ip != "" {
|
||||
remoteAddr = ip
|
||||
} else {
|
||||
remoteAddr, _, _ = net.SplitHostPort(remoteAddr)
|
||||
}
|
||||
|
||||
if remoteAddr == "::1" {
|
||||
remoteAddr = "127.0.0.1"
|
||||
}
|
||||
|
||||
return remoteAddr
|
||||
}
|
||||
59
pkg/utils/jwt/jwt.go
Normal file
59
pkg/utils/jwt/jwt.go
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
|
||||
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 jwt
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
)
|
||||
|
||||
const secretEnv = "JWT_SECRET"
|
||||
|
||||
var Secret []byte
|
||||
|
||||
func init() {
|
||||
if env := os.Getenv(secretEnv); env != "" {
|
||||
Secret = []byte(env)
|
||||
} else {
|
||||
fmt.Printf("Environment variable %s not set\n", secretEnv)
|
||||
}
|
||||
}
|
||||
func provideKey(token *jwt.Token) (interface{}, error) {
|
||||
if _, ok := token.Method.(*jwt.SigningMethodHMAC); ok {
|
||||
return Secret, nil
|
||||
} else {
|
||||
return nil, fmt.Errorf("expect token signed with HMAC but got %v", token.Header["alg"])
|
||||
}
|
||||
}
|
||||
|
||||
func ValidateToken(uToken string) (*jwt.Token, error) {
|
||||
|
||||
if len(uToken) == 0 {
|
||||
return nil, fmt.Errorf("token length is zero")
|
||||
}
|
||||
|
||||
token, err := jwt.Parse(uToken, provideKey)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return token, nil
|
||||
}
|
||||
@@ -15,12 +15,23 @@
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
package v1alpha2
|
||||
package utils
|
||||
|
||||
import (
|
||||
"kubesphere.io/kubesphere/pkg/monitoring/v1alpha2/monitoring"
|
||||
)
|
||||
|
||||
func init() {
|
||||
addToWebServiceFuncs = append(addToWebServiceFuncs, monitoring.Route)
|
||||
func RemoveString(slice []string, remove func(item string) bool) []string {
|
||||
for i := 0; i < len(slice); i++ {
|
||||
if remove(slice[i]) {
|
||||
slice = append(slice[:i], slice[i+1:]...)
|
||||
i--
|
||||
}
|
||||
}
|
||||
return slice
|
||||
}
|
||||
|
||||
func HasString(slice []string, str string) bool {
|
||||
for _, s := range slice {
|
||||
if s == str {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -1,40 +1,19 @@
|
||||
/*
|
||||
Copyright 2018 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
|
||||
Copyright 2019 The KubeSphere Authors.
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
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.
|
||||
|
||||
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 version
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
)
|
||||
|
||||
var (
|
||||
versionFlag = pflag.Bool("version", false, "print the version of kubesphere")
|
||||
)
|
||||
|
||||
// PrintAndExitIfRequested will check if the -version flag was passed
|
||||
// and, if so, print the version and exit.
|
||||
|
||||
func PrintAndExitIfRequested() {
|
||||
if *versionFlag {
|
||||
fmt.Printf("Kubesphere %s\n", constants.APIVersion)
|
||||
os.Exit(0)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user